Skip to content

feat(provider): complete the custom API provider feature on dev (#68–#73) - #74

Closed
xjoker wants to merge 15 commits into
devfrom
cursor/provider-docs-5a91
Closed

feat(provider): complete the custom API provider feature on dev (#68–#73)#74
xjoker wants to merge 15 commits into
devfrom
cursor/provider-docs-5a91

Conversation

@xjoker

@xjoker xjoker commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Background (verified)

The custom API provider feature was split into a stack of PRs #67#73. After re-checking against the real dev: dev already contains #67 (provider data model + storage + CLI) and #72 (Cloud Agent environment). What is not yet in dev is #68#73 (codex_config / launch_provider / Providers tab all count 0 on dev) — those had only been merged into their in-stack parent branches.

This PR uses cursor/provider-docs-5a91, which holds the complete stack code, and, based on the real dev (ad7326c), lands the missing #68#73.

Net additions in this PR (#68#73)

Merge safety

Validation

  • cargo fmt --check and cargo clippy --all-targets --all-features -- -D warnings are green.
  • cargo test --all: 1019 passed / 0 failed, no regressions.
  • Real OpenRouter-token end-to-end (earlier sessions): a reasoning model with --reasoning, the --no-web-search + --reasoning combo, and a tool operation that actually created a file — all exited 0.

After this PR merges, #68#73 are fully in dev and the custom API provider feature is complete. The original #67#73 are already MERGED (into in-stack branches) and those branches can be deleted.

Open in Web Open in Cursor 

cursoragent and others added 15 commits August 26, 2026 01:09
First slice of custom-provider support (方案 A). Adds a provider-profile
type that lets codex-switch target a third-party OpenAI-compatible endpoint
(OpenRouter, an LLM proxy, ...) instead of a ChatGPT OAuth account.

- src/provider.rs: ProviderProfile model + private storage under
  $CODEX_SWITCH_HOME/providers/<alias>/provider.toml (dir 0700, file 0600),
  validation (reserved-id/name/base_url/env_key/model checks), key redaction,
  and env_key derived from the codex-switch alias (CODEX_SWITCH_<ALIAS>_KEY)
  so the injected key never collides with a provider's own variable.
- CLI: codex-switch provider add/list/show/remove. The API key is read from a
  hidden prompt (rpassword) or --api-key-stdin, never from argv, and is
  redacted in list/show/--json output.

Storage only; launch integration is PR-2. Nothing is written to ~/.codex yet.

Unit tests cover env_key derivation, id sanitization, validation, redaction,
0600 permissions, and save/load/list/remove round-trip. Adds rpassword.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Wire provider profiles into `codex-switch launch`. When the alias names a
provider profile, launch takes a separate path from the ChatGPT one:

- translate the profile into `codex -c model_providers.<id>.* / model_provider
  / model` overrides (layered over the user's base config, so ~/.codex and its
  MCP servers are untouched), and
- inject the API key into the Codex child process under the profile's env_key,
  never onto the command line.

No auth.json staging/backup/restore happens for providers (there is no OAuth
token), so that whole window is skipped. Auto-select (no alias) stays
ChatGPT-only. Extracted ensure_codex_available() and child_exit_code() shared
by both launch paths.

provider.rs gains codex_config_args()/launch_env()/toml_string() (pure,
unit-tested: overrides present and TOML-quoted, key absent from argv, env pair
correct, escaping). Verified end-to-end with a stub codex (args + env, key not
in argv) and real codex 0.149.1 (base MCP server still lists through a provider
launch).

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Load custom API provider profiles into the TUI and render them in a
separate "Custom providers" panel below the account table. Providers carry
no OAuth/usage, so they stay out of the account table, scoring, and refresh;
the panel lists alias / name / model / base_url and never renders the key.

Interactive add/remove of providers in the TUI is PR-4.

Adds a TestBackend render test asserting the panel lists a provider and does
not leak the API key.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Rework the custom-providers UI from a stacked panel into a top-level tab
layout (per design 方案③), isolating codex-native ChatGPT accounts from
third-party API+key providers:

- Tab bar with Accounts (N) / Providers (N); Tab / BackTab switches.
- Accounts tab: the existing account table + detail panel, unchanged.
- Providers tab: a full-height read-only table of custom providers
  (alias / name / model / base_url) with a selection highlight; the API key
  is never rendered.
- Event loop routes keys per active tab: account keys (a/r/t/i/s/space///Esc,
  and W auto-warmup) only fire on the Accounts tab; j/k move the provider
  selection on the Providers tab; q/h/Tab are global.

Interactive add/remove within the Providers tab is PR-4.

Test updated to render the Providers tab; still asserts the key never
renders.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
On the Providers tab:
- 'a' opens a multi-step add wizard (alias -> base URL -> model -> API key)
  reusing the single-line input pattern; the API-key step is masked in the
  status bar and the key is never echoed. Each step validates (alias rules +
  collision with providers/accounts, http(s) base URL, non-empty model/key);
  on completion it derives env_key/provider_id, saves via provider::save, and
  reloads.
- 'd' removes the selected provider after a y/n confirmation
  (ConfirmAction::RemoveProvider).
- Keys route per tab; the wizard consumes raw case-sensitive input. A
  tab-aware footer shows the Providers key hints.

Unit tests: wizard collects fields and saves (with hermetic CODEX_SWITCH_HOME/
CODEX_HOME), stays on-step for a bad base URL, and request+confirm removes a
provider.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Document provider add/list/show/remove, launch overlay, TUI two-tab
add/remove, OpenRouter and DeepSeek-via-gateway, and the no-argv key
contract. Wiki page plus README, command reference, architecture, and
changelog.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
…models

End-to-end testing against OpenRouter showed Codex enables its built-in
web_search server tool by default, which most third-party models reject
with HTTP 400 'Server tool request failed'. Document the top-level
web_search='disabled' config (and -c override), plus the note that some
reasoning models impose their own request requirements.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
…etting

Smoke-tested DeepSeek and Kimi (thinking + non-thinking) over OpenRouter.
web_search rejection is model-specific, not universal: deepseek-v3.2,
kimi-k2, and minimax-m3:free accept it (HTTP 200); gpt-oss-20b rejects it
(400). Thinking models (deepseek-r1, kimi-k2-thinking) need
model_reasoning_effort set or they 400 with 'Reasoning is mandatory'.
Reword from 'most models' to model-specific, and document the reasoning
effort override.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Providers can now carry extra `codex -c KEY=VALUE` overrides (`provider add
--set`, repeatable) that launch applies automatically, so model-specific
Codex settings like `web_search=disabled` or `model_reasoning_effort=medium`
no longer have to be retyped on every launch.

Overrides are stored verbatim in provider.toml and layered on top of the
model selection at launch. Codex, not codex-switch, remains the source of
truth for valid keys/values: only KEY=VALUE shape is validated, values pass
through untouched.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Co-authored-by: xJoker <xjoker@users.noreply.github.com>
`provider add --reasoning <effort>` saves model_reasoning_effort=<effort> and
`--no-web-search` saves web_search=disabled, lowering the barrier for the two
most common model-specific settings. They are shortcuts over --set: any value
passes through to Codex unchecked (the effort set is Codex's to define), and an
explicit --set for the same key still wins.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
After the model step the wizard offers a reasoning-effort single choice
(default "(skip)") and a web_search on/off toggle, both saved into the
provider's codex_config. Presets cover the common efforts; the CLI --set stays
the escape hatch for any other value.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
…steps

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Brings the whole custom-API-provider stack (#67-#73) up to date with dev
(webbrowser 1.2.4, pay-per-use credits column, etc). The only conflict was
src/tui/ui.rs: kept both dev's credits_table_* helpers and the provider
tab/panel renderers, and merged the test-module imports. Full suite: 1019 passed.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
Real dev already carries #67 (provider store) and #72 (env config). Re-merged
the true dev HEAD and resolved the add/add conflicts in provider.rs / cli.rs /
commands/provider.rs by keeping the provider-docs full-feature versions
(verified supersets of dev's #67). environment.json (#72) merged in cleanly.
This PR now cleanly adds #68-#73 (launch / TUI / docs / codex overrides) that
are not yet in dev. Full suite: 1019 passed.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
@cursor cursor Bot changed the title feat(provider): land the custom API provider stack (#67–#73) onto dev feat(provider): complete the custom API provider feature on dev (#68–#73) Aug 26, 2026
@xjoker xjoker closed this Aug 26, 2026
@cursor
cursor Bot deleted the cursor/provider-docs-5a91 branch August 26, 2026 07:04
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.

2 participants