Skip to content

v3.1.1

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Oct 21:42
· 114 commits to main since this release

v3.1.1 以修复为主,同时带来两项社区贡献的大功能。修复方面:gpt-6.1-sol 在所有套餐上报「not supported when using Codex with a ChatGPT account」(#793)、积分顶替显示「已生效」却不接流量(#791)、Gemini 4 Argon 多轮工具调用报缺少 thought_signature(#792),另外首次初始化改为必须提供日志里的一次性令牌(安全修复)。功能方面:新增账号降智检测(#790);Responses 保留原生请求语义,WebSocket 支持多流并行(#788)。

Features

  • 账号降智检测(#790,@OneAHPro 贡献)。

    背景:号池里的账号可能被上游悄悄降级(答错题或响应明显变慢),之前没有固定账号、持续观察的手段。

    方案:新增「降智检测」页面(/admin/intelligence-check),用管理员维护的题库对指定账号做手动或定时检测。

    • 支持 GPT/Codex、Responses 中转和 Claude 账号;Grok、Antigravity 暂不支持。
    • 每道题有预期答案(完整匹配 / 包含 / 正则)和可选的耗时上限,最多 100 题。
    • 检测复用账号的请求执行器、身份、指纹和时区配置。只走账号绑定的代理:未绑定时直连,绑定代理失败时不回退直连。
    • 请求失败单独记为「错误」,和答错分开,不计入通过率。
    • 连续未通过达到阈值时,可以自动暂停调度或切换分组,恢复阈值达到后自动还原。只还原检测自己做的暂停或切组;人工改过账号调度开关或分组后,检测就不再管这个账号的状态。
    • 账号表格、卡片和详情在健康条旁显示最近 20 次结果,历史可分页查看(默认每账号保留 200 条)。
    • 任务走 SQLite / PostgreSQL 持久队列,有租约、每账号去重和共享并发上限。

    验证:贡献者在本地跑了 Go 全量测试和定向 -race、PostgreSQL 16 行为集、前端 379 项单测和 7 项浏览器回归;main 上 CI 全绿。维护者没有在生产号池上长期运行过。

  • Responses 保留原生请求语义,WebSocket 支持多流并行(#788,@dundunge 贡献)。

    背景:Responses 请求经过网关转换时,可能丢掉原生的 reasoning、结构化输出约束或父轮上下文;WebSocket 逐轮串行处理,互相独立的工具流也会排队等待。

    方案:

    • 原生字段:Responses 中转原样保留 reasoning.effort、text.format、JSON Schema 约束和大整数;原生字段优先于 reasoning_effort、response_format 等兼容别名。
    • 严格模式(可选):请求头 X-Codex2API-Strict-Compatibility: true,或环境变量 CODEX_STRICT_RESPONSES_COMPAT=true。原生 Codex 路径会丢弃或改写的字段、工具 schema、输出 schema,在严格模式下直接返回 400 unsupported_feature,并在 error.details.fields 里列出字段。检查按实际选中的原生 Codex 账号进行,中转账号不受影响。默认不开启,默认行为沿用原有兼容转换。
    • WebSocket 多流:GET /v1/responses 上,同一个 stream_id(以及缺省流)内保持先后顺序,不同流并行处理。每连接最多 16 个活动轮次、32 个命名流,队列有界。一个命名流的请求失败不再关掉其他健康的流。
    • 跨流续链:同一个客户端连接可以从自己另一个流里已提交的 store:false 响应继续,Key、分组、账号和凭据代际的隔离规则不变。
    • 能力清单:探测到的 experimental_supported_tools 会保存下来,Codex 模型清单按 Key 能用的账号取交集后下发。
    • response.append / response.steer 返回 unsupported_feature,本版没有实现生成中改向。

    详见 docs/RESPONSES_COMPATIBILITY.md。

    验证:贡献者用真实 Codex CLI 0.162.0-alpha 和 gpt-6-luna 测了 HTTP 4 次、WebSocket 6 次,读文件、apply_patch、执行命令和工具结果续轮都正确;同一 WebSocket 连接上的命名流、同流续链和跨流分叉也恢复正确。贡献者也说明了一项没通过的测试:图片盲测里模型读错一位数字,原因未确定,所以不宣称视觉准确率达标。

  • Antigravity 发布 Gemini 4 Argon 三档思考强度。

    • 账号目录里出现 gemini-4-argon-high 后,网关发布 gemini-4-argon-low / -medium / -high,分别对应 thinkingLevel;裸名 gemini-4-argon 默认 high。
    • /v1/messages 也会在检查 Key 限制、选号之前,把 Antigravity 的裸逻辑模型名折叠成对应档位;中转账号保留逻辑名。
    • Codex 模型清单里 Argon 只显示一个选项,思考强度按 Key 选择,上下文窗口 1,048,576 token。
    • gemini-4-argon-disabled 这类禁用占位会在管理端目录里显示(带禁用遮罩),但不对外发布、不参与调度,也不会被自动选去测连。批量测试只剩禁用模型时,不再把账号标成异常。
    • 没有额度元数据的模型显示「额度未知」,不再显示一个凭空算出来的剩余百分比。

    验证:新增测试覆盖分档、折叠和占位;Argon 的实际生成没有对真实上游验证过(Argon 需要 Ultra / Enterprise 账号,维护者手头没有)。

  • Antigravity 的 Workspace / 企业账号可以填写自己的 GCP 项目。

    背景:Google 只给个人套餐(免费档、Google One AI Pro/Ultra)分配托管的 Cloud Code 项目。Gemini Code Assist Standard / Enterprise 的 Workspace 账号完成 onboarding 后拿不到项目,账号无法调度,额度查询报 "You do not have a valid license of this product"。

    方案:Antigravity 账号编辑弹窗新增「GCP 项目 ID」(user_project_id,存为 antigravity_user_project_id)。

    • 项目会发给 loadCodeAssist,非免费档还会发给 onboardUser。保存后立即重新同步账号。
    • Google 返回的项目仍然优先。免费档始终不带这个项目,因为带上会报 FAILED_PRECONDITION。
    • onboarding 结束仍没有项目时,错误信息会说明该档位是否要求自备项目,以及在哪里填写。

    验证:新增导入、更新和 onboarding 测试;没有用真实 Workspace 账号实测。

  • 「不支持模型冷却」可配置,号池耗尽时返回真实错误。

    • 新设置 oauth_unsupported_model_cooldown_seconds(默认 1800 秒,范围 0–1800,0 关闭):上游回复 "model is not supported when using Codex with a ChatGPT account" 后,该账号在这段时间内不再承接这个模型。其他模型和账号健康度不受影响,这个 400 不再计为账号故障。
    • 调短或关闭时,会清掉超过新时长的已有冷却。
    • Responses、Chat Completions、Messages 不再为这种情况返回 503 "no available accounts":最后一次尝试就是这个 400 时,透传上游原文;所有可用账号都在冷却时,返回 400(code model_not_supported),写明模型名和最早恢复时间。
    • 号池里混有 free 和付费号时,仍建议用账号级模型白名单。

    验证:新增设置读写、冷却清理和各端点错误形态的测试。

Fixes

  • gpt-6.1-sol 不再在所有套餐上报「model is not supported when using Codex with a ChatGPT account」(#793,@syunnrai123 报告)。

    现象:请求 gpt-6.1-sol 报上述错误,同步最新客户端版本后依旧。

    根因:

    • 上游对「套餐不支持这个模型」和「客户端版本低于这个模型的真实门槛」返回的是同一段文案。
    • gpt-6.1-sol 在模型清单里自称 minimal_client_version: 0.153.0,实测要 0.159.0 才会出现。网关内置的 0.153.3 在所有套餐上都会被拒。
    • 网关把它当成套餐问题,给每个账号写 30 分钟模型冷却,一次请求会烧掉几个号,冷却很快铺满全池;版本同步也不清这些冷却,所以「同步后无效」。

    修复:

    • 内置 Codex CLI 版本和新安装的 codex_min_cli_version 默认值升到 0.160.0;Desktop / VSCode 预设加上官方 0.160.0 配对,不同步也能过版本门槛。
    • Pro 档账号(Spark 除外)报这个错时判为版本闸:不写冷却,并在 30 分钟内记住「模型 + 出站版本」组合,同组合下低档账号失败也不写冷却。套餐闸照旧按(账号,模型)冷却。
    • 客户端版本同步写入更新的版本时,清掉已有的 model_not_supported 冷却,旧的仅 CLI 同步端点也算。
    • 失败日志记录出站 Version;gpt-6.1-sol 和其他 GPT-6 模型一样标为不支持 API Key 认证(仅元数据)。

    验证:新增版本闸判定测试;2004 部署实测 gpt-6.1-sol 经 WebSocket 打到 Pro 号返回 200,出站 UA 为 codex-tui/0.160.0。2004 本来就已同步到 0.160.0,所以内置版本号的效果和版本闸分支都没有在真实上游上单独触发过。

  • 开启积分顶替后账号真正接流量(#791,@xiaobulv 报告)。

    现象:账号弹窗显示积分顶替「已生效」、余额充足,但账号一直分不到请求。

    根因:

    • 额度自动暂停不看积分。阈值最高只能设到 100%,所以账号、分组、全局任意一层设了 5h 或 7d 自动暂停,账号都会在窗口用尽、切到积分之前就被停掉;列表上还同时挂着「使用积分」徽章。5h 护栏带(并发压缩和调度扣分)同理。
    • 开启积分只会释放本地记录的 7d 判罚。开关打开之前从响应头或 WHAM 记录的 5h 判罚(rate_limited_5h)会一直保留到 5h 重置。

    修复:积分在顶替时,自动暂停和 5h 护栏带都让位;积分用完或工作区触发硬停后恢复。rate_limited_5h 和 7d 判罚一样会被释放。真实的 /responses 429 记录在另一个原因下,仍然生效。

    验证:新增 5 项测试;没有在 2004 实测(没有窗口已用尽且有积分的账号)。上游在窗口用尽后是否真的扣积分放行,本项目从未在真实上游上确认过,如果升级后仍不接流量,请在 issue 里附上错误原文。

  • Antigravity Gemini 多轮工具调用不再报「Function call is missing a thought_signature」(#792,@Likhixang 报告)。

    根因:回放历史函数调用时,只有模型名含 flash / pro / thinking,或正好是 gemini-4-argon-high 才会补签名占位。裸名 gemini-4-argon 这类直通模型发出去的 functionCall 没有签名,多轮工具循环每次都失败。

    修复:所有 gemini- 开头的后端模型都补占位。Responses / Chat Completions / Messages 转换和原生 /v1beta 清洗都覆盖;Claude 和 GPT-OSS 不受影响。占位只是回放字段,多补不会被上游拒绝,漏补会让整个工具循环失败。

    验证:新增端到端测试;没有对真实 Argon 上游验证(同上,需要 Ultra 账号)。

  • Claude Code 内置 WebSearch 经 /v1/messages 可用(#784,@Dominic485649 贡献)。

    现象:Claude Code 走 /v1/messages 用 WebSearch 时,上游返回 400 11129,或者返回一个没有客户端会执行的空 web_search 工具调用。

    根因:Anthropic → Responses 转换把服务端检索工具(web_search_20250305、web_search_20260209、web_search_20260318、preview 变体和不带 schema 的 web_search)当成普通函数转发。

    修复:

    • 转成上游托管的 web_search,保留 user_location 和域名过滤;自带 input_schema 的同名自定义函数仍按函数转发。
    • 上游 web_search_call 还原成 server_tool_use + web_search_tool_result,流式和非流式都处理,流式补发检索 query;托管检索结束后 stop_reason 保持 end_turn。
    • 检索失败或不完整时返回配对的 web_search_tool_result_error,不再留下没有结果的 server_tool_use。
    • 强制选择 web_search 时用 allowed_tools + mode: required,模型不会改选别的函数;缺 input_schema 的普通函数补空参数。

    验证:贡献者对真实上游对照了 tool_choice 的几种写法,新增转换、流式、错误结果等测试。

  • 首次初始化改为必须提供日志里的一次性令牌(安全修复)。

    根因:初始化接口按来源 IP 是否为私网来放行。在 Docker Desktop、rootless 端口转发或私网反代后面,公网请求到达时对端本来就是私网地址;X-Forwarded-For 又由客户端控制。所以没设 ADMIN_SECRET、端口可达时,任何人都可以抢先设置管理密钥。

    修复:

    • 启动时在内存里生成令牌,打印在启动横幅和服务日志里;POST /api/admin/bootstrap 必须带上,初始化成功后作废。运行时清空密钥后,bootstrap-status 会重新生成一个。
    • BOOTSTRAP_ALLOWED_CIDR 改为匹配 TCP 直连对端,转发头不能再伪造进白名单。
    • 只有令牌错误的尝试计入限频,扫描器刷满限频也锁不住管理员;审计日志记录真实对端和声称的转发 IP。
    • 初始化页面新增令牌输入框,并给出查日志的命令。

    验证:新增 5 项测试并做过变异验证;本地临时实例端到端通过。

  • 大体积 Codex 历史在发往上游前的内存分配大幅下降(#787,@HanYC666 报告)。

    现象:一个 10 MiB 的 Responses 请求体在发往上游前要分配约 232 MB,Pi Zero W 上表现为 20–90 秒满 CPU、RSS 峰值接近 300 MB。

    根因:删除一个不存在的字段时,JSON 库也会完整复制一遍文档;图片生成检测对每个缺失字段都把 input 数组扫一遍;多处扫描都在复制 input。

    修复:HTTP、compact 和 WebSocket 路径只删除确实存在的字段,字节不变的写入直接跳过;图片生成检测一次读完顶层字段;几处扫描改为不复制地读取 input;请求大小限制器按声明的 Content-Length 一次性分配缓冲区。

    验证:差分测试证明输出字节不变(畸形 JSON、重复键、转义键,以及 1024 种字段组合)。基准测试:10 MiB 请求分配 232 MB → 87 MB;1 MiB 请求 23.7 MB → 11.3 MB。没有在 Pi Zero W 上实测,欢迎报告者回帖反馈。

  • 一个繁忙的 API Key 不再卡住整个持久化生图队列。

    根因:Worker 取最早的一条排队任务后,原地等这个 Key 的并发槽。某个 Key 被自己的长流式请求占满时,Worker 被它占住,其他 Key 的任务只能干等。

    修复:

    • Worker 每次只看每个 Key 最早的一条任务,先占到该 Key 的并发槽再领取;占不到就跳过,去做别的 Key 的任务。
    • 新增两个限制(仅在用 IMAGE_JOB_WORKERS 启用队列时生效):
      • IMAGE_JOB_MAX_QUEUED_PER_KEY(默认 1000,0 不限):单个 Key 排队任务达到上限后,创建接口返回 429 并带 Retry-After。
      • IMAGE_JOB_MAX_QUEUE_WAIT(默认 24h,0 关闭,最小 1m):排队超过这个时长仍未开始的任务标记为失败,并清理落盘的参考图。这类任务从未请求上游,可以直接重试。
    • 新增 (status, api_key_id, id) 索引。

    验证:新增队列轮转、上限和过期任务测试。

  • 原生 Codex HTTP 续链不再静默丢失历史(#788,@dundunge 贡献)。

    • 网关在请求方自己的缓存里找不到 previous_response_id 时,返回 409(缓存后端故障返回 503),不再返回一轮没有历史的「成功」响应。
    • 新的工具调用输出会拼接到父快照上;只有完整父前缀和重叠的 call_id 都一致时才跳过重复内容,部分或冲突的重放返回 409 response_context_unavailable。
    • 顶层重复的 input / previous_response_id(包括转义后的同名键)返回 400,避免不同 JSON 解析器取到不同的值。
    • HTTP、compact 和上游 WebSocket 请求删除网关信封的顶层字段(type、stream_id),嵌套的同名字段保留。
    • 内置 tool_search 不再被注入非法的 description;background: false 不再被误判为图片背景扩展。
    • 首次初始化时,闲置对话连接和空白 WebSocket 连接的保留数补上默认值 8;已显式设为 0 的保持不变。
  • 公开用量页拒绝已禁用的 API Key。用量页早于 Key 启用开关,禁用的 Key 仍能读到用量汇总、限额和近期请求日志,页面还显示为「正常」。现在返回 401 并记审计,与代理接口和生图工作台一致。已过期、额度用尽的 Key 仍可读取,方便持有者看到调用失败的原因。

  • 慢速 SQLite 存储上价格轮询启动不再超时(#778,@HanYC666 报告)。第一次读取官方价格同步配置时会顺带建表,其中的 INSERT 需要 SQLite 写锁。升级后用量小时汇总的回填几乎一直占着写锁,启动时 5 秒的读取就会报 "context deadline exceeded"。现在先读,读失败才建表。新增回归测试:持有写事务时读取配置,修复前超时,修复后立即返回。

Upgrade Notes

  • 数据库迁移(启动时自动执行,SQLite / PostgreSQL 均支持重复执行):
    • 新增三张降智检测表及索引,以及新账号默认参与检测的初始化触发器(#790)。
    • system_settings 新增 oauth_unsupported_model_cooldown_seconds,默认 1800。
    • image_generation_jobs 新增 (status, api_key_id, id) 索引。
  • 默认行为变化:
    • 首次初始化必须提供启动日志里的令牌。Docker Compose 部署可用 docker compose logs codex2api | grep "bootstrap token" 查看(初始化页面上也有这条命令)。令牌只在当前进程有效,重启后会重新生成。BOOTSTRAP_ALLOWED_CIDR 改为匹配直连对端:放在反代后面时,要填反代所在的网段。多副本部署且没设 ADMIN_SECRET 时,每个副本的令牌不同,建议直接设置 ADMIN_SECRET。已经初始化过的部署不受影响。
    • 积分顶替开启并生效时,额度自动暂停和 5h 护栏带不再拦截这个账号(#791)。如果你用自动暂停来避免消耗积分,请关掉这个账号的积分顶替。
    • 原生 Codex HTTP 请求带的 previous_response_id 无法恢复时返回 409,之前是丢掉历史后照常回答。只用 HTTP 做纯文本续链的客户端,需要改为发送完整历史并省略 previous_response_id,或改用 WebSocket(#788)。
    • 不支持模型的 400 不再计入账号健康度;号池耗尽时返回 400 而不是 503。
    • 内置 Codex CLI 版本升到 0.160.0。已有部署保存的 codex_min_cli_version 不会被改动。
    • 启用了持久化生图队列(IMAGE_JOB_WORKERS)的部署:单个 Key 默认最多 1000 个排队任务,排队超过 24 小时未开始的任务会被标记为失败。
    • 降智检测默认关闭,不会产生任何额外请求。
  • 是否建议升级:用 gpt-6.1-sol、积分顶替、Antigravity Gemini 工具调用,或 Claude Code WebSearch 的部署建议升级。端口可能被公网访问、且还没初始化的部署务必升级后再初始化。
  • 逃生阀:
    • 不想让不支持模型的冷却影响调度:把 oauth_unsupported_model_cooldown_seconds 设为 0。
    • 生图队列限制:IMAGE_JOB_MAX_QUEUED_PER_KEY=0、IMAGE_JOB_MAX_QUEUE_WAIT=0 分别关闭。
    • 严格兼容模式默认关闭,不开就是原来的兼容转换。
    • 初始化令牌没有关闭开关;不想走页面初始化,可以直接设置 ADMIN_SECRET。
  • 本次发布前验证:
    • main 最新提交上的 CI(Go 全量测试、race 分片、golangci-lint、PostgreSQL 兼容、前端)和 Security Scan 全部通过。
    • 2004 部署只实测了 #793(gpt-6.1-sol 返回 200)。#791、#792、Argon 生成、Workspace 项目、降智检测都没有在真实上游上实测,上文各条已分别注明。

致谢

  • @OneAHPro — 贡献账号降智检测(#790)。
  • @dundunge — 贡献 Responses 原生语义保留、WebSocket 多流和工具续链修复(#788),附有详细的真实客户端验收记录,包括没通过的项。
  • @Dominic485649 — 贡献 /v1/messages 服务端检索工具转发(#784),并根据评审对真实上游做了 tool_choice 对照实验。
  • @syunnrai123 — 报告 gpt-6.1-sol 不支持(#793)。
  • @xiaobulv — 报告积分顶替不生效(#791)。
  • @Likhixang — 报告 Argon 工具调用缺少 thought_signature(#792),并直接指出了出问题的函数。
  • @HanYC666 — 报告 Pi Zero W 上的高内存、高 CPU 占用(#787),以及慢速 SD 卡上的超时(#778)。

Full Changelog: v3.1.0...v3.1.1