{ "module": "session_router", "version": "2.0", "purpose": "Session Router — 多通道 session 路由 + 命令循环。为 XMPP/VC/微信等通道提供类 TUI 的 session 体验:auto 模式自动绑定最近活跃 session、NL 切换 session('切换到xxx')、LLM 驱动的 ##command## 系统。", "ui_location": "无直接 UI — 被 chat_bridge.py 和 xmpp_bot.py 使用", "human_help": { "title": "Session Router — 多通道 Session 路由", "description": [ "session_router.py 是一个消息路由器,让多个通信通道(XMPP/VC/微信)能像 TUI 一样使用 OpenCode session:自动绑定活跃 session、自然语言切换 session、支持 LLM 命令系统。", "命令系统:LLM 回复中的 ##command## 被拦截执行而非直接回复。支持 ##list_sessions##(列 session)、##switch_session:ID##(切换 session)、##select_session:1-5##(用户选择 session)等。", "选择模式:当用户用自然语言说'切换到xxx session'时,router 列出匹配的 session 让用户选择,选择超时 120s。", "消息循环(command loop):LLM 回复后检查是否包含 ##command## → 如果包含,执行命令 → 结果追加到上下文 → 重新调用 LLM → 直到无命令或达到 MAX_LOOPS=10。" ], "usage": [ "1. 创建: router = SessionRouter(bridge=SessionBridge(...), default_session='ses_xxm_xmpp')", "2. 路由消息: router.route(channel='xmpp', sender='hmo', message='你好') → AI 回复", "3. NL 切换: 用户在消息中说'切换到xxx session' → router 匹配并切换", "4. 命令: LLM 回复中包含 ##list_sessions## → router 拦截执行而非返回用户", "5. 选择超时: SELECTION_TIMEOUT = 120s — 超时后选择模式自动取消" ], "troubleshooting": [ "如果命令循环死循环: MAX_LOOPS=10 限制 — 超过后直接返回最后结果", "如果 session 切换失败: 检查 opencode.db 是否可读 — DB_PATH = ~/.local/share/opencode/opencode.db", "如果选择模式卡住: 120s 超时后自动取消" ] }, "ai_spec": { "apis": [ {"method": "N/A (内部路由)", "path": "router.route(channel, sender, message)", "returns": "AI 回复文本", "note": "主入口 — 处理消息 → 调用 LLM → 解析命令 → 循环直到无命令"}, {"method": "N/A (工具函数)", "path": "extract_session_context(session_id, limit=200)", "returns": "formatted context string", "note": "从 opencode.db 提取最近 N 条会话上下文"} ], "dependencies": [ "opencode.db (SQLite) — ~/.local/share/opencode/opencode.db", "chat_bridge.py — SessionBridge (LLM 调用)", "SQLite3 stdlib — 数据库读取", "threading — 选择模式超时管理" ], "architecture": { "flow": "消息 → ① 检查选择模式(pending user choice) → ② extract_session_context (200条) → ③ 构建 prompt → ④ SessionBridge.chat() → ⑤ 解析回复查找 ##command## → ⑥ 有命令 → 执行命令 → 结果追加 → 回到④ → 无命令 → 返回回复", "command_loop": "最多 10 次循环 — 每次 LLM 回复后检查 CMD_RE regex (##\\w+(?::[^#\\n]*)?##) → 拦截执行 → 追加结果 → 重新调用 LLM", "selection_mode": "用户请求切换 session → 列出匹配 session → 设置 selection_timer (120s) → 等待用户选择 → 超时自动取消", "context_extraction": "SQLite 查询 messages 表 → 按 role 格式化 ('用户:' / '小小莫:') → 最近 200 条" }, "constraints": [ "MAX_LOOPS = 10 — 防止命令循环无限执行", "SELECTION_TIMEOUT = 120s — 用户选择超时", "RECENT_MSG_LIMIT = 200 — 上下文上限", "SESSION_LIST_LIMIT = 15 — 列表显示最多 15 条", "DB_PATH 依赖于系统 opencode 安装路径 — ~/.local/share/opencode/opencode.db" ], "must_not": [ "不要在命令循环中无限 loop — MAX_LOOPS 是硬限制", "不要修改 opencode.db 的 messages 表结构 — 只读查询", "不要合并不同 channel 的消息 — 每条消息标记 source 标签" ], "related_modules": [ {"module": "chat_bridge", "relation": "session_router 包装 SessionBridge,增加命令路由层"}, {"module": "xmpp_bot", "relation": "xmpp_bot 使用 SessionRouter 进行消息路由和命令处理"} ], "tests": [ {"id": "SR01", "name": "extract_session_context 返回格式化上下文", "endpoint": "extract_session_context('ses_test') → '用户: xxx\\n小小莫: xxx'"}, {"id": "SR02", "name": "命令循环最多 10 次", "endpoint": "注入始终返回 ##dummy## 的 LLM → 10 次后停止"}, {"id": "SR03", "name": "选择模式 120s 超时", "endpoint": "设置选择模式 → 等 130s → 选择自动取消"} ], "known_issues": [ "命令循环依赖 LLM 回复格式 — 如果 LLM 返回非标准 ##command## 格式,会直接当作回复", "openCode.db schema 可能会随 opencode 升级变化 — 如果 messages 表结构变了,extract_session_context 需要更新" ], "related_files": [ "gateway/scripts/session_router.py — 本文件 (635行)", "gateway/scripts/chat_bridge.py — SessionBridge 实例", "~/.local/share/opencode/opencode.db — Session 数据源" ] } }