Codex Retry Gateway

  • 文档层级:app 项目真源
  • 应用性质:自有 infra 工具
  • 源码来源:git submodule
  • 运行关系:多实例服务
  • 部署模型:managed_systemd_apps
  • 对应服务:services/pc/systemd-user/codex-retry-gateway/current/README.mdservices/a100/systemd-user/codex-retry-gateway/current/README.md
  • 对应 stack:无
  • Secret 边界:本地用户配置
  • 数据来源:本地 Codex provider 配置、gateway profile state 与上游 OpenAI-compatible API 响应。
  • 输出边界:仅返回代理后的 Codex API 响应和本地健康/状态信息。
  • 写入边界:只写本地用户态 gateway 状态目录。
  • 本地状态路径:~/.codex-retry-gateway/
  • 备注:token 与 provider secret 只保留在目标用户配置或 secret 文件中,不进入 repo。

一个不依赖 cc-switch 路由模式的独立本地网关。

目标:

  • 保持 Codex 继续使用现有 auth.json
  • 只把 config.toml 的当前 provider base_url 改成本地网关
  • 非流式命中 reasoning_tokens = 516 时返回 502
  • 上游若返回明确的容量错误(默认匹配错误文案 Selected model is at capacity. Please try a different model.stream disconnected before completion: Concurrency limit exceeded for account, please retry later,以及 Responses 错误码 server_is_overloaded / slow_down),也会自动重试;重试耗尽后转成本地 502
  • 除了 429/503 JSON 错误响应,也会识别 200 但返回体本质是错误、以及流式失败事件里携带同样文案的情况
  • 流式命中时默认先缓存并判断;一旦命中 516,统一返回 502
  • 流式成功响应在严格检查模式下仍会先缓存完成;成功后会按真实且规范化的 Responses 生命周期与输出顺序逐块回放给 Codex,每个 SSE 块之间至少间隔 5ms,并关闭 TCP 小包聚合,避免大量 delta 在同一事件循环突发到达;不会伪造缺少 response ID 的生命周期事件
  • 默认同时拦截 root 路径和 /v1 路径:
    • /responses
    • /chat/completions
    • /v1/responses
    • /v1/chat/completions

限制:

  • 这个网关不负责 ResponsesChat Completions 协议互转
  • 如果你的上游本身不支持 Codex 当前使用的协议,这个网关不会替你补齐转换能力

默认路径

Windows:

  • Codex 配置:%USERPROFILE%\.codex\config.toml
  • Gateway 状态目录:%USERPROFILE%\.codex-retry-gateway

macOS / Linux:

  • Codex 配置:~/.codex/config.toml
  • Gateway 状态目录:~/.codex-retry-gateway

当前版本说明

  • 这是一个可独立发布、独立运行的仓库
  • 默认监听地址是 http://127.0.0.1:4610
  • 默认示例上游见 config.example.json
  • 实际运行时配置会写到当前用户目录下的 gateway 状态目录

一键启动并打开管理页

在仓库根目录执行:

Windows:

powershell -ExecutionPolicy Bypass -File .\scripts\launch-ui.ps1

macOS / Linux:

bash ./scripts/launch-ui.sh

这个脚本是默认入口,执行后会自动完成:

  • 第一次运行时:
    • 备份当前用户目录下的 Codex config.toml
    • 生成当前用户目录下的 gateway config.json
    • 启动本地 gateway
    • 把当前 model_provider 对应的 base_url 改到本地 gateway
  • 之后再次运行时:
    • 自动复用现有安装状态
    • 自动重启或拉起 gateway
    • 自动再次打开管理页

默认会打开:

http://127.0.0.1:4610/__codex_retry_gateway/ui

如果你只想启动、不自动开浏览器:

powershell -ExecutionPolicy Bypass -File .\scripts\launch-ui.ps1 -NoOpen
bash ./scripts/launch-ui.sh --no-open

常用参数:

  • Windows 参数:
    • -CodexConfigPath
    • -StateRoot
    • -ListenHost
    • -ListenPort
    • -NoOpen
  • macOS / Linux 参数:
    • --codex-config-path
    • --state-root
    • --listen-host
    • --listen-port
    • --no-open

macOS / Linux 说明:

  • 需要 bash
  • 需要 Node.js 18+
  • Unix 入口会调用跨平台 node 管理核心,不依赖 PowerShell
  • 推荐显式使用 bash ...sh
  • 这样即使目录是从 Windows 或压缩包复制过来、没有可执行位,也能直接运行

