跳转到内容

工作原理

Codex 使用 OpenAI Responses API。opencodex 接收通过 HTTP 与 Server-Sent Events 发送的 POST /v1/responses,也可选择在同一路径上启用 WebSocket 升级。它会把请求转换为 provider 的 wire 格式,再把响应转换回 Responses 事件,因此 Codex 无需知道自己正在与非 OpenAI 模型通信。

┌──────────────────────────── opencodex ────────────────────────────┐
│ │
Codex ──▶ │ parser ──▶ router ──▶ [vision] ──▶ adapter ──▶ provider │ ──▶ Codex
(/v1/ │ │ │ │ │ │ │ (SSE / WS)
responses)│ OcxParsed provider describe buildRequest parseStream │
│ Request +adapter images + fetch AdapterEvent[] │
│ │ │ │
│ [web-search loop] bridge ─▶ SSE │
└─────────────────────────────────────────────────────────────────────┘

Codex 多账号路由:已有线程保持账号绑定,新会话可以查询额度并选择使用量更低的健康账号。

当选择的 provider 使用 ChatGPT/Codex 直通时,opencodex 可以在转发请求前从已保存的账号池中选择账号。

  • 已有线程保持绑定。 线程绑定到开始时所选的账号代次,长时间运行的 SSH、tmux 或移动端 Codex 会话不会在正常对话过程中重新分配账号。
  • 新会话可以重新分配。 新线程按 accountPoolStrategy 选择可用账号,默认为 quota,也支持 round-robinfill-firstquota 比较已知的 5 小时、每周和 30 天额度使用量,并在当前账号 超过 autoSwitchThreshold 时选择使用量更低的账号。冷却中或需要重新认证的账号会被跳过。
  • 额度和失败信号参与路由。 仪表盘通过 GET /api/codex-auth/accounts?refresh=1 强制刷新额度。 成功的上游响应会更新额度头信息;429 使账号进入冷却,401/403 会将账号标记为需要重新认证。
  • 空闲额度窗口可以自动激活。 高级设置中的自动激活默认关闭,统一控制当前主账号和附加账号 已报告的 5 小时及每周窗口;新添加账号不会自动启用。在 Pool 模式下,窗口到期后会通过对应账号 发送最小化、不保存的请求,并消耗少量额度;同时到期的窗口合并为一次请求。暂停、需要重新认证 的账号会被跳过,主账号硬锁限制也会得到遵守。成功响应的额度头会更新缓存;已启用且符合条件的 空闲账号还会每隔至少 5 分钟刷新过期的额度元数据,无需保持仪表盘打开。已观察到的到期时间会保留 至激活完成,重启或后续查询的时间变化不会丢失待处理窗口。元数据查询复用现有的有次数限制的认证 恢复逻辑;推理请求返回 401 时,被拒绝的凭据会标记为需要重新认证。失败日志仅记录不透明账号标签 和安全的状态原因。该功能独立于为传入请求选择账号的路由逻辑。

降级说明: 运行旧版本前,请仅移除自动激活设置中的 nextFiveHourResetAtnextWeeklyResetAt。旧版严格校验不接受这两个新字段,可能因此禁用整个自动激活设置块。

全新安装会通过 subagentModels 在 Codex 的 sub-agent 选择器中优先显示 gpt-6-astra、GPT-5.6 Sol/Terra/Luna 三个模型和 gpt-5.5。仪表盘可以从原生或已路由模型中重新排序或替换最多 五个条目。对于 v1 协作请求,可选的 injectionModelinjectionEffort 会添加开发者指令, 告诉 spawn_agent 应使用哪个模型和 reasoning effort;v2 请求保留 Codex 原生的多智能体指引。

  1. 解析 —— responses/parser.ts 使用 Zod schema(responses/schema.ts)校验请求, 并将其降级为内部的 OcxParsedRequest:系统提示词、一份规范化的消息列表 (文本、图像、工具调用、工具结果)、工具定义、生成选项,以及诸如 _webSearch(请求了托管的网络搜索) 和 _structuredOutput(设置了 JSON schema / JSON 对象的 text.format)等特性标志。图像会被保留为真正的内容部分 —— 绝不会被内联为 base64 文本。

  2. 路由 —— router.ts 按固定的优先级将请求的模型 id 映射到一个已配置的 provider: 显式的 provider/model → provider 的 defaultModel → 内置前缀模式 (claude-gpt-o1-/o3-/o4-llama-/mixtral-/gemma-) → provider 的 models[]defaultProvider 回退。参见 模型路由

  3. 认证 —— 对于 oauth 类型的 provider,opencodex 会换入一个全新、自动刷新的 access token 作为 bearer key,从而让现有的 adapter 无需改动即可完成认证。

  4. Vision sidecar(可选) —— 如果已路由的模型被列在 provider.noVisionModels 中,且 请求携带了图像,opencodex 会通过你的 ChatGPT 登录凭据,使用已配置的 vision sidecar 描述 每张图像并将其替换为文本,让纯文本模型仍可对图像进行推理。 参见 Sidecar

  5. 直通快速路径 —— 对于 Responses 直通 adapter(openai-responsesazure-openai), opencodex 会保留 Responses body,只执行必要的路由与兼容性改写,然后直接转发 provider 响应, 不再转换为 AdapterEvent

  6. 网络搜索 sidecar(可选) —— 如果 Codex 启用了托管的 web_search,但已路由的模型 并非 OpenAI,opencodex 会暴露一个合成的 web_search 函数工具,并在一个小型 agentic 循环中运行该模型,默认通过你的 ChatGPT 登录凭据调用 gpt-5.6-luna 执行真实搜索, 再将结果作为工具结果注入回去。

  7. 压缩(按需) —— Codex v1 会调用 POST /v1/responses/compact,v2 则在 Responses turn 中 加入 compaction_trigger。原生直通路由会把压缩请求发送到上游;已路由模型则在禁用工具的 情况下执行摘要,并返回 Codex 所需的替代历史记录格式。

  8. 适配 —— 否则,所选 adapter 的 buildRequest() 会以 provider 的原生格式生成上游 HTTP 请求 (URL、headers、body),由 opencodex 对其执行 fetch

  9. 桥接 —— adapter 的 parseStream()(或 parseResponse())会产出内部的 AdapterEvent (text、reasoning、tool-call start/delta/end、done、error)。bridge.ts 会将该流转换回 Responses SSE 事件 —— response.output_text.deltaresponse.reasoning_summary_text.deltaresponse.function_call_arguments.deltaresponse.completed 等等。启用 WebSocket 时,同样的 event payload 会作为 text frame 发送。

为什么是代理而不是 fork 一份 Codex?

Section titled “为什么是代理而不是 fork 一份 Codex?”

Codex 把 Responses API 硬编码在内部。通过在协议边界处进行翻译,opencodex 可以与 Codex 的 CLI、App 和 SDK 无改动地协作,能在 Codex 更新后继续工作,并让你能够按请求切换 provider 而无需改动 Codex 本身。这种翻译是双向且忠于 streaming 的: 推理摘要、MCP 工具命名空间、freeform(apply_patch)工具,以及 tool_search 发现 都能正确地往返。关于逐事件的映射,参见 架构参考