Skip to content

Repository files navigation

CodexApiGateway

让 Codex CLI 接上多种上游后端的本地网关。

logo

Codex CLI 只能走 OpenAI Responses API。本网关在本地提供 Responses 兼容端点(/v1/responses/v1/models),按源配置把请求转到不同上游,再以 Responses SSE 回给 Codex。Codex 全程无感。

支持三类上游(可混排故障转移):

backend_type 上游 路径
a(默认) Anthropic Messages Responses → Messages → Responses SSE
c OpenAI Chat Completions Responses → Chat → Responses SSE
r OpenAI Responses 透传 最小改写透传 + 出站 model 别名回写
Codex CLI
   │  POST /v1/responses  (OpenAI Responses 格式)
   ▼
codex-api-gateway  ── 协议适配 / 透传 + 多源路由 + 熔断
   ├─ a → Anthropic Messages (/v1/messages, SSE)
   ├─ c → OpenAI Chat Completions (/chat/completions, SSE)
   └─ r → OpenAI Responses 透传 (/responses, SSE)

OpenAI Chat 兼容上游(backend_type: c)

除默认 Anthropic(a)外,源可配置为 OpenAI Chat Completions 兼容后端(c)。Responses 透传见下一节 r

sources:
  - name: openai-compat
    base_url: https://api.openai.com/v1   # 填 OpenAI SDK 的 base_url,不要带 /chat/completions
    api_key: ${OPENAI_API_KEY}
    backend_type: c
    model_map: { gpt-5: gpt-4o }
    default_model: gpt-4o

base_url 示例:OpenAI …/v1、DeepSeek https://api.deepseek.com、智谱 https://open.bigmodel.cn/api/paas/v4、火山 https://ark.cn-beijing.volces.com/api/v3、百炼 https://dashscope.aliyuncs.com/compatible-mode/v1。客户端仍只访问网关的 /v1/responses

OpenAI Responses 透传上游(backend_type: r)

当上游本身提供 OpenAI Responses API 时,配置 backend_type: r:网关映射 model、强制 stream, 并将上游 SSE 转回客户端(出站 response.model 回写为客户端模型别名)。可与 a/c 混排故障转移。

sources:
  - name: openai-responses
    base_url: https://api.openai.com/v1
    api_key: ${OPENAI_API_KEY}
    backend_type: r
    model_map: { gpt-5: gpt-5 }
    default_model: gpt-5

功能

  • 多后端协议适配a Anthropic Messages 直转、c Chat Completions 转换、r Responses 透传;客户端始终只走 /v1/responses SSE。
  • 多源路由:多源按配置顺序优先级,运行时重建;a/c/r 可混排。
  • 手动停用源:管理页一键停用/启用单源,即时写盘并热重载;停用源不参与调度,仍保留在配置与观测中。
  • 首字节前故障转移:上游未开始流式输出前可切换到下一个源;出流后仅收到状态事件(response.created/in_progress)、未产出任何内容事件(空响应)时仍可切换,一旦产出首个内容事件即锁定该源。
  • 断路器:失败降级 → 熔断 → 冷却 → 半开探测 → 恢复,逐源可覆盖参数。
  • 模型白名单/v1/models 只返回 models 段显式声明的模型,不暴露上游别名。
  • 结构化日志:等级过滤 + text/json 输出,全走 slog
  • 配置热重载:管理页保存,或编辑 config.yaml / 同级 base_instructions.mdfsnotify 自动生效,无需重启。
  • H5 管理页:观测台、配置编辑、中英文/明暗主题,挂载在根路径 /所有配置都在网页里完成,无需手动写 YAML。
  • 系统托盘:启动即常驻(含 -d 后台模式),点开即用;headless / 托盘宿主异常时自动降级为信号模式,不影响服务运行;GATEWAY_NO_TRAY=1 可显式禁用。
  • 双击即用:打包为单文件后双击运行即可,首次启动自动生成默认配置,无需命令行、无需提前准备配置文件。
  • 环境变量:YAML 内联 ${ENV} 展开 + CODEX_API_GATEWAY_ 前缀覆盖(可选,网页配置已足够)。

