Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased model provider gateway

- Model provider keys and connection recovery are stored separately in model-providers.vault using the existing protection identity. Preserve this file, the account vault and the original Codex sign-in.
- ProviderEditorSession retains drafts and selection in that same encrypted store. A null draft API key retains the saved credential; an explicitly empty key is invalid. Revealing/copying a loaded key must never authorize sending it to a changed destination. Preserve drafts on provider changes, failed saves and close/reopen.
- Connection/restoration edits use the official version-checked configuration RPC. Model choices route per request; never restart the owner's Codex for verification.
- The gateway runs inside Switch. Treat an active gateway as part of ongoing Codex work when planning utility updates; use an owner-approved idle handoff.
- Provider checks use disposable storage, fictional upstreams and an explicit reviewed CLI. Keep component renders, native app-server contracts, native desktop picker confirmation, real provider acceptance and public release as separate states. [Contract](docs/MODEL_PROVIDERS.md).
Expand Down
20 changes: 13 additions & 7 deletions docs/MODEL_PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ Keep eligible OpenAI models and custom Responses models in the existing Codex mo
## Set up a provider

1. In1.44.0, open Model providers in the titlebar Settings gear. Older1.43.3 Windows packages use Models in the toolbar.
2. Select Add a provider, enter a display name, API base URL and API key, then choose Discover and save.
3. If the provider has a large catalog, enter the model IDs to include, one per line. Leave this field empty to discover all models within the supported bounds.
4. Choose Connect Codex, then use Restart Codex in Settings when ready (on the main window in older1.43.3). Connecting prepares settings; the separate restart action normally closes and reopens Codex and resumes eligible unfinished chats with the same login.
5. Keep Switch running, including in its tray. Choose OpenAI or a custom model inside each Codex chat. Model-list refresh can take a few minutes after registering models.
2. In the first step, select Add a provider or a saved provider, then enter its display name, API base URL and API key. Choose Save and continue to discover and save its models.
3. For a large catalog, expand the optional model-ID field and enter one ID per line. Leave it empty to discover all models within the supported bounds. Reasoning and conversation-handoff controls stay under Advanced in the second step.
4. In the second step, choose Connect Codex, then Restart Codex when ready. Saving alone does not connect or restart Codex. The restart button uses the existing normal restart and chat-recovery flow with the same login.
5. Keep Switch running, including in its tray. Choose OpenAI or a custom model inside each Codex chat. New connections use an explicit local model catalog; after changing its models or reasoning settings, restart Codex when ready to load the updated catalog.

Select an existing provider to edit it. An empty key field retains its saved key; changing the destination URL requires a replacement key. Keys remain masked in the editor and encrypted in the separate local model-providers.vault file. The account vault and original OpenAI login are preserved.
Saved providers reopen with their fields and a masked key. The eye button shows or hides the current key, and Copy copies it only after an explicit click. Neither action changes the key. Changing the destination URL still requires an explicitly entered replacement key; displaying a saved key does not authorize sending it elsewhere.

Draft fields and the last selected provider are encrypted in the existing model-providers.vault when changing providers, attempting a save or closing the editor. A failed save retains the input. More options offers Load saved values, Use these values for a new provider, provider removal and connection restoration. Loading saved values is the explicit way to discard an edit. The account vault and original OpenAI login are preserved.

Restart Codex keeps the current account and original chat names. It uses the existing durable recovery and uncertain-Continue suppression. Running work and active unfinished goals are captured; completed or already-running work is checked before another Continue is sent. Existing credit-protection settings still apply. The action stays disabled while another login/restart/handoff is in progress.

Expand All @@ -38,10 +40,12 @@ Switch supports at most32 providers and128 selected models per provider. Discove

JSON validation reads tokens without a payload-sized document metadata pool. It refuses duplicate properties, nesting above64levels, more than one million tokens, property names over1KiB or total property-name bytes over8MiB. Routing controls (`reasoning` and `text`) are each limited to64KiB. These bounds apply before upstream inference and do not remove conversation items. Unchanged OpenAI requests retain exact body bytes; custom-provider rewrites serialize only small controls and stream original history/image value slices. The buffer budget covers request arrays, not all process/runtime/HTTP allocations.