手工安装入口

如果你明确只想做脚本级安装,不想自动打开 UI,也可以直接执行:

Windows:

powershell -ExecutionPolicy Bypass -File .\scripts\install-for-current-provider.ps1

macOS / Linux:

bash ./scripts/install-for-current-provider.sh

Linux systemd + profile 启动

在 Linux 上需要常驻运行时,推荐用 scripts/run-profile.mjs 作为 systemd 的 ExecStart。它会读取 profile env,生成运行时 config.json,并把当前 Codex provider 的 base_url 指向本机 gateway。

文本 profile env 默认放在:

~/.config/codex-retry-gateway/profiles/<profile>.env

图片 profile env 独立放在:

~/.config/codex-retry-gateway/image-profiles/<profile>.env

当前文本 profile 与当前图片 profile 分别由 state 中的 profile_nameimage_profile_name 记录;切换其中任意一方不会改写另一方。首次升级时,当前文本 profile 中已有的 CODEX_RETRY_GATEWAY_IMAGE_* 字段会复制到同名图片 profile,旧文本文件会保留作为兼容回退,但后续 UI/TUI 保存文本 profile 不再写入图片字段。

常用字段:

  • CODEX_RETRY_GATEWAY_LISTEN_HOST
  • CODEX_RETRY_GATEWAY_LISTEN_PORT
  • CODEX_RETRY_GATEWAY_UPSTREAM_BASE_URL
  • CODEX_RETRY_GATEWAY_REASONING_EQUALS
  • CODEX_RETRY_GATEWAY_RETRYABLE_STATUS_CODES
  • CODEX_RETRY_GATEWAY_RETRYABLE_ERROR_MESSAGES
  • CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_MODE
  • CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_ENV
  • CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_FILE
  • CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_JSON_PATH
  • CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_JSON_KEY
  • CODEX_RETRY_GATEWAY_REQUEST_HISTORY_LIMIT

CODEX_RETRY_GATEWAY_UPSTREAM_AUTH_MODE 支持:

  • passthrough:默认模式,透传 Codex 发来的 Authorization
  • manual_bearer:在 UI 中手动填入一次 token/password,写入用户级受限 secret 文件,并覆盖上游 Authorization: Bearer ...
  • fixed_bearer:从环境变量或文件读取 token,并覆盖上游 Authorization: Bearer ...
  • auth_json:从 Codex auth.json 的指定 key 读取 token,并覆盖上游 Authorization: Bearer ...