快速开始

不需要命令行。 构建(或下载)出二进制后,双击运行即可。

  1. codex-api-gateway 二进制放到任意目录,双击打开。
    • 首次运行会在同目录自动生成 config.yaml(最小默认配置,未含任何上游源)。
    • 进程启动后常驻在系统托盘,点托盘图标的「打开」菜单即可进入管理页。
  2. 浏览器打开管理页 http://localhost:8383/(或托盘菜单「打开」)。
    • 配置管理里添加上游源(粘贴 API Key、填 base_url、设 model_map),保存即热重载生效。
    • 未配置上游源前,转发请求会返回 503,配好即恢复。
  3. 把 Codex 的 base URL 指向网关根(含 /v1):
http://127.0.0.1:8383/v1

Codex 会自动在 base_url 后拼接 /responses/models不要把 base_url 写成 …/v1/responses——那样 /models 会打到 /v1/responses/models 返回 404,Codex 拉不到模型列表。

退出时右键托盘图标选「退出」,或直接关闭托盘进程即可。

开机自启(推荐托盘勾选)

托盘菜单提供 「开机自启」 勾选项(Linux / Windows / macOS):

  1. 右键托盘图标 → 勾选「开机自启」即写入系统登录自启;
  2. 再点一次取消勾选即关闭。

平台机制:

平台 注册位置
Linux ~/.config/autostart/codex-api-gateway.desktop
Windows HKCU\...\CurrentVersion\Run
macOS ~/Library/LaunchAgents/codex-api-gateway.plist

自启命令为当前可执行文件 + -config <绝对路径> -chdir-home,进程启动后自动切换到用户目录($HOME,与直接从用户目录启动一致),登录图形会话后自动带上 DISPLAY/WAYLAND_DISPLAY,托盘「打开」管理页可正常冷启动浏览器。

不要用 systemd --user 无图形环境拉起网关——浏览器冷启动会静默失败。若以前启用过:

systemctl --user disable --now codex-api-gateway.service

可选:task install-autostart 仍可安装应用菜单快捷方式(兼写 autostart desktop,与托盘开关读写同一文件)。

应用到 Codex(推荐托盘勾选)

托盘菜单提供 「应用到 Codex」 勾选项:勾选后把 Codex CLI 的用户配置 $CODEX_HOME/config.toml 指向本网关(新增 model_providers.codex-api-gateway 并置 model_provider = "codex-api-gateway",顶层 model_catalog_json 指向 $CODEX_HOME/models.jsonbase_url 自动取当前监听端口);取消勾选恢复启用前的 model_providermodel_catalog_json 原值。

  • 启用前的原值备份在 ~/.codex/codex-api-gateway-backup.json,恢复后自动删除。
  • 备份文件异常缺失时,取消勾选会移除网关注入键并回落到 Codex 默认 provider(对应 WARN 日志)。
  • config.toml 不存在时不自动创建,请先运行一次 codex 生成配置。
  • 网关监听端口变更后,重新勾选一次即可刷新 provider 块的 base_url
  • 管理页新增/删除/排序模型并保存后,网关会同步刷新 $CODEX_HOME/models.json, 文件内容与 /v1/models 一致,Codex 通过 model_catalog_json 读取最新模型目录。

手动配置 Codex CLI(可选)

一般不需要手动配置:直接用上方托盘「应用到 Codex」勾选即可。以下内容保留给脚本化或特殊场景参考。

方式一:改 ~/.codex/config.toml

[model_providers] 下加一个自定义 provider,base_url 指向网关根(含 /v1,不要带 /responses/models),wire_api 必须设为 responses(网关是 OpenAI Responses 兼容端点):

model_provider = "codex-api-gateway"

[model_providers.codex-api-gateway]
name = "Codex API Gateway"
base_url = "http://127.0.0.1:8383/v1"
wire_api = "responses"   # provider 不声明 auth/env_key,网关 /v1/* 不校验入站 Authorization

