From f652d0ed387b01b869959c7e7d9b27abdffca5e8 Mon Sep 17 00:00:00 2001 From: Sterbennicht <118495910+Sterbennicht@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:50:55 +0800 Subject: [PATCH] fix(keys): use ~/ for the Codex model catalog path on Windows Codex expands a leading ~/ in config.toml paths on every platform but does not expand %userprofile%. The Windows config generated by the Use Key dialog wrote model_catalog_json = "%userprofile%\.codex\codex-models.json", which Codex resolves relative to the config directory (C:\Users\\.codex\%userprofile%\.codex\codex-models.json), so it fails to load the config with "The system cannot find the path specified (os error 3)". Always write ~/.codex/codex-models.json into config.toml. The download hint still shows the Windows location to save the file. --- frontend/src/components/keys/UseKeyModal.vue | 12 ++++++++---- .../components/keys/__tests__/UseKeyModal.spec.ts | 8 +++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/keys/UseKeyModal.vue b/frontend/src/components/keys/UseKeyModal.vue index d008fddbbd..242817d1cc 100644 --- a/frontend/src/components/keys/UseKeyModal.vue +++ b/frontend/src/components/keys/UseKeyModal.vue @@ -325,6 +325,10 @@ const codexModelCatalogPath = computed(() => { return joinConfigPath(configDir, 'codex-models.json', isWindows) }) +// Codex expands a leading ~/ on every platform but not %userprofile%, which it +// resolves relative to the config directory, so config.toml always uses ~/. +const CODEX_MODEL_CATALOG_CONFIG_PATH = '~/.codex/codex-models.json' + const codexManifestContext = computed(() => { if (!showCodexModelCatalog.value) return '' return `${props.platform}|${props.baseUrl}|${props.apiKey}` @@ -952,7 +956,7 @@ function generateOpenAIFiles(baseUrl: string, apiKey: string): FileConfig[] { model = "${model}" review_model = "${model}" ${reasoningEffortLine}disable_response_storage = true -model_catalog_json = "${escapeTomlBasicString(codexModelCatalogPath.value)}" +model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}" network_access = "enabled" windows_wsl_setup_acknowledged = true @@ -1185,7 +1189,7 @@ function generateGrokCodexFiles(baseUrl: string, apiKey: string): FileConfig[] { model_provider = "sub2api" model = "${model}" -model_catalog_json = "${escapeTomlBasicString(codexModelCatalogPath.value)}" +model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}" # Optional: # review_model = "${model}" # model_reasoning_effort = "medium" @@ -1266,7 +1270,7 @@ model_provider = "sub2api" model = "${model}" review_model = "${model}" disable_response_storage = true -model_catalog_json = "${escapeTomlBasicString(codexModelCatalogPath.value)}" +model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}" [model_providers.sub2api] name = "Sub2API ${label}" @@ -1301,7 +1305,7 @@ function generateOpenAIWsFiles(baseUrl: string, apiKey: string): FileConfig[] { model = "${model}" review_model = "${model}" ${reasoningEffortLine}disable_response_storage = true -model_catalog_json = "${escapeTomlBasicString(codexModelCatalogPath.value)}" +model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}" network_access = "enabled" windows_wsl_setup_acknowledged = true diff --git a/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts b/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts index efc32a0f57..7d2a939ed1 100644 --- a/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts +++ b/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts @@ -848,9 +848,11 @@ describe('UseKeyModal', () => { const windowsConfig = wrapper.findAll('pre code') .map((code) => code.text()) .find((content) => content.includes('[model_providers.sub2api]')) - expect(windowsConfig).toContain( - 'model_catalog_json = "%userprofile%\\\\.codex\\\\codex-models.json"' - ) + // Codex does not expand %userprofile% in config.toml; it only expands ~/. + expect(windowsConfig).toContain('model_catalog_json = "~/.codex/codex-models.json"') + expect(windowsConfig).not.toContain('%userprofile%') + expect(wrapper.get('[data-testid="codex-model-catalog"]').text()) + .toContain('%userprofile%\\.codex\\codex-models.json') }) it.each(['anthropic', 'gemini', 'antigravity', 'kimi', 'zhipu', 'minimax'] as const)(