{
  "module": "chat_bridge",
  "version": "2.0",
  "purpose": "Chat Bridge — 直接 HTTP API 调用 OpenCode serve session，带模型 fallback + session 持久化。消息双写到 bridge_context.jsonl（即时上下文注入）和 opencode.db（session_search 可回溯）。上下文窗口上限 200 条，超出用 session_search。支持 TUI 活跃 session 追踪。",
  "ui_location": "无直接 UI — 被 xmpp_bot.py 调用",

  "human_help": {
    "title": "Chat Bridge — Session 桥接",
    "description": [
      "chat_bridge.py 是 XMPP 消息和 OpenCode serve session 之间的桥梁。它把群聊/私聊消息发送到 OpenCode API，获取 AI 回复，支持多模型 fallback。",
      "消息双写：① bridge_context.jsonl — 立即注入到下次 API 调用的上下文 ② opencode.db — 持久化存储，session_search 可回溯。",
      "TUI 追踪：当 xxm 在 TUI 中与用户对话，mark_active_tui_session() 记录活跃 session ID。bot 处理群消息时会注入 TUI 上下文，让 LLM 知道用户在 TUI 讨论了什么。",
      "模型 fallback：主模型（deepseek-v4-pro）→ 超时/失败 → fallback 模型。失败不丢消息，降级处理。"
    ],
    "usage": [
      "1. 创建实例: bridge = SessionBridge(session_id='ses_xxm_xmpp')",
      "2. 发送消息: bridge.chat(message, source='xmpp', sender='hmo') → AI 回复文本",
      "3. TUI 追踪: mark_active_tui_session('ses_xxx') → bot 自动注入 TUI 上下文",
      "4. 上下文注入: bridge 自动读取最近 200 条 session 消息 + TUI 活跃 session 内容",
      "5. 日志: gateway/logs/bridge.log"
    ],
    "troubleshooting": [
      "如果 API 调用超时: 检查 OpenCode serve 是否在线 (localhost:4096)，模型 API 是否可用",
      "如果回复乱码: 检查上下文注入是否过长（上限200条），model fallback 是否降级到较差模型",
      "如果 TUI 上下文不生效: 检查 _.active_tui_session.json 是否存在且未过期（1小时）"
    ]
  },

  "ai_spec": {
    "apis": [
      {"method": "POST", "path": "OpenCode API /v1/chat/completions", "returns": "AI 回复文本", "note": "直接 HTTP 调用 OpenCode serve — 非 OpenAI 兼容格式"},
      {"method": "POST", "path": "OpenCode API fallback model", "returns": "AI 回复文本", "note": "主模型超时/失败后降级到备用模型"}
    ],
    "dependencies": [
      "OpenCode serve session (localhost:4096) — API 后端",
      "opencode.db (SQLite) — session 持久化存储（~/.local/share/opencode/opencode.db）",
      "session_router.py — extract_session_context() + 命令协议",
      "requests — HTTP 库（已经设了 no_proxy='*'）",
      "Model API — deepseek-v4-pro (主) + fallback model"
    ],
    "architecture": {
      "flow": "XMPP消息 → SessionBridge.chat() → ① 读取最近200条 context (SQLite) → ② 注入 TUI 活跃 session 内容 → ③ 构建 prompt → ④ POST OpenCode API → ⑤ 解析回复 → ⑥ 双写 (bridge_context.jsonl + opencode.db) → 返回文本",
      "dual_write": "每条消息同时写入 bridge_context.jsonl 和 opencode.db — 前者即时上下文，后者持久可回溯",
      "tui_tracking": "mark_active_tui_session() 写 JSON 文件 → get_active_tui_session() 读取 → 1h 自动过期",
      "fallback": "主模型超时/失败 → 切换到 fallback 模型 — 不丢消息"
    },
    "constraints": [
      "上下文窗口硬上限 200 条 — 防止 prompt 过长",
      "TUI session 1h 自动过期 — 匹配 Hermes state_meta 模式",
      "no_proxy='*' — 确保本地 API 调用不走代理",
      "双写操作需要文件系统写入权限 — temp/ 和 opencode.db"
    ],
    "must_not": [
      "不要在 API 调用失败时返回空 — 至少返回错误描述",
      "不要超过 200 条上下文 — 可能导致 prompt 截断",
      "不要修改 opencode.db 的表结构 — 只读/只插入，不 DDL"
    ],
    "related_modules": [
      {"module": "xmpp_bot", "relation": "xmpp_bot 通过 SessionBridge 发送消息到 OpenCode API — chat_bridge 是 xmpp_bot 的 LLM 调用层"},
      {"module": "session_router", "relation": "session_router 包装 SessionBridge，增加命令路由 + 多 channel 支持"}
    ],
    "tests": [
      {"id": "CB01", "name": "chat() 返回非空字符串", "endpoint": "bridge.chat('hello') → str"},
      {"id": "CB02", "name": "TUI session 1h 过期", "endpoint": "设 timestamp 2h 前 → get_active_tui_session() 返回 None"},
      {"id": "CB03", "name": "消息双写成功", "endpoint": "chat() 后检查 bridge_context.jsonl 和 opencode.db 都有新记录"}
    ],
    "known_issues": [
      "API 调用是同步阻塞的 — 不适用于高并发场景（但 XMPP 消息量小，问题不大）",
      "双写数据可能不一致 — 如果仅一个写入成功（极少发生）"
    ],
    "related_files": [
      "gateway/scripts/chat_bridge.py — 本文件 (754行)",
      "gateway/scripts/session_router.py — extract_session_context()",
      "gateway/temp/bridge_context.jsonl — 即时上下文文件",
      "~/.local/share/opencode/opencode.db — Session 持久化 DB",
      "gateway/temp/.active_tui_session.json — TUI session 追踪文件",
      "gateway/logs/bridge.log — 桥接日志"
    ]
  }
}