model 填网关 models 段声明的别名(即 model_map 的键,例如 gpt-5),网关再映射成上游真实模型。

方式二:命令行 -c 覆盖(临时、单次会话)

不改配置文件,用 -c 传 TOML 键值(点路径表示嵌套),优先级高于 config.toml

codex -c 'model_provider="codex-api-gateway"' \
      -c 'model_providers.codex-api-gateway.name="Codex API Gateway"' \
      -c 'model_providers.codex-api-gateway.base_url="http://127.0.0.1:8383/v1"' \
      -c 'model_providers.codex-api-gateway.wire_api="responses"' \
      -m gpt-5

方式三:环境变量(仅覆盖单个 provider 字段,需配合 config.toml 的 provider 壳)

Codex 没有统一的 OPENAI_BASE_URL 环境变量,base_url 只能写在 [model_providers] 段。若整段配置都由脚本生成,可在脚本里把 base_url 写成变量渲染进 TOML,再 codex -c 覆盖。

验证:启动 Codex 后随便发条消息,网关管理页「观测台」应出现一条请求;若 Codex 报 404 / unauthorized,99% 是 base_url 多了 /responseswire_api 没设 responses

从源码构建(仅开发者)

task build                 # 产出 ./codex-api-gateway
#
go build -o codex-api-gateway ./cmd/server

想要发布包(双击即用),用 task build 产出单文件二进制即可,无需任何运行前配置。 跨平台交叉编译示例:

# macOS (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -o codex-api-gateway-darwin-arm64 ./cmd/server
# Windows
GOOS=windows GOARCH=amd64 go build -o codex-api-gateway.exe ./cmd/server
# Linux
GOOS=linux GOARCH=amd64 go build -o codex-api-gateway-linux-amd64 ./cmd/server

管理页

