feat(codex): add unified session history toggle for official providers

Codex buckets resume history by the model_provider id recorded in each
session: official runs (no key, built-in "openai") and cc-switch
third-party runs (shared "custom") are mutually invisible in the resume
picker. Add an opt-in setting that runs official providers under the
shared "custom" id so future official sessions land in the same history
bucket as third-party ones. Forward-only by design: existing sessions
are not migrated.

When enabled, official live config.toml gets model_provider = "custom"
plus a [model_providers.custom] entry that mirrors the built-in openai
provider (requires_openai_auth routes auth to the ChatGPT login in
auth.json, name "OpenAI" keeps is_openai() feature gates, explicit
supports_websockets/wire_api restore built-in defaults). auth.json is
untouched.

Key invariants:
- Injection lives only in the live config: switch-away backfill strips
  the exact injected shape, so stored provider configs stay clean and
  turning the toggle off fully reverts on the next write.
- Toggle changes apply immediately via a takeover-aware reapply: when
  the proxy owns the live config (backup/placeholder present), only the
  live backup is updated, mirroring the provider-switch path.
- The takeover backup path runs the same injection so a takeover
  release restores a config that still carries the unified routing.
- Injection refuses to activate a foreign [model_providers.custom]
  table (e.g. stale entry with a third-party base_url) to avoid routing
  ChatGPT OAuth traffic to an unknown backend.

The toggle lives under Settings → Codex App Enhancements; the
description warns that resuming old sessions across providers may fail
because encrypted_content reasoning only decrypts on the backend that
created it (upstream treats cross-provider resume as unsupported).
This commit is contained in:
Jason
2026-06-12 10:40:51 +08:00
parent 4f355970e1
commit 948d762792
14 changed files with 406 additions and 2 deletions
+3
View File
@@ -118,6 +118,7 @@ export function useSettingsForm(): UseSettingsFormResult {
skipClaudeOnboarding: data.skipClaudeOnboarding ?? false,
preserveCodexOfficialAuthOnSwitch:
data.preserveCodexOfficialAuthOnSwitch ?? false,
unifyCodexSessionHistory: data.unifyCodexSessionHistory ?? false,
claudeConfigDir: sanitizeDir(data.claudeConfigDir),
codexConfigDir: sanitizeDir(data.codexConfigDir),
geminiConfigDir: sanitizeDir(data.geminiConfigDir),
@@ -143,6 +144,7 @@ export function useSettingsForm(): UseSettingsFormResult {
enableClaudePluginIntegration: false,
skipClaudeOnboarding: false,
preserveCodexOfficialAuthOnSwitch: false,
unifyCodexSessionHistory: false,
language: readPersistedLanguage(),
} as SettingsFormState);
@@ -182,6 +184,7 @@ export function useSettingsForm(): UseSettingsFormResult {
skipClaudeOnboarding: serverData.skipClaudeOnboarding ?? false,
preserveCodexOfficialAuthOnSwitch:
serverData.preserveCodexOfficialAuthOnSwitch ?? false,
unifyCodexSessionHistory: serverData.unifyCodexSessionHistory ?? false,
claudeConfigDir: sanitizeDir(serverData.claudeConfigDir),
codexConfigDir: sanitizeDir(serverData.codexConfigDir),
geminiConfigDir: sanitizeDir(serverData.geminiConfigDir),