Changing providers sends the replayed conversation to the selected provider. Provider-encrypted reasoning is omitted after a conversation crosses routes. An existing provider-encrypted compaction cannot be reconstructed by another provider: that request fails explicitly and requires a portable text summary. Stateful response references are refused rather than silently dropping history. New gateway sessions are configured for local compaction.
Changing providers sends the replayed conversation to the selected provider. Provider-encrypted reasoning is omitted after a conversation crosses routes. An existing provider-encrypted compaction cannot be reconstructed by another provider: that request fails explicitly and requires a portable text summary. Stateful response references are refused rather than silently dropping history. Compaction remains tied to its original provider.

The connection uses existing file-backed OpenAI authentication. The local listener accepts authenticated requests on127.0.0.1 only, refuses browser-origin requests, and never forwards an OpenAI credential or account header to a custom provider. A custom provider receives only its saved key. Redirects are not followed. The only automatic inference retry is the explicit HTTP507 recovery described below.

For Codex requests carrying the native turn identity, the gateway retains a hashed receipt for each distinct input and route for30minutes. Automatic client retries of that same turn request are refused before another upstream send; a new user turn or changed full-input tool follow-up remains eligible. The receipt budget is4096 and a full budget reports503. Receipts contain no request body or credentials and last only for the current gateway process. This prevents the built-in client's retry policy from multiplying the gateway's own recovery budget.

### Automatic HTTP507 recovery

For streaming `POST /responses`, an upstream HTTP507 refusal before its response begins is retried at most three times, after2,5and10seconds. The original attempt plus retries makes at most four upstream requests. All attempts retain the original selected model, provider URL/key, signed-in account, complete input bytes/history and tool-call identities. The current sign-in is revalidated before another attempt. There is no new chat, `Continue` message, model/account change, history trimming or context compression.
Expand All @@ -68,7 +72,9 @@ The large-upload admission slot and request buffers are released when final upst

Unregistered model names fail explicitly. OpenAI routes are checked against the current sign-in's catalog, while custom routes use their registered aliases. Managed provider/catalog requirements are refused before preparing a local connection.

The initial configuration selects the codex_switch_router provider with an explicit catalog URL, and also sets the built-in OpenAI base URL to the same listener for pre-existing OpenAI-provider chats. WebSockets and request compression are disabled for portable full-input HTTP replay. Unrelated custom provider definitions are preserved; already-pinned chats using those independent definitions are outside the verified migration scope.
New connections preserve the existing built-in `openai` provider identity and set `openai_base_url` to the loopback listener. An explicit private `model_catalog_json` file supplies the combined native and custom model list to Codex and its desktop picker. The catalog contains model metadata, not API keys. It is refreshed on provider edits, account changes and the existing refresh cycle; Codex loads the file at startup. WebSockets and request compression are disabled for portable full-input HTTP replay. Existing provider definitions are preserved.

Older connections that use `codex_switch_router` remain untouched. Recent Codex versions reject a chat when its saved provider identity differs from the current provider, even if both use the same gateway. Restoring/reconnecting an older installation can therefore affect which provider-pinned chats it can reopen. Switch does not rewrite chat history or bypass that check. Keep the older connection for its existing router-pinned chats; new built-in OpenAI connections retain compatibility with original OpenAI chats.

Workspace-enforced routing, keyring-only authentication, API-key-only dashboard startup, external production provider compatibility, and the actual desktop picker still require their own acceptance evidence. Do not bypass managed policy or replace the owner's running client to verify them.

Expand Down
4 changes: 4 additions & 0 deletions docs/development/PLAN.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Current plan

Custom-provider setup now keeps connection state visible after every editor action and preserves the original OpenAI provider identity. New connections supply an explicit private combined model catalog. Native visible-model discovery, same-chat provider selection, catalog refresh/restoration and bounded retry receipts are verified with disposable inputs. Require final-head repository/native CI before promotion; owner restarts, actual desktop picker confirmation and binary releases remain separate actions.

The two-step onboarding follow-up preserves encrypted drafts, selected provider and saved keys through errors and reopening. Explicit eye/copy/reuse/load and user-requested restart actions are implemented. Provider, account/recovery, language and narrow Windows-component checks pass alongside both desktop builds. Complete final-head CI and review before promotion; owner installation and binary release remain separate.