管理页是唯一的配置入口。双击启动后,浏览器打开 http://localhost:<listen>/(默认 http://localhost:8383/,或点托盘「打开」菜单)即进入 H5 控制台。所有上游源、模型白名单、断路器参数、全局设置都能在网页里图形化增删改,保存即热重载,不用碰 YAML、不用命令行。

  • 观测台:6 张 Token 指标卡(上游调用量 / 输入 / 输出 / 缓存创建 / 缓存命中 / 缓存 Token 命中率)+ 供应商 × 模型 用量聚合表 + 最近 1000 条请求历史(按模型/供应商/Code 过滤,耗时渐变色条)。指标按上游尝试聚合;总输入已按协议归一化,Anthropic 为 input + cache_read + cache_creation,Chat/Responses 使用已含缓存 Token 的 input;命中率为缓存读取 Token / 归一化总输入 Token。
  • 实时推送:指标经 SSE(/admin/api/events)每 3 秒推送,无需手动刷新。
  • 配置管理:图形化编辑供应商(含 model_map 列表式编辑、单源断路器、停用/启用、上移/下移排序)、模型白名单、全局参数、基线指令文件(config 同级 base_instructions.md)。
  • 个性化:中英文切换、亮/暗主题,均记忆在 localStorage。
  • 性能隔离:指标采集走独立 goroutine + 带缓冲 channel,请求路径只做一次非阻塞投递,channel 满即丢弃,绝不拖慢转发;管理端异常不影响 /v1/*。指标为进程生命周期内的内存累计值,重启后清零。

JSON 接口(前端调用,也可独立集成):

方法 路径 说明
GET /admin/api/metrics 当前指标快照
GET /admin/api/config 读取配置视图
POST /admin/api/config 全量覆盖写回并热重载
GET /admin/api/guidance 读取基线指令文件(config 同级 base_instructions.md)内容
POST /admin/api/guidance 保存基线指令文件(config 同级 base_instructions.md)
POST /admin/api/config/reload 手动触发从磁盘 reload
POST /admin/api/sources/promote 手动将源提升回 normal
POST /admin/api/sources/disabled 即时停用/启用单源(写盘 + 热重载)
POST /admin/api/sources/test base_url + api_key 探测上游连通性与 key 有效性
POST /admin/api/sources/reorder 调整源顺序(写盘 + 热重载)
POST /admin/api/sources 追加新源(写盘 + 热重载)
POST /admin/api/sources/delete 按 name 删除源(写盘 + 热重载)
POST /admin/api/upstream-models 用连接参数试拉上游模型列表(未落盘配置)
GET /admin/api/models 按源名拉取上游模型列表
POST /admin/api/models/reorder 调整模型白名单顺序(写盘 + 热重载)
POST /admin/api/models/add 追加模型白名单项(写盘 + 热重载)
POST /admin/api/models/delete 删除模型白名单项(写盘 + 热重载)
GET /admin/api/version 返回构建注入版本号
GET /admin/api/events SSE 推送 metrics 快照(每 3s 一次)

配置

完整示例见 config.example.yaml

服务监听

server:
  listen: ":8383"
  max_body_mb: 32              # /v1/responses 请求体上限(MiB),超限 413
  read_header_timeout: 10s     # 读完请求头超时;不影响 SSE 长流

本机防误伤:限制超大 body,避免长历史/大图 base64 撑爆内存;read_header_timeout 防止半开连接挂住,设置全局写超时以免掐断长 SSE。

日志

logging:
  level: info   # debug | info | warn | error
  format: text  # text | json
  # file: gateway.log
  # max_size_mb: 50   # 单文件滚动阈值(仅 file 模式)
  # max_backups: 3    # 保留历史文件个数
等级 内容
debug 输入项、会话回填、上游流事件、SSE 转换、上游错误详情
info 启动、请求进入、转换完成、上游流锁定、请求完成
warn 请求解析失败、上游失败、断路器跳过、重试
error 服务端写出失败、请求最终失败、HTTP 服务退出

环境变量(可选)

普通场景直接在管理页填写 API Key 即可,无需环境变量。仅当你希望密钥不落盘、或用脚本批量覆盖配置时,才用以下两种方式(后者优先级更高;加载顺序:先展开 ${ENV} 并加载 YAML,再应用 CODEX_API_GATEWAY_ 覆盖)。

# 方式一:YAML 内联展开
sources:
  - name: anthropic-official
    api_key: ${ANTHROPIC_KEY}
# 方式二:CODEX_API_GATEWAY_ 前缀覆盖(层级用双下划线 __,字段单下划线保留)
export CODEX_API_GATEWAY_LOGGING__LEVEL=debug
export CODEX_API_GATEWAY_SOURCES__0__API_KEY=sk-ant-...
export CODEX_API_GATEWAY_BREAKER__MAX_RETRIES=2

后端源

sources:
  - name: anthropic-official
    base_url: https://api.anthropic.com
    api_key: ${ANTHROPIC_KEY}
    model_map: { gpt-5: claude-sonnet-4-20250514 }
    default_model: claude-sonnet-4-20250514
  • sources 列表顺序即优先级,第一个源优先尝试。
  • base_url 写上游根地址,不含 /v1/messages
  • model_map 把 Codex/OpenAI 侧别名映射到上游真实模型名。
  • default_model 用于请求模型未命中 model_map 时兜底。
  • disabled: true 人工停用该源(不参与调度);管理页可即时切换,也可直接改 YAML。

建议让 Codex 使用 gpt-5gpt-5.5 这类别名,再经 model_map 映射到上游专有模型(如 glm-5.2)。直接把 Codex 模型名设成上游专有名,Codex 可能缺本地元数据。

断路器

breaker:
  first_byte_timeout: 12s
  request_timeout: 120s
  degrade_threshold: 3
  degrade_interval: 1m
  degraded_recovery_threshold: 1
  circuit_interval: 30m
  circuit_recovery_threshold: 1
  recovery: normal
  max_retries: 0

状态流转:normal → degraded → circuitOpen → halfOpen → normal/degraded

参数 含义
first_byte_timeout 等待上游首个流式事件的最长时间,超时计为失败
request_timeout 单个源单笔上游调用的总时长上限(默认 120s,0 或缺省走默认,负值拒绝)。与首字节超时不同:不被首个事件停止,到点即终止该笔调用并返回 failed 终态/504;未出内容时该源按失败计熔断并允许换源,已出内容时源锁定、流以 failed 收尾不换源
degrade_threshold 连续失败达阈值后降级,再达阈值后熔断
degrade_interval 降级源超过此间隔无新失败后恢复到原始优先级位置进入机会窗口(状态仍保持 degraded;机会内失败重新排到队尾,连续 N 次机会失败后熔断)
degraded_recovery_threshold degraded 恢复到 normal 所需的连续成功次数(降级恢复阈值)
circuit_interval 熔断后进入半开探测前的等待时间
circuit_recovery_threshold halfOpen 恢复到 normal/degraded 所需的连续探测成功次数(熔断恢复阈值)
recovery 半开探测成功后恢复到 normaldegraded
max_retries 所有源全部失败后的整轮重试次数(0=不重试;仅全局,单源不覆盖)

request_timeout 支持单源覆盖,零值继承全局:

单源可覆盖部分断路器参数,零值字段继承全局:

sources:
  - name: zhipu
    base_url: https://open.bigmodel.cn/api/anthropic
    breaker:
      first_byte_timeout: 8s
      request_timeout: 90s
      circuit_interval: 10s

API

POST /v1/responses

核心转发入口。请求体为 OpenAI Responses API 格式;按命中源的 backend_type 走 a/c/r 适配或透传,响应始终为 OpenAI Responses SSE 流。

GET /v1/models

返回 Codex ModelsResponse 格式({ "models": [ModelInfo] })而非 OpenAI 的 { data: [] },Codex 据此直接解析 ModelInfo 能力字段(如 supports_search_tool)。只返回 models 段显式声明的模型,不拉取上游 /v1/models,也不暴露 model_map 别名。

架构

分层、单向依赖的 Go 服务,禁止反向引用:

L5 观测/管理  internal/admin  internal/metrics
L4 编排      internal/server
L3 运行时    internal/scheduler  internal/backend(a/c/r 适配器)
L2 转换      convert/streamconv(a)  chatconvert/chatstreamconv(c)  透传无 L2(r)
L1 客户端    anthropic  chatclient  responsesclient
L0 基础      config  logging  model  breaker  toolcatalog

两条贯穿路径:

  • 配置生效路径(单一真相源):磁盘 config.yaml(及同级 base_instructions.md)→ config.Loadholder.Replacescheduler.Reload。管理页保存与外部编辑都走写盘 → fsnotify → 这条链路。
  • 请求转发路径/v1/responsesserverscheduler.ExecuteGeneric → 按源选 backend(a/c/r)→ 上游 SSE → 回写 Responses SSE。任何失败以 error / SSE 错误事件返回,不 panic 逃逸。

开发

普通用户无需此节——双击二进制即可运行。以下仅面向想从源码改代码的开发者。

优先使用 Taskfile:

task build       # 构建二进制 ./codex-api-gateway(双击即用)
task run         # 前台开发调试:用当前目录 config.yaml 跑起来
task up          # 后台启动(-d,类似 docker compose up -d)
task stop        # 按 gateway.pid 停止
task restart     # stop 后后台启动,并等 /v1/models 健康
task test        # 运行全部测试
task test-race   # race detector
task cover       # 覆盖率
task check       # gofmt 检查 + go vet + go test

未安装 Task 时直接用 Go:

go test ./...
go build -o codex-api-gateway ./cmd/server   # 构建双击即用二进制
go run ./cmd/server                          # 开发调试:默认读 ./config.yaml
go run ./cmd/server -config config.yaml -d   # 后台启动(写 gateway.pid / gateway.log)

维护与排错

清理 Codex 模型缓存

Codex CLI 会把 /v1/models 的返回缓存在 ~/.codex/models_cache.json。当网关 models 段或某个源的 model_map 发生变化(新增/改名模型别名)后,Codex 可能仍用旧缓存、拉不到新模型。此时删掉缓存文件,下次启动 Codex 会自动重新拉取:

rm -f ~/.codex/models_cache.json

常见症状

症状 可能原因 处理
Codex 报 404 base_url 写成 …/v1/responses 改成 …/v1,Codex 自己拼 /responses/models
Codex 报 unauthorized requires_openai_auth 没设 truewire_api 没设 responses 见「配置 Codex CLI 指向网关」
转发返回 503 网关未配置任何上游源,或全部源被停用 管理页「配置管理」加源/启用源并保存
Codex 拉不到新模型 models_cache.json 旧缓存 ~/.codex/models_cache.json 重启 Codex

产品边界

本网关是 Codex CLI → 多上游 的协议适配 / 透传层,不是 OpenAI 全量 Responses 平台,也不是 session 运行时:

  • 客户端自带完整 input 回灌:网关无 session store,不按 previous_response_id 补历史。
    • a 源:非空 previous_response_id 通常 WARN + 忽略(字段不进 Anthropic)。
    • 配置含启用中的 r 源时:字段透传上游,日志说明「网关不代补会话」,不写「数据被丢弃」。
  • a 路径:Responses ↔ Anthropic Messages 直转,不经 Chat 中枢。
  • c / r:并行 Backend;c 做 Chat 形状转换,r 做 Responses 最小改写透传(model 映射、强制 stream、出站 model 别名回写)。

已知限制

下列限制主要针对 a(Anthropic) 路径的协议映射天花板。c / r协议覆盖矩阵 专节;r 以形状透传为主,能力由上游决定。

  • 多模态input_image.file_id 不支持(网关无 OpenAI 凭据拉取文件;仅接受 base64 / URL)。
  • web_search:出站完整(事件链 + url_citation,流式与终态 item annotations 都写);历史回灌为 server_tool_use + 空 web_search_tool_result + sources 可见文本——OpenAI wire 无 Anthropic required 的 encrypted_content,无法做官方级 result round-trip。
  • code interpreter:网关整体不支持(a 声明 fail-fast;c 声明 Debug 跳过;历史与回程静默忽略/skip),不再映射 Anthropic code_execution。
  • structured outputtext.format.json_schema / json_object a/c 统一忽略(output_config 仅保留 effort),不写 output_config.formatresponse_format
  • redacted_thinking:网关只接受明文 thinking;出站 redacted_thinking 块跳过,入站 redacted 密文(无 summary 文本的 encrypted_content)忽略,明文 thinking 签名回灌保留。
  • MCP
    • MCP 由 Codex 客户端本地执行:allowed_tools 展开为扁平 mcp__<server>__<tool> function 声明,回程走 function_call,不再注入 Anthropic beta MCP 配置
    • mcp_call 历史 → 标准 tool_use + tool_result(扁平名直接回填)
    • mcp_list_tools 历史 → DEBUG 丢弃(opencode 无此类型,Codex 不把 AdditionalTools 转消息,工具经请求 tools/ToolSpec 声明)
    • mcp_approval_request / response 不实现:Anthropic 无审批协议,历史 WARN + 丢弃
    • 连接字段(server_url/headers/require_approval/connector_id/tunnel_id)不注入或 fail-fast,交给客户端本地连接执行
  • tool_choice allowed_tools:仅 auto/required 映射;条目按 type/namespace/name 精确匹配已声明工具;含 hosted/MCP 条目时 fail-fast。
  • 无等价历史 itemfile_search_call / computer_call* / image_generation_call / program* / item_reference / additional_tools):WARN + 丢弃,不进 system context。
  • 无等价请求参数(a 路径)background / conversation / context_management / max_tool_calls / prompt / deprecated user 等按 WARN + 忽略;moderation / top_logprobs / prompt_cache_* / safety_identifier / service_tierc 路径透传(a 路径按 INFO 提示忽略)。

完整状态见协议覆盖矩阵(含 Anthropic a、Chat Completions c 与 Responses 透传 r 专节)。

设计文档

About

让 Codex CLI 接入 Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 三种上游接口协议的统一网关,本地提供 Responses 兼容端点,支持多源路由、故障转移与熔断。

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages