{
  "module": "ocg_router",
  "version": "1.0",
  "purpose": "OCG 路由代理。OpenAI 兼容代理(:19878)，背后池化 6 个 OpenCode Go API key，按剩余 quota 智能路由，402/429/5xx 自动故障切换。替代写死的 key3 配置，让所有 OMO 子 agent 自动使用最空闲的 key。",
  "ui_location": "I Tab (Infrastructure) → OCG 路由代理 section (API 用量下方)",

  "human_help": {
    "title": "OCG 路由代理",
    "description": [
      "把 6 个 OpenCode Go key 池化成一个 OpenAI 兼容的 API 端点(:19878)。",
      "每次请求自动选剩余 quota 最多的 key，用完后自动切下一个。",
      "402(余额不足)、429(限流)、5xx(服务器错误) 自动标记故障 key 并切换，5 分钟后恢复。",
      "取代原来写死 key3 的配置——key3 订阅已取消，不改的话所有子 agent 都会 Insufficient balance。",
      "Dashboard 可以看到当前路由到哪个 key、各 key 用量、命中次数。"
    ],
    "usage": [
      "1. 确保 systemd 服务 ocg-router 在运行 (systemctl status ocg-router)",
      "2. OMO 配置指向 http://192.168.1.246:19878/v1（已在 oh-my-openagent.jsonc 和 config.json 配置好）",
      "3. 本区块自动每 10 秒刷新，显示当前路由 key 和池状态",
      "4. 如果代理挂了，Dashboard 会显示「代理未运行」并给出错误信息",
      "5. 每个 key 卡片有「启用/停用」按钮 — 停用的 key 立即从路由池移除（不再参与路由，也不出现在 /api/status 池中），启用后立即恢复。状态写入 accounts.json 的 enabled 字段"
    ],
    "troubleshooting": [
      "代理未运行 → ssh 246 systemctl restart ocg-router",
      "所有 key 故障 → 检查 246 到 opencode.ai 网络是否通 (curl https://opencode.ai/zen/go/v1/models)",
      "某个 key 一直在冷却中 → 等 5 分钟冷却期过去，或重启代理清冷却 (systemctl restart ocg-router)",
      "当前路由 key 为空 → 代理刚启动还没收到请求，先发一个请求就会显示"
    ]
  },

  "ai_spec": {
    "apis": [
      {"method": "GET", "path": "http://192.168.1.246:19878/health", "returns": "{ok, time}", "proxied_to": "ocg_router.py status"},
      {"method": "GET", "path": "http://192.168.1.246:19878/v1/models", "returns": "OpenAI 兼容模型列表", "proxied_to": "ocg_router.py → opencode.ai"},
      {"method": "POST", "path": "http://192.168.1.246:19878/v1/chat/completions", "returns": "OpenAI 兼容响应 (含 stream)", "proxied_to": "ocg_router.py → opencode.ai"},
      {"method": "GET", "path": "http://192.168.1.246:19878/api/status", "returns": "代理状态 {current_key, pool, hits}", "proxied_to": "ocg_router.py internal"},
      {"method": "POST", "path": "http://192.168.1.246:19878/api/keys/toggle", "returns": "{ok, key_id, enabled, pool_size}", "proxied_to": "ocg_router.py — 写 accounts.json enabled 字段并立即 reload"},
      {"method": "POST", "path": "http://192.168.1.246:19878/api/reload", "returns": "{ok, keys}", "proxied_to": "ocg_router.py — 立即重载 accounts.json/usage_stats.json"},
      {"method": "GET", "path": "/api/proxy/status", "returns": "代理状态(通过 dashboard 代理)", "proxied_to": "dashboard.py → 19878"},
      {"method": "POST", "path": "/api/proxy/toggle-key", "returns": "{ok, key_id, enabled, pool_size}", "proxied_to": "dashboard.py → 19878 /api/keys/toggle"}
    ],
    "dependencies": [
      "ocg_router.py — 代理核心，systemd 常驻 (:19878)",
      "usage_stats.json — 每 2 分钟刷新，提供各 key 用量数据",
      "accounts.json — 提供 key 列表和 API key",
      "dashboard.py — /api/proxy/status 代理端点",
      "dashboard.html — OCG 路由代理 section (id=proxy-router-section)",
      "oh-my-openagent.jsonc — OMO 配置，所有 agent/category 指向 ocg-router",
      "~/.config/opencode/config.json — ocg-router provider 定义"
    ],
    "architecture": {
      "flow": "OMO(Windows) → ocg-router(:19878, 246) → 按 usage_stats.json 选最空闲 key → opencode.ai/zen/go/v1",
      "key_selection": "健康度 score = rolling%*0.6 + weekly%*0.3 + monthly%*0.1。score 最低的 key 被选中。订阅取消 score=999，故障冷却期内 score=888，用量采集失败(error) score=500（降权但可用）",
      "failover": "401/402/403/429/5xx → 标记 key 故障 5 分钟 → 自动重试下一个 key",
      "enable_disable": "accounts.json 每 key 支持 enabled 字段（默认 true）。enabled=false 的 key 不加入路由池：不出现在 /v1/models、/api/status、路由候选。Dashboard 卡片按钮或 POST /api/keys/toggle 可切换，立即生效",
      "providers": ["ocg-key1 (staymo7777@gmail.com)", "ocg-key2 (hua65111@gmail.com)", "ocg-key3 (staymo@163.com — 订阅已取消, 不可用)", "ocg-key4 (staywithmo@163.com)", "ocg-key5 (damnedmoon@163.com)", "ocg-key6 (ycdennismo@163.com)"],
      "port": "19878"
    },
    "constraints": [
      "代理必须跑在 246 上 — usage_stats.json 在 246 本地",
      "firewall: ufw allow 19878/tcp from 192.168.1.0/24",
      "pid lock: proc_guard('ocg_router') — 防止重复启动",
      "冷却期 300 秒 — key 被标记故障后 5 分钟自动恢复",
      "用量刷新间隔 120 秒",
      "User-Agent 必须用 Mozilla/5.0 — 否则 Cloudflare 1010 拦截"
    ],
    "must_not": [
      "不要把代理跑在 206 上 — 206 是阿里云，到 opencode.ai 的网络被 Cloudflare 按数据中心 IP 拦截",
      "不要绕过代理直接配 ocg-key3 — key3 订阅已取消，会 Insufficient balance",
      "不要改 baseURL 从 http 到 https — 内网走 HTTP 性能更好",
      "不要在 Windows 本机直接拉 usage_stats.json — 数据在 246 上，代理跑 246 避免网络依赖"
    ],
    "related_modules": [
      {"module": "usage_monitor", "relation": "提供 usage_stats.json 用量数据，代理依赖它做 key 选择"},
      {"module": "dashboard", "relation": "/api/proxy/status 端点代理到路由器；前端 OCG 路由代理 section 展示状态"}
    ],
    "tests": [
      {"id": "ROUTER01", "name": "GET /health returns ok", "endpoint": "GET http://192.168.1.246:19878/health"},
      {"id": "ROUTER02", "name": "GET /v1/models returns model list", "endpoint": "GET http://192.168.1.246:19878/v1/models"},
      {"id": "ROUTER03", "name": "POST /v1/chat/completions non-stream", "endpoint": "POST http://192.168.1.246:19878/v1/chat/completions"},
      {"id": "ROUTER04", "name": "GET /api/status returns pool health", "endpoint": "GET http://192.168.1.246:19878/api/status"},
      {"id": "ROUTER05", "name": "Dashboard /api/proxy/status proxies correctly", "endpoint": "GET http://192.168.1.246:5803/api/proxy/status"}
    ],
    "known_issues": [
      "Cloudflare 1010: opencode.ai API 需要真实 User-Agent（Mozilla/5.0），代理已内置",
      "阿里云到 opencode.ai: 数据中心 IP 可能被 Cloudflare WAF 拦截，所以代理必须跑在 246（家庭宽带 IP）",
      "key3 订阅已取消: accounts.json 已标 subscribed=false，不会出现在路由池",
      "用量采集失败(usage error): 只降权不排除 — key 仍可用，只是无法按用量排序（2026-08-03 修复，避免采集超时误杀所有 key）"
    ],
    "related_files": [
      "gateway/scripts/ocg_router.py — 代理核心",
      "gateway/scripts/dashboard.py — /api/proxy/status",
      "gateway/scripts/templates/dashboard.html — proxy-router-section",
      "gateway/scripts/specs/ocg_router.json — 本 spec 文件",
      "gateway/temp/usage_stats.json — 用量数据源",
      "gateway/scripts/usage_monitor/accounts.json — key 配置",
      "~/.config/opencode/oh-my-openagent.jsonc — OMO 配置",
      "/etc/systemd/system/ocg-router.service — systemd 服务定义"
    ]
  }
}