Extend recovery beyond the pre-response507case to confirmed failed turns of every error type. Preserve original tools/context by continuing the saved chat once through its desktop owner, with three persisted attempts across a failure chain. Verify all-error eligibility, message-less failures, actual interruption exclusion, latest-turn/queue/identity/model/provider checks, no duplicate after IPC ambiguity, restart/exhaustion, bounded decision diagnostics, real rollout/SQLite path handling and actual Codex failed-turn followed by same-chat completion. Existing observed active/completed work is left alone.

Bounded HTTP507recovery to streaming Responses passes231local provider/official-CLI checks: original plus at most three requests after2/5/10seconds, retained native/custom body/route identity, early success, terminal exhaustion, cancellation/disconnect, changed sign-in and shutdown. Images/compaction and ambiguous transport/partial-stream failures remain single-send. Preserve the existing input buffer budget, and verify local installation separately from source integration or a new public release. [Recovery contract](../MODEL_PROVIDERS.md#automatic-http507-recovery).
Expand Down
2 changes: 2 additions & 0 deletions docs/development/STATUS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Current status

Provider setup and onboarding pass255gateway/current-native-CLI checks,350account/recovery checks,116offscreen WPF checks and42language API checks. The two-step editor retains encrypted drafts and selection through failed saves, provider changes and close/reopen. Saved keys remain masked, with explicit eye/copy/reuse/load actions; a displayed key never authorizes a changed destination. New connections retain OpenAI identity and use a private combined catalog, with bounded native-request receipts. Windows/shared desktop builds and all9language catalogs pass. Existing accounts, router-pinned chats and owner installations remain unchanged; actual Codex picker interaction and a binary release are separate.

Unreleased: the chat date button independently updates active root chat titles with the existing KST prefix and verified metadata path. It does not switch accounts or restart Codex. Errors stop the operation and report the number already verified. Native UI screenshots and real-user acceptance remain pending.
The all-error recovery follow-up passes346account/recovery contracts,234provider/official-CLI checks and99Windows package self-tests on runtime10.0.13. Failed terminal status now controls eligibility across HTTP, stream, authentication, quota, context and compaction errors, including absent error prose. First-request failures no longer need an earlier successful-route receipt; current owner/settings/authentication and gateway history checks remain enforced. Bounded hashed decision diagnostics distinguish continuation, exhaustion and guard exclusions. Source checks and Windows/shared builds are verified. A local installed package also confirmed an identified automatic continuation followed by an active error-free turn and completed tool work; this does not establish completion of the continued project or public release availability.

Expand Down
13 changes: 13 additions & 0 deletions docs/evidence/provider-connection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Provider connection state

These images are production WPF components rendered offscreen with fictional provider metadata and disposable encrypted storage. The two-step flow loads saved fields, keeps keys masked, retains failed edits, and advances to Connect only after saving. Eye, copy, explicit reload/reuse and close/reopen are checked through the editor's normal controls and persistence paths. These are not native Codex picker or real-provider acceptance images.

![English provider details](providers-en-dark.png)

![Korean provider details](providers-ko-dark.png)

![English saved provider connection state](saved-connection-en-dark.png)

![Korean saved provider connection state](saved-connection-ko-dark.png)

The current native Codex app-server separately verifies visible custom models, unchanged OpenAI provider identity, per-chat routing, catalog refresh, restoration and bounded upstream retries against fictional endpoints. See [the contract](../../MODEL_PROVIDERS.md).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 17 additions & 3 deletions localization/packs/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"msg.linux_account_file_policy": "Dieser Codex-Kontext erlaubt keine ChatGPT-Anmeldedaten in Dateien. Die Konfiguration wurde nicht geändert.",
"msg.linux_account_workspace_policy": "Das ausgewählte Konto entspricht nicht dem für diesen Codex-Kontext erforderlichen Arbeitsbereich.",
"msg.linux_account_async_policy": "Kontovorgänge unter Linux erfordern eine erneute asynchrone Prüfung der Client-Richtlinie.",
"providers.model_count": "{0} models discovered",
"providers.model_count": "Saved models: {0}",
"providers.incomplete": "The connection update was not confirmed. Restore the previous connection before trying again.",
"providers.details": "Compatibility and conversation sharing",
"providers.restored": "Previous connection settings restored. Restart Codex once when ready.",
Expand All @@ -471,7 +471,7 @@
"providers.name": "Anzeigename",
"providers.url": "API-Basis-URL",
"providers.key": "API-Schlüssel",
"providers.key_hint": "Leave blank to retain the saved key. Enter a new key when changing the URL. Keys are encrypted locally.",
"providers.key_hint": "Stored encrypted. Reveal or copy only when needed.",
"providers.save": "Modelle abrufen und speichern",
"providers.remove": "Anbieter entfernen",
"providers.models": "Abgerufene Modelle",
Expand All @@ -487,7 +487,21 @@
"providers.history_hint": "Changing providers sends the replayed conversation to the selected provider. Opaque encrypted reasoning is excluded. Stateful response references are refused. Existing OpenAI-provider chats retain their IDs.",
"providers.prepared": "Connection settings prepared. Restart Codex once when ready.",
"providers.not_connected": "Codex is not connected to the local gateway.",
"providers.saved": "Provider settings saved. New requests use the saved route; model-list refresh may take a few minutes.",
"providers.saved": "Provider settings saved.",
"providers.step_details": "1. Connection details",
"providers.step_connect": "2. Connect to Codex",
"providers.save_next": "Save and continue",
"providers.edit": "Edit details",
"providers.close": "Close",
"providers.reuse": "Use these values for a new provider",
"providers.reset": "Load saved values",
"providers.key_show": "Show API key",
"providers.key_hide": "Hide API key",
"providers.key_copy": "Copy API key",
"providers.key_copied": "API key copied.",
"providers.copy_failed": "Could not copy.",
"providers.more": "More options",
"providers.advanced": "Advanced",
"providers.working": "Working…",
"providers.cancelled": "Cancelled or timed out.",
"providers.failed": "Provider operation failed.",
Expand Down
20 changes: 17 additions & 3 deletions localization/packs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"msg.linux_account_file_policy": "This Codex context does not allow ChatGPT file credentials. Its configuration has not been changed.",
"msg.linux_account_workspace_policy": "The selected account does not match this Codex context's required workspace.",
"msg.linux_account_async_policy": "Linux account operations require a fresh asynchronous client policy check.",
"providers.model_count": "{0} models discovered",
"providers.model_count": "Saved models: {0}",
"providers.incomplete": "The connection update was not confirmed. Restore the previous connection before trying again.",
"providers.details": "Compatibility and conversation sharing",
"providers.restored": "Previous connection settings restored. Restart Codex once when ready.",
Expand All @@ -471,7 +471,7 @@
"providers.name": "Display name",
"providers.url": "API base URL",
"providers.key": "API key",
"providers.key_hint": "Leave blank to retain the saved key. Enter a new key when changing the URL. Keys are encrypted locally.",
"providers.key_hint": "Stored encrypted. Reveal or copy only when needed.",
"providers.save": "Discover and save",
"providers.remove": "Remove provider",
"providers.models": "Discovered models",
Expand All @@ -487,7 +487,21 @@
"providers.history_hint": "Changing providers sends the replayed conversation to the selected provider. Opaque encrypted reasoning is excluded. Stateful response references are refused. Existing OpenAI-provider chats retain their IDs.",
"providers.prepared": "Connection settings prepared. Restart Codex once when ready.",
"providers.not_connected": "Codex is not connected to the local gateway.",
"providers.saved": "Provider settings saved. New requests use the saved route; model-list refresh may take a few minutes.",
"providers.saved": "Provider settings saved.",
"providers.step_details": "1. Connection details",
"providers.step_connect": "2. Connect to Codex",
"providers.save_next": "Save and continue",
"providers.edit": "Edit details",
"providers.close": "Close",
"providers.reuse": "Use these values for a new provider",
"providers.reset": "Load saved values",
"providers.key_show": "Show API key",
"providers.key_hide": "Hide API key",
"providers.key_copy": "Copy API key",
"providers.key_copied": "API key copied.",
"providers.copy_failed": "Could not copy.",
"providers.more": "More options",
"providers.advanced": "Advanced",
"providers.working": "Working…",
"providers.cancelled": "Cancelled or timed out.",
"providers.failed": "Provider operation failed.",
Expand Down
Loading
Loading