Repository navigation
Codex Desktop needs a supported recovery path when a thread's persisted model provider is unavailable #40314
Description
What variant of Codex are you using?
Codex Desktop and app-server (observed with app-server 0.147/0.148 behavior).
What feature would you like to see?
Codex Desktop should provide a supported way to continue an existing local thread when the thread's persisted model_provider is no longer present in the current configuration.
A common lifecycle is:
- A user starts with the built-in
openaiprovider or another existing provider. - A local provider manager temporarily installs an OpenAI-compatible proxy as
[model_providers.proxy]and setsmodel_provider = "proxy". - Threads are created or resumed through that proxy.
- The manager later restores the user's original
config.tomlexactly. Theproxydefinition is therefore no longer present. - The local thread remains intact in the rollout JSONL and
state_5.sqlite. - Even if Desktop lists all providers (
thread/listwithmodelProviders: []), selecting the thread cannot recover it: Desktop callsthread/resumewith the thread's persistedmodelProvider(proxy), which is no longer configured.
This is distinct from history discovery. Fixing thread/list visibility alone makes the thread visible but still not usable.
Please provide an official recovery path, for example one of:
- Desktop detects that the persisted provider is unavailable and offers Open with current provider, with an explicit compatibility warning.
thread/resumeaccepts a provider override that can optionally be persisted as the thread's latest effective provider.- A dedicated API such as
thread/provider/updateatomically updates the canonical rollout metadata and SQLite projection.
The important requirements are:
- Preserve the same thread ID and history.
- Do not fork the thread into two independently progressing copies.
- Do not require users or provider managers to rewrite rollout JSONL and SQLite directly.
- Keep the default safe for encrypted or provider-specific history: migration should be explicit and may be rejected when compatibility cannot be established.
Additional information
Current behavior and constraints observed in source:
thread/listcan enumerate all providers withmodelProviders: [].thread/resumealready has an optionalmodelProviderparameter, so an external client that knows the thread ID can resume the same ID through a compatible current provider.- Desktop selects the persisted
thread.modelProvider, so a normal sidebar click cannot use that recovery path. thread/metadata/updatedoes not expose model-provider changes.thread/forksupports a target provider, but creates a second thread ID and produces two potentially divergent conversations.- Editing only
state_5.sqliteis not safe because rollout JSONL remains the durable source and can rebuild the projection.
Related but distinct issues:
- (app-server and Desktop) thread/list treats omitted modelProviders as current-provider filter instead of all providers #24648 covers cross-provider history visibility /
thread/listfiltering. - Codex Desktop should preserve local history visibility and continuation across providers/accounts #20004 requests broader provider/account-aware visibility and continuation.
This request is specifically for the case where a thread is known and visible, but its persisted provider definition is unavailable and Desktop has no supported same-thread recovery action.
Activity
github-actions commentedon Aug 24, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
OriyukiAkari commentedon Sep 4, 2026
I tested a related core-side piece of the recovery path described here while investigating #17541.
Tested implementation:
OriyukiAkari@926c1d1
In particular, I verified that the existing
thread/resumemodelProvideroverride can continue the same thread ID through a different configured provider, but provider-bound encrypted Reasoning/Compaction history cannot safely be replayed verbatim to that replacement runtime.The implementation keeps the rollout JSONL and SQLite projection untouched. Instead, it:
TurnContextItemso it survives app-server restartSessionMeta.model_providerfor legacy histories where no previous real turn survives reconstructionI tested this using an existing Desktop/app-server thread with persisted provider
openai, then explicitly resumed the same thread ID with effective providercustom.Before the change, continuation failed because encrypted history from the previous runtime was sent to the replacement provider.
After the change, the same thread ID successfully completed:
No rollout JSONL or SQLite rewriting was required, and the original encrypted history remained persisted rather than being destructively removed.
This does not implement the Desktop UX requested by this issue: Desktop still needs a supported action such as "Open with current provider" when the persisted provider is unavailable. The implementation is only a tested core safety mechanism for what happens after such an explicit provider override is chosen.
I posted the fuller root-cause and validation details in #17541.