图片 profile 常用字段:

  • CODEX_RETRY_GATEWAY_IMAGE_BASE_URL

  • CODEX_RETRY_GATEWAY_IMAGE_AUTH_MODE

  • CODEX_RETRY_GATEWAY_IMAGE_AUTH_ENV

  • CODEX_RETRY_GATEWAY_IMAGE_AUTH_FILE

  • CODEX_RETRY_GATEWAY_IMAGE_AUTH_JSON_PATH

  • CODEX_RETRY_GATEWAY_IMAGE_AUTH_JSON_KEY

  • 配置 CODEX_RETRY_GATEWAY_IMAGE_BASE_URL 后,/images/*/v1/images/* 会改用该地址;root 图片路径会在上游规范化为 /v1/images/*,其他请求仍使用 CODEX_RETRY_GATEWAY_UPSTREAM_BASE_URL

  • 图片认证字段与普通上游同义,使用 CODEX_RETRY_GATEWAY_IMAGE_AUTH_*;默认 fixed_bearerCODEX_RETRY_GATEWAY_IMAGE_API_KEY 读取 key。

  • 不要把 key 直接写进 profile env;优先通过 IMAGE_AUTH_FILE 或管理页的 manual_bearer 写入用户级受限 secret 文件。

示例:

node ./scripts/run-profile.mjs default

指定图片 profile

node ./scripts/run-profile.mjs default --image-profile images

如果已经由 state 记录了当前活跃 profile,也可以直接不传 profile 参数:

node ./scripts/run-profile.mjs --prefer-state-profile

测试与发布

这个服务会改写目标用户的 Codex base_url,属于当前操作链路上的高风险本地网关。后续变更默认按“先对侧宿主、再当前宿主”发布。

pca100 的模型都显式设置了 systemd_unit_manage_state: false。因此下面的主干 playbook 只负责同步源码、安装 npm 依赖、构建 UI 和渲染 unit,不会自动 restart 或收敛 gateway 的运行状态;playbook 成功不代表新代码已经由当前进程加载。每台宿主完成同步和构建后,必须由操作者在目标服务用户的 user systemd 中显式重启 codex-retry-gateway.service,再开始验证。

推荐顺序:

  1. 先部署 a100 上的 codex-retry-gateway,然后以 zhouyunyao 用户显式重启 codex-retry-gateway.service
  2. 确认重启后的 unit 为 active,再检查 health 和管理 API,避免对仍在运行的旧进程做出错误判断。
  3. 在对侧机器的目标用户环境里发起真实 Codex 冒烟请求,不要先改当前正在依赖本机 4610 的会话。
  4. 确认健康检查、管理 API、响应完整性与关键重试行为正常。
  5. 通过后再以相同顺序部署 pc:同步和构建、以 shujakuin 用户显式重启、验证 unit 与 API、最后做真实 Codex 冒烟。

推荐部署命令:

uv run ansible-playbook playbooks/deploy_managed_systemd_apps.yml -i inventory/hosts.yml --limit a100 -e managed_systemd_apps_selected_names=codex-retry-gateway

同步和构建完成后,在 a100zhouyunyao 用户会话中执行:

systemctl --user restart codex-retry-gateway.service
systemctl --user is-active codex-retry-gateway.service

验证通过后,再切到本机:

uv run ansible-playbook playbooks/deploy_managed_systemd_apps.yml -i inventory/hosts.yml --limit pc -e managed_systemd_apps_selected_names=codex-retry-gateway

随后在 pcshujakuin 用户会话中执行同样的受控重启和状态检查:

systemctl --user restart codex-retry-gateway.service
systemctl --user is-active codex-retry-gateway.service

真实 Codex 网关冒烟固定显式使用 gpt-5.6-terra,不再使用 gpt-5.4

codex --dangerously-bypass-approvals-and-sandbox -c model="gpt-5.6-terra" hello

建议同时检查:

  • curl http://<listen-host>:4610/__codex_retry_gateway/health
  • /__codex_retry_gateway/api/profiles 等本次变更涉及的管理 API 能正常返回,且当前文本 / 图片 profile 没有被意外切换
  • /responses 成功流能完整结束,不会卡 pending;response.created 必须带真实 response ID,随后依次可见 response.in_progress、输出 delta 与 response.completed
  • 容量错误 Selected model is at capacity. Please try a different model. 仍能按网关策略自动重试

通过标准是重启后的 unit 保持 active、health 和相关管理 API 正常、真实 Codex 请求完整结束且关键重试行为未回归。任一检查失败都停止后续滚动,不要继续处理 pc;应先恢复上一版源码或修复问题,并重新从 a100 试点。

R2 --check --diff 不安装依赖、不构建 UI、也不重启 unit,只验证目标宿主当前已有源码、依赖、构建产物和运行前置是否满足模型声明。它不能替代上述发布后的运行验证,也不能证明新提交已经被目标进程加载。

如果当前对话依赖本机 4610,不要把本机作为首个发布目标;先在另一台已接管相同 profile 的机器验证,再回到本机切换,且 pc 必须是最后一个处理的宿主。

如何恢复

Windows:

powershell -ExecutionPolicy Bypass -File .\scripts\restore-codex-config.ps1

macOS / Linux:

bash ./scripts/restore-codex-config.sh

这个脚本会:

  • 停掉本地 gateway
  • 用最近一次备份恢复当前用户目录下的 Codex config.toml
  • 删除当前安装状态文件

管理页面

页面入口:

http://127.0.0.1:4610/__codex_retry_gateway/ui

UI 现在是独立的 Vite + React + TypeScript 前端:

  • 源码:ui-src/
  • 构建产物:public/ui/
  • 本地开发:npm run dev:ui
  • 生产构建:npm install && npm run build:ui

gateway 运行时只负责 API 与静态文件服务,不再把复杂 UI 硬写在 gateway.mjs 字符串里。

页面里可以直接做这几件事:

  • 看当前监听地址、真实上游、当前 provider、当前 Codex base URL
  • 看基于持久请求记录累计的实时统计
    • 代理请求总数
    • 被检查响应总数
    • 累计 input / output / total / reasoning tokens
    • 516 命中次数
    • 516 占比
  • 看最近请求记录
    • 请求时间戳、首字耗时、总耗时、请求体大小、路径、模型、状态码
    • 相同重发请求会带相同的 request_id
    • usage 中的 input / output / total / reasoning tokens
  • 分别管理文本 profiles 与图片 profiles
    • 各自新建 / 编辑 / 探测 / 切换 / 删除 profile env
    • 各自导出 / 导入可移植 profile JSON;导出前必须再次验证该 profile 当前实际使用的 API key
    • 文本切换 provider base_url 不会改写图片分流,图片切换只影响 /images/*/v1/images/*
    • 各自切换 passthrough / manual_bearer / fixed_bearer / auth_json 认证模式
  • reasoning_equals
  • 改 capacity error 的匹配状态码和错误文案
  • endpoints
  • non_stream_status_code
  • 开关 log_match
  • 动态查看当前 gateway 的实时日志
  • 一键恢复 Codex 原设置

说明:

  • 页面保存配置后会立即热生效,不需要重启 gateway
  • 页面点“恢复 Codex 原设置并关闭网关”后,当前页面会失联,这是预期行为
  • 日常恢复优先用 UIrestore-codex-config.ps1 作为脚本级应急回滚入口保留
  • UI 恢复不会再额外拉起恢复子进程,而是由当前 gateway 直接完成恢复并退出
  • 统计口径默认按持久请求记录累计,重启后会从 requests.sqlite / requests.jsonl 回灌
  • 516 占比 = reasoning_tokens = 516 的响应次数 / 被检查响应总数
  • 请求历史只记录元数据、请求体字节数和 token usage,不保存请求正文或响应正文;默认展示最近 200 条
  • gateway 日志持久化到 ~/.codex-retry-gateway/logs/gateway.log
  • 请求记录持久化到 ~/.codex-retry-gateway/logs/requests.jsonl~/.codex-retry-gateway/logs/requests.sqlite,重启后会用于 UI 请求页以及 overview 的累计 token / reasoning 统计
  • manual_bearer 的手动 token/password 只写入系统 secret 文件,普通 profile API/UI 不读回明文;只有再次验证当前 key 的显式导出接口会把它放进下载文件,profile env 仍只保存 secret 文件路径
  • 其他 profile env 不保存明文 sk-...;固定密钥请使用 env/file 引用,或用 auth_json 指向 auth.json 字段名

Profile 导入与导出

文本与图片 profile 都支持从 Profiles 页面导出和导入:

  • 文本接口:POST /__codex_retry_gateway/api/profiles/exportPOST /__codex_retry_gateway/api/profiles/import
  • 图片接口:POST /__codex_retry_gateway/api/image-profiles/exportPOST /__codex_retry_gateway/api/image-profiles/import
  • 导出前必须再次提交该 profile 当前实际使用的 API keygateway 会从现有 manual_bearer secret 文件、fixed_bearer env/file 或 auth_json 解析当前 key,并做常量时间比对
  • passthrough 没有 profile-owned key,无法完成再次验证,因此拒绝导出
  • 验证成功后才返回 codex-retry-gateway-profile v1 JSON;文件包含明文 API key,文本 profile 若配置了管理 Access key 也会一并保留
  • 导出响应使用 Cache-Control: no-store,服务端不生成或保留导出副本,日志只记录 profile 名称和认证来源,不记录 key
  • 导入只接受该格式的 JSON,并把包内 key 写入目标用户的默认 secret 文件,目录权限为 0700、文件权限为 0600profile env 仍只保存 secret 文件路径
  • 为避免当前控制链路被意外改写,导入不会自动切换 profile,也不允许直接覆盖当前活跃 profile;同名非活跃 profile 需要显式确认覆盖
  • 导入后的认证统一落为可移植的 manual_bearer;先用 profile 探针验证,再手动热切换

导出文件本身就是明文 secret 载体,不应提交到 Git、上传到普通日志或长期放在共享下载目录。

如何调整拦截条件

编辑:

Windows: %USERPROFILE%\.codex-retry-gateway\config\config.json
macOS / Linux: ~/.codex-retry-gateway/config/config.json

常用字段:

  • reasoning_equals
    • 例如 [516]
  • retryable_status_codes
    • 默认 [429, 503]
  • retryable_error_messages
    • 默认包含 Selected model is at capacity. Please try a different model.
    • 也默认包含 stream disconnected before completion: Concurrency limit exceeded for account, please retry later
    • 只要上游 JSON 错误里包含这些文案之一,gateway 就会把上游错误翻成本地 non_stream_status_code
  • endpoints
    • 默认包含 root 与 /v1 两套路径
  • non_stream_status_code
    • 默认 502
  • stream_action
    • 默认 strict_502
    • strict_502:先缓存整个流,命中 516 时统一返回 502
    • disconnect:兼容旧行为;若命中发生在已透传 chunk 之后,则直接断开连接
  • log_match
    • 是否记录命中日志

改完后重启:

powershell -ExecutionPolicy Bypass -File .\scripts\start-gateway.ps1 -RestartIfRunning
bash ./scripts/start-gateway.sh --restart-if-running

如果你已经打开管理页,优先直接在页面里改,通常不需要手改 config.json

其他机器如何应用

在其他 Windows 机器上:

  1. 复制整个仓库目录
  2. 确保本机有 Node.js 18+
  3. 不需要安装 cc-switch,也不需要使用 cc-switch 路由模式
  4. 在仓库根目录执行 powershell -ExecutionPolicy Bypass -File .\scripts\launch-ui.ps1
  5. 如需回滚,优先在 UI 里点“恢复 Codex 原设置并关闭网关”;脚本级回滚仍可执行 powershell -ExecutionPolicy Bypass -File .\scripts\restore-codex-config.ps1

在其他 macOS / Linux 机器上:

  1. 复制整个仓库目录
  2. 确保本机有 bash
  3. 确保本机有 Node.js 18+
  4. 不需要安装 cc-switch,也不需要使用 cc-switch 路由模式
  5. 在仓库根目录执行 bash ./scripts/launch-ui.sh
  6. 如需回滚,优先在 UI 里点“恢复 Codex 原设置并关闭网关”;脚本级回滚仍可执行 bash ./scripts/restore-codex-config.sh

运行时状态默认写到当前用户目录:

Windows: %USERPROFILE%\.codex-retry-gateway
macOS / Linux: ~/.codex-retry-gateway

已验证事项

  • test-gateway-e2e.ps1
    • 已通过
    • 验证 /responses/chat/completions/v1/responses/v1/chat/completions
  • node scripts/test-gateway-e2e.mjs
    • 已通过
    • 验证 strict capture 下 /responses 生命周期不注入空事件,长流 delta 按序完整回放并以 response.completed 结束
    • 验证文本 / 图片 profile 导出必须重新校验 key,错误 key 不泄露 secret;导入后 key 只进入 0600 secret 文件,不进入 profile env 或普通 API 响应
  • test-install-restore.ps1
    • 已通过
    • 验证安装、透传、UI 页面、热更新配置、实时日志、516 统计、恢复闭环
  • test-launch-ui.ps1
    • 已通过
    • 验证首次一键启动自动安装、再次启动自动复用、UI 可访问、默认 516 拦截仍生效
  • test-launch-ui-unix.ps1
    • 已通过
    • 在当前 Windows 主机的 Bash 环境里验证 Unix .sh 入口能完成启动、透传、恢复闭环
  • bash ./scripts/launch-ui.sh --no-open
    • 已通过
    • 当前机器实测返回 mode=reuse
    • 后续 GET /__codex_retry_gateway/healthGET /__codex_retry_gateway/uiGET /v1/models 都返回 200
  • codex exec
    • 已通过
    • 在 Bash 默认入口重新拉起 gateway 后,当前机器再次返回 OK
  • 当前实机验证示例
    • GET http://127.0.0.1:4610/__codex_retry_gateway/health 已通过
    • GET http://127.0.0.1:4610/v1/models 已通过,并成功透传到配置里的真实上游
    • GET http://127.0.0.1:4610/__codex_retry_gateway/ui 已实际打开并确认页面内容
  • codex exec 历史现象
    • gateway 关闭时,真实报错地址为 http://127.0.0.1:4610/responses
    • gateway 恢复后,codex exec 已再次成功返回 OK
S
Description
Codex retry gateway with profile switching and request telemetry
Readme 1.6 MiB
Languages
JavaScript 69.1%
TypeScript 23%
PowerShell 4%
CSS 3%
Shell 0.8%