Skip to content
kyrin-labsPublic

About

Discord bot + LLM agent loop with a tool harness.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Iris

Discord bot + LLM (OpenAI-compatible) + Harness — บอทที่คุยกับผู้ใช้ผ่าน LLM พร้อมชุดเครื่องมือ (tools/harness) ให้ทำอะไรได้จริงใน Discord

เอกสารสำคัญ: SPEC · Phases · Tools · Decisions

ฟีเจอร์

  • คุยกับ LLM แบบ OpenAI-compatible (สลับ provider ได้ผ่าน env)
  • Agent loop (tool-calling): iris ตอบผ่านวง agent ที่เรียกใช้เครื่องมือได้จริง (มี AGENT_MAX_TOOL_CALLS / AGENT_TOOL_TIMEOUT_SECONDS คุมการทำงาน)
  • บุคลิกจาก persona.md + ความจำระยะยาว memory/ (มี memory.md เป็นดัชนี)
  • บันทึก session + flag-memory (สรุปสาระสำคัญ) แบบ 1:1 — thread ใหม่ = session ใหม่; หลายคนใน thread เดียวกัน แชร์ session เดียวกัน แต่ทุกบรรทัดแนบ user_id → iris เห็นทั้ง thread พร้อมรู้ว่าใครพูด
  • กันคำลงท้ายผู้ชาย "ครับ" หลุดด้วยตัวกรองอัตโนมัติ (persona เป็นหญิง ใช้ คะ/ค่ะ)
  • Harness: time, search (SearXNG), mention_user, store memory, schedule task, music, request_tool (ขอเพิ่มเครื่องมือผ่าน GitHub issue) — ส่วน steam_price ยัง deferred

สถานะ: อยู่ระหว่างพัฒนาตาม docs/PHASES.md

ความต้องการ

  • Python 3.11
  • uv
  • Docker (สำหรับรัน SearXNG แบบ local — ดูหัวข้อ SearXNG)
  • (Phase 9) ffmpeg สำหรับฟีเจอร์ music

Setup

git clone <repo-url> iris
cd iris
uv sync                # ติดตั้ง dependencies (รวม dev)
cp .env.example .env   # แล้วแก้ค่าให้ครบ

ตัวแปร env หลัก

ตัวแปร คำอธิบาย
DISCORD_BOT_TOKEN token ของ Discord bot
LLM_BASE_URL / LLM_API_KEY / LLM_MODEL LLM แบบ OpenAI-compatible
SEARXNG_URL URL ของ SearXNG instance (รัน local ผ่าน make searxng-up)
GITHUB_TOKEN / GITHUB_REPO ใช้โดย request_tool (Phase 10)

ดูตัวแปรทั้งหมดใน .env.example

SearXNG (ค้นเว็บ) — รัน local

tool search ของ iris ค้นเว็บผ่าน SearXNG — รัน SearXNG ผ่าน docker compose ที่แยกไว้เฉพาะ (docker/searxng/) iris เองยังไม่ได้ containerized (compose ของ iris จะมาทีหลังใน Phase 12):

make searxng-up        # รัน SearXNG (ครั้งแรกจะ pull image) + รอจนพร้อม
make searxng-logs      # ดู log แบบ realtime (Ctrl+C เพื่อออก)
make searxng-status    # สถานะ container
make searxng-restart   # รีสตาร์ท
make searxng-down      # หยุด SearXNG

ตั้ง SEARXNG_URL=http://127.0.0.1:8080 ใน .env (default ใน .env.example มีให้แล้ว) → uv run iris ก็เชื่อมได้เลย

เช็คด้วยตัวเอง:

curl "http://127.0.0.1:8080/search?q=hello&format=json"

รัน

uv run iris

ต้องตั้งค่าใน .env ก่อน: DISCORD_BOT_TOKEN (token ของ bot) + LLM_BASE_URL / LLM_API_KEY / LLM_MODEL

วิธีคุย: @iris หรือพิมพ์ prefix (iris, ...) ใน channel → iris จะสร้าง thread เป็นพื้นที่สนทนาและตอบในนั้น ภายใน thread คุยต่อได้เลยโดยไม่ต้อง mention ซ้ำ (channel ที่สร้าง thread ไม่ได้ เช่น DM → ตอบตรงๆ) ทุกข้อความที่ iris ตอบแล้วจะถูก add reaction ✅ กำกับ (เครื่องหมาย "ตอบแล้ว")

token/secret ที่ยังไม่ได้ตั้งจะ fail พร้อม error ที่ชัดเจนตอนรัน (ไม่ fail ตอน import)

Privileged intents: iris ใช้ Message Content และ Server Members intent — ต้องเปิดทั้ง 2 ตัวใน Discord Developer Portal (Applications → bot ของคุณ → Bot → Privileged Gateway Intents) ก่อนรัน ถ้าไม่เปิด Server Members Intent บอทจะหาเพื่อนสมาชิกเจอเฉพาะตัวมันเอง → tool mention_user จะบอก "ไม่พบผู้ใช้" (tool มี fallback เรียก API fetch_member อยู่แล้ว แต่เปิด intent ให้ก็จะ resolve จาก cache ได้ทันที ไม่เสียรอบ API)

LLM smoke test (Phase 1)

คุยกับ LLM ที่ตั้งค่าไว้ใน .env โดยตรง ไม่ต้องเปิดบอท (ยังไม่มี tool-calling loop):

uv run python -m iris.llm.chat "สวัสดี"
echo "ตอนนี้กี่โมง" | uv run python -m iris.llm.chat

ถ้าโมเดลขอใช้ tool จะแสดงเป็น [tool_call] <name>(<arguments>) (ยังไม่ execute — เป็นฝั่งล่างนี้ที่ execute จริง)

Agent smoke test (Phase 3)

รันวง agent loop (tool-calling) เต็มรูปแบบโดยไม่ต้องเปิด Discord — โมเดลจะเรียกใช้ tool ได้จริง:

uv run python -m iris.agent "ตอนนี้กี่โมง"   # ควรเห็น iris เรียก tool `time` แล้วตอบเวลาจริง

Persona & Memory smoke test (Phase 4)

  • แก้ persona.md แล้ว save → บุคลิกเปลี่ยนทันทีใน turn ถัดไป (โหลดจาก disk ใหม่ทุกครั้ง ไม่มี cache)
  • เพิ่ม/แก้ไฟล์ใน memory/ แล้วรัน regenerate index → ไฟล์ขึ้นใน memory.md และถูก inject เข้า system prompt อัตโนมัติ:
uv run python -m iris.memory.index     # regenerate memory.md จาก listing memory/

Session & flag-memory smoke test (Phase 5)

คุยใน Discord 2 รอบใน thread เดียว → iris จำบริบทรอบแรกได้ (history โหลดจาก transcript); thread ใหม่ → ได้ session ใหม่แยกไฟล์; หลายคนใน thread เดียวกัน → แชร์ session เดียวกัน แต่แต่ละบรรทัดมี user_id กำกับ

ls data/sessions/       # transcript JSONL ต่อ session (ชื่อไฟล์ = {guild_id}:{thread_id}; แต่ละบรรทัดผู้ใช้มี user_id)
ls data/flag-memory/    # สรุปสาระสำคัญ 1:1 กับ session (LLM ตัวย่อย condense ทุกจบ turn)

Store-memory smoke test (Phase 7)

สั่งใน Discord เช่น "จำไว้ว่าฉันชื่อไก่" / "ลืมเรื่อง X" → iris เรียก memory_write / memory_delete สร้าง/ลบไฟล์ใน memory/ และ regenerate memory.md ให้อัตโนมัติ (ADR-007 บังคับในโค้ด — ไม่ต้องสั่ง index เอง)

ls memory/                        # ไฟล์ที่ iris จำไว้ (เช่น users/kiki.md)
cat memory.md                     # ดัชนีที่ถูก regenerate ให้อัตโนมัติ
uv run python -m iris.memory.index  # regenerate ด้วยมือ (กรณีคนสร้างไฟล์เอง)

restart บอท แล้วถามเรื่องที่จำ → iris ยังตอบได้ (โหลดไฟล์จาก disk ทุก turn); ลองใช้ชื่อไฟล์ ../escape.md หรือ .txt → ถูกบล็อกเป็น success=False ไม่มีการเขียนเกิดขึ้น (path traversal guard)

Test / Lint / Type check

uv run pytest
uv run ruff check .
uv run mypy src

โครงสร้าง

src/iris/        # โค้ดหลัก (ดู docs/SPEC.md)
  agent.py       # วง agent loop (tool-calling) — system prompt = persona + memory (Phase 4)
  harness/       # framework ของ tools: base.py (ToolSpec/ToolResult/...) + registry.py
  builtin/       # tools ที่ติดมากับ iris (time, ...)
  bot.py         # Discord bot + trigger + thread
  llm/           # LLM gateway (OpenAI-compatible)
  memory/        # MemoryStore (store.py) + regenerate memory.md (index.py) — Phase 4
  session/       # SessionStore (store.py) + FlagMemory (flag.py) — Phase 5
docs/            # สเปค + แผนพัฒนา
persona.md       # บุคลิก (Phase 4)
memory.md        # ดัชนีความจำ (Phase 4)
memory/          # ความจำระยะยาว (Phase 4)
data/            # runtime data (sessions / flag-memory / schedules) — ไม่ commit

หมายเหตุ

  • token/secret fields มี default ว่างไว้เพื่อให้ import iris และ test รันได้โดยไม่ต้องมี .env — จะ fail ตอนรันจริงถ้าไม่ได้ตั้งค่า
  • ดู docs/DECISIONS.md สำหรับการตัดสินใจออกแบบ

About

Discord bot + LLM agent loop with a tool harness.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages