影响范围
供应商切换 / 配置写入(apply_pure_api_injection)
接入模式
纯 API
当前行为
在 Codex++ 设置界面点击切换供应商时,apply_pure_api_injection 会破坏性重写整个 ~/.codex/config.toml——只保留一个占位段(model_provider 当前指向的段),把目标供应商的部分字段写进去,清空其他所有 [model_providers.X] 段。
后续切换其他供应商时,因目标段已被自己清空,verify 阶段失败,弹出:
供应商切换失败:纯 API 配置写入后未检测到完整 custom provider,请检查 config.toml 和供应商 API Key。
而且占位段的内容会被「部分覆盖」——段名 / display name / api_key 保留旧值,只有 wire_api 和 base_url 被更新,导致段内容变成不伦不类的混合状态。
预期行为
切换供应商时应该只更新 model_provider 字段 + 目标供应商段的内容(或直接改 model_provider 指向目标段名),保留其他所有 [model_providers.X] 段不动。这样用户可以自由切换任意供应商,不依赖段是否被自己清空。
复现步骤
- 在
~/.codex/config.toml 里配置多个供应商段(例如 7 个:zhipu / apikey_gork / one_api / agnes / deepseek / apikey_fun / custom)
- 启动 Codex++,设置界面显示全部 7 个供应商
- 点击切换到供应商 A(例如 apikey gork)
- UI 显示切换成功("使用"标签移到 A 上)
- 但
config.toml 被整个重写,只剩 1 段(占位段,内容被污染为「旧段名 + A 的 base_url + 旧 api_key」的混合)
- 其他 6 段全消失
- 点击切换到供应商 B(例如 apikey.fun)
- 弹出错误「纯 API 配置写入后未检测到完整 custom provider」
- 原因:
[model_providers.apikey_fun] 段已在第 3 步被自己清空
证据
证据 1:切换前后 config.toml 段数对比
切换前(7 段):
[model_providers.custom]
[model_providers.zhipu]
[model_providers.apikey_gork]
[model_providers.one_api]
[model_providers.agnes]
[model_providers.deepseek]
[model_providers.apikey_fun]
切换到 apikey gork 后(只剩 1 段,且内容被污染):
[model_providers.zhipu] # 段名仍是 zhipu(占位段)
name = "zhipu" # 仍是 zhipu
wire_api = "responses" # 被改成 responses
base_url = "https://api.apikey.fun" # 被改成 apikey gork 的 url
api_key = "d3f4...(zhipu 的 key,未更新)" # 仍是 zhipu 的 key
注意:段名 / display name / api_key 都没被正确更新为目标供应商的值,只有 wire_api 和 base_url 被覆盖。
证据 2:manager 二进制里的错误链
用 Node 脚本扫 codex-plus-plus-manager.exe 的 UTF-8 字符串,找到完整错误链:
manager.apply_pure_api_injection.before
manager.apply_pure_api_injection
manager.apply_pure_api_injection.generated
manager.apply_pure_api_injection.ok
纯 API 配置写入后未检测到完整 custom provider,请检查 config.toml 和供应商 API Key。
纯 API 模式已写入:config.toml 已写入 custom provider,auth.json 已切换为当前供应商。
manager.apply_pure_api_injection.failed
写入纯 API 模式失败:{error}
manager.apply_pure_api_injection.profile
切换纯 API 配置失败:{error}
说明 apply_pure_api_injection 的流程是:写入 → 再读回 verify。verify 失败就弹这个错。
证据 3:没有「保留所有段」的开关
扫 manager 二进制查找 preserve / merge / keep_providers / non_destructive 等关键词,没有找到任何相关开关。说明这是默认行为,用户无法通过配置关闭。
根因猜测
apply_pure_api_injection 的实现可能是:
- 从某个内部 store(UI 显示的供应商列表来源)读取目标供应商配置
- 重写整个
config.toml(而不是只更新 model_provider 和占位段)
- 重写时只输出「当前激活的占位段」,遗漏了其他
[model_providers.X] 段
- 写完后读回
config.toml 验证占位段完整
问题出在第 2-3 步:重写时应该保留所有段,只更新占位段的内容;或者根本不应该重写整个文件,只改 model_provider 字段 + 占位段。
修复建议
方案 A(推荐,最小改动):apply_pure_api_injection 改为只更新 model_provider 字段 + 目标供应商段的内容,不重写整个 config.toml。具体:
- 读当前 config.toml
- 用正则/TOML 库定位
[model_providers.<target>] 段
- 更新该段的 base_url/api_key/wire_api 等字段
- 改
model_provider = "<target>"
- 写回(保留其他所有段)
方案 B:如果一定要重写整个 config.toml,重写时应该输出所有 [model_providers.X] 段(从内部 store 读取),而不是只输出占位段。
方案 C:如果占位段机制是设计意图(用一个固定段名作为占位),那么切换时把目标供应商配置写入占位段 + 保留其他所有原始段不动(作为「供应商库」供下次切换读取)。
临时解决方案
写了一个 PowerShell 脚本绕开这个 bug,只改 model_provider / model / auth.json 三处,不动其他段:
.\switch-provider.ps1 list # 列出所有供应商段
.\switch-provider.ps1 deepseek # 切到 deepseek(默认模型)
.\switch-provider.ps1 deepseek deepseek-reasoner # 切并指定模型
实测切换 agnes ↔ deepseek 双向通过,7 段全保留。
环境信息
- Codex++ 版本:1.2.38(
codex-plus-plus.exe + codex-plus-plus-manager.exe)
- Codex CLI 版本:26.609.41114
- 操作系统:Windows 11
- config.toml 路径:
C:\Users\<user>\.codex\config.toml
相关 issue
提交前确认
影响范围
供应商切换 / 配置写入(
apply_pure_api_injection)接入模式
纯 API
当前行为
在 Codex++ 设置界面点击切换供应商时,
apply_pure_api_injection会破坏性重写整个~/.codex/config.toml——只保留一个占位段(model_provider当前指向的段),把目标供应商的部分字段写进去,清空其他所有[model_providers.X]段。后续切换其他供应商时,因目标段已被自己清空,verify 阶段失败,弹出:
而且占位段的内容会被「部分覆盖」——段名 / display name / api_key 保留旧值,只有
wire_api和base_url被更新,导致段内容变成不伦不类的混合状态。预期行为
切换供应商时应该只更新
model_provider字段 + 目标供应商段的内容(或直接改model_provider指向目标段名),保留其他所有[model_providers.X]段不动。这样用户可以自由切换任意供应商,不依赖段是否被自己清空。复现步骤
~/.codex/config.toml里配置多个供应商段(例如 7 个:zhipu / apikey_gork / one_api / agnes / deepseek / apikey_fun / custom)config.toml被整个重写,只剩 1 段(占位段,内容被污染为「旧段名 + A 的 base_url + 旧 api_key」的混合)[model_providers.apikey_fun]段已在第 3 步被自己清空证据
证据 1:切换前后 config.toml 段数对比
切换前(7 段):
切换到 apikey gork 后(只剩 1 段,且内容被污染):
注意:段名 / display name / api_key 都没被正确更新为目标供应商的值,只有
wire_api和base_url被覆盖。证据 2:manager 二进制里的错误链
用 Node 脚本扫
codex-plus-plus-manager.exe的 UTF-8 字符串,找到完整错误链:说明
apply_pure_api_injection的流程是:写入 → 再读回 verify。verify 失败就弹这个错。证据 3:没有「保留所有段」的开关
扫 manager 二进制查找
preserve/merge/keep_providers/non_destructive等关键词,没有找到任何相关开关。说明这是默认行为,用户无法通过配置关闭。根因猜测
apply_pure_api_injection的实现可能是:config.toml(而不是只更新model_provider和占位段)[model_providers.X]段config.toml验证占位段完整问题出在第 2-3 步:重写时应该保留所有段,只更新占位段的内容;或者根本不应该重写整个文件,只改
model_provider字段 + 占位段。修复建议
方案 A(推荐,最小改动):
apply_pure_api_injection改为只更新model_provider字段 + 目标供应商段的内容,不重写整个 config.toml。具体:[model_providers.<target>]段model_provider = "<target>"方案 B:如果一定要重写整个 config.toml,重写时应该输出所有
[model_providers.X]段(从内部 store 读取),而不是只输出占位段。方案 C:如果占位段机制是设计意图(用一个固定段名作为占位),那么切换时把目标供应商配置写入占位段 + 保留其他所有原始段不动(作为「供应商库」供下次切换读取)。
临时解决方案
写了一个 PowerShell 脚本绕开这个 bug,只改
model_provider/model/auth.json三处,不动其他段:实测切换 agnes ↔ deepseek 双向通过,7 段全保留。
环境信息
codex-plus-plus.exe+codex-plus-plus-manager.exe)C:\Users\<user>\.codex\config.toml相关 issue
apply_pure_api_injection状态管理问题)提交前确认