Skip to content

fix(codex): ensure [model_providers.<id>] TOML section exists in config.toml#3719

Open
Kakueeen wants to merge 4 commits into
farion1231:mainfrom
Kakueeen:fix/issue-3449-codex-cli-config-toml-format
Open

fix(codex): ensure [model_providers.<id>] TOML section exists in config.toml#3719
Kakueeen wants to merge 4 commits into
farion1231:mainfrom
Kakueeen:fix/issue-3449-codex-cli-config-toml-format

Conversation

@Kakueeen
Copy link
Copy Markdown

@Kakueeen Kakueeen commented Jun 4, 2026

Summary / 概述

Fix Codex CLI ignoring the model_provider = "custom" setting by ensuring the [model_providers.<id>] TOML section always exists in the written config.toml.

Codex CLI requires the [model_providers.<id>] section to route requests to a custom provider. When this section is missing — which can happen when Codex Desktop App rewrites config.toml, when CC-Switch imports a pre-existing flat-format config, or after a backup/restore cycle — Codex falls back to model_provider: openai and all API calls go directly to api.openai.com.

Changes / 变更内容

File Change
src-tauri/src/codex_config.rs Add ensure_codex_model_provider_section() that defensively creates [model_providers.<id>] table when model_provider is set but the table is missing. Integrate into write_codex_live_for_provider and prepare_codex_provider_live_config. Add 6 unit tests covering normalization edge cases.

Fix details (commits 2-3)

  1. Non-implicit TOML table: toml_edit::Table::new() creates implicit tables (no [section] header in output). Changed to set_implicit(false) so the synthesized [model_providers.<id>] header is emitted correctly.
  2. Test assertions: Updated two test assertions to check experimental_bearer_token at its scoped location [model_providers.<id>] rather than the top level — the function intentionally scopes bearer tokens inside the provider table for custom providers.

Root Cause / 根因

The [model_providers.<provider>] TOML table could be lost during the config lifecycle (Codex.app rewrites, import, backup restore). Without this table, Codex CLI ignores the model_provider top-level key and defaults to openai, routing all traffic to the official OpenAI endpoint instead of the configured custom provider.

Test Plan / 测试计划

  • TypeScript type checking passes (pnpm typecheck)
  • cargo test --lib codex_config — 43 passed, 0 failed
  • 6 new unit tests added for ensure_codex_model_provider_section
  • cargo fmt --check / cargo clippy (requires Rust 1.95)
  • Manual verification: create a Codex third-party provider, verify [model_providers.<id>] section persists in ~/.codex/config.toml

Related Issue / 关联 Issue

Fixes #3449

Kakueeen added 2 commits June 4, 2026 20:28
… config.toml

Codex CLI requires the `[model_providers.<id>]` section to route requests
to a custom (non-reserved) provider.  Without it, Codex falls back to
`model_provider: openai` and all API calls go directly to api.openai.com.

The section can be lost when:
- Codex Desktop App rewrites config.toml, stripping unknown tables
- CC-Switch imports a pre-existing flat-format config
- A backup/restore cycle drops the section

Add a defensive normalization step (`ensure_codex_model_provider_section`)
that creates an empty `[model_providers.<id>]` table whenever
`model_provider` is set to a custom provider ID but the corresponding
table is missing.  This runs in both `write_codex_live_for_provider`
and `prepare_codex_provider_live_config`, covering all code paths that
write config.toml to disk.

Fixes farion1231#3449

Signed-off-by: Liu Zhangjian <liuzhangjian@uniontech.com>
set_implicit(true) on the synthesized table prevented toml_edit from
emitting the [model_providers.<id>] section header, causing the empty
table to be invisible to subsequent DocumentMut parsing. This made
set_codex_experimental_bearer_token fall through to the top-level
fallback instead of scoping the token inside the provider table.

Also update two test assertions to check the bearer token at its
scoped location inside [model_providers.<id>] rather than the top level.
@farion1231
Copy link
Copy Markdown
Owner

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1761570241

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src-tauri/src/codex_config.rs Outdated
…ovider table

Address AI review P2 feedback: when ensure_codex_model_provider_section()
creates a new [model_providers.<id>] table, it now copies/migrates the
legacy top-level base_url and wire_api fields into the synthesized table
and removes the top-level copies.

This ensures that configs in the flat layout (model_provider + top-level
endpoint fields) that Codex Desktop App or CC-Switch import can leave
behind are normalized so that Codex CLI finds all required routing fields
inside [model_providers.<id>].

Also fixes cargo fmt issues that caused CI to fail.

Closes farion1231#3719
@Kakueeen Kakueeen marked this pull request as ready for review June 5, 2026 01:36
@Kakueeen
Copy link
Copy Markdown
Author

Kakueeen commented Jun 5, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

Copy link
Copy Markdown
Owner

@farion1231 farion1231 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢您的贡献。请查看一下是否有以下问题:

P1:Clippy 阻塞
cargo clippy --lib -- -D warnings 失败,位置在 src-tauri/src/codex_config.rs:1136:
.map(|t| ensure_codex_model_provider_section(t)) 应改成 .map(ensure_codex_model_provider_section)。

P1/P2:可能没覆盖 #3449 的字面复现
#3449 贴出的坏配置没有 model_provider,但 PR 的 ensure_codex_model_provider_section() 在缺少 model_provider 时直接原样返回。也就是说,它只修了“有 model_provider、缺 [model_providers.] 表”的场景,可能没修“顶层 base_url/wire_api + 没有 model_provider”这个 issue 报告格式。需要作者确认真实现场格式,或补一条针对该 flat config 的 normalization。

P2:合成 provider 表时仍可能不完整
PR 会在没有任何 endpoint 字段时合成只有 experimental_bearer_token 的 [model_providers.] 表,这是对旧测试 does_not_create_incomplete_provider_table 的反转。没有 base_url 的表对 Codex 路由帮助有限。另外,如果 provider 表已存在但缺 base_url/wire_api,而顶层有旧字段,当前代码会 early-return,不会补齐缺失字段。建议只在有可迁移 endpoint 时合成,或至少回填缺失字段并明确 name / requires_openai_auth 的策略。

P1 (Clippy): Use method reference instead of closure.
P1/P2: Handle flat config without model_provider (issue farion1231#3449 format).
  When top-level base_url exists but model_provider is absent, synthesize
  model_provider = "custom" + [model_providers.custom] table with migrated
  endpoint fields.

P2: Fill incomplete existing provider tables.
  When [model_providers.<id>] exists but is missing base_url/wire_api
  while top-level copies remain, fill the gap so Codex CLI can route.

Refactored ensure_codex_model_provider_section() with clearer documentation
covering all three normalization scenarios.

Closes farion1231#3719
@farion1231
Copy link
Copy Markdown
Owner

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8d1bedd2a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1149 to +1150
for (field, _) in &fields_to_insert {
doc.remove(field);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve endpoints when provider entries are inline

When a valid TOML config represents the active provider as an inline entry, e.g. [model_providers] followed by vendor = { name = "Vendor" }, mp.contains_key(&provider_id) is true but as_table_mut() returns None. In that case the code above does not copy base_url/wire_api into the provider entry, yet these lines still remove the top-level endpoint fields, leaving the active custom provider without the base_url Codex needs for routing. Only remove the flat fields after a successful insert, or handle inline tables as provider tables.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CC-Switch 写入的 config.toml 格式不被 Codex CLI 识别,导致自定义路由配置始终不生效

2 participants