{
  "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 数据源"
    ]
  }
}
