diff --git a/frontend/src/components/keys/UseKeyModal.vue b/frontend/src/components/keys/UseKeyModal.vue index 18440c60111..3077f2ed7e3 100644 --- a/frontend/src/components/keys/UseKeyModal.vue +++ b/frontend/src/components/keys/UseKeyModal.vue @@ -418,9 +418,9 @@ const currentFiles = computed((): FileConfig[] => { return generateAnthropicFiles(baseUrl, apiKey) } if (activeClientTab.value === 'codex-ws') { - return generateOpenAIWsFiles(baseUrl, apiKey) + return generateOpenAIWsFiles(apiBase, apiKey) } - return generateOpenAIFiles(baseUrl, apiKey) + return generateOpenAIFiles(apiBase, apiKey) case 'gemini': return [generateGeminiCliContent(baseUrl, apiKey)] case 'antigravity': @@ -528,39 +528,40 @@ ${keyword('$env:')}${variable('GEMINI_MODEL')}${operator('=')}${string(`"${model function generateOpenAIFiles(baseUrl: string, apiKey: string): FileConfig[] { const isWindows = activeTab.value === 'windows' const configDir = isWindows ? '%userprofile%\\.codex' : '~/.codex' + const configPath = isWindows ? `${configDir}\\config.toml` : `${configDir}/config.toml` + const envCommand = isWindows + ? `setx OPENAI_API_KEY "${apiKey}"` + : `export OPENAI_API_KEY="${apiKey}"` + const envPath = isWindows ? 'Command Prompt / PowerShell' : 'Terminal' // config.toml content - const configContent = `model_provider = "OpenAI" + const configContent = `preferred_auth_method = "apikey" model = "gpt-5.5" review_model = "gpt-5.5" +model_provider = "proxy" model_reasoning_effort = "xhigh" disable_response_storage = true network_access = "enabled" windows_wsl_setup_acknowledged = true -[model_providers.OpenAI] -name = "OpenAI" +[model_providers.proxy] +name = "OpenAi" base_url = "${baseUrl}" +env_key = "OPENAI_API_KEY" wire_api = "responses" -requires_openai_auth = true [features] goals = true` - // auth.json content - const authContent = `{ - "OPENAI_API_KEY": "${apiKey}" -}` - return [ { - path: `${configDir}/config.toml`, + path: configPath, content: configContent, hint: t('keys.useKeyModal.openai.configTomlHint') }, { - path: `${configDir}/auth.json`, - content: authContent + path: envPath, + content: envCommand } ] } @@ -568,41 +569,42 @@ goals = true` function generateOpenAIWsFiles(baseUrl: string, apiKey: string): FileConfig[] { const isWindows = activeTab.value === 'windows' const configDir = isWindows ? '%userprofile%\\.codex' : '~/.codex' + const configPath = isWindows ? `${configDir}\\config.toml` : `${configDir}/config.toml` + const envCommand = isWindows + ? `setx OPENAI_API_KEY "${apiKey}"` + : `export OPENAI_API_KEY="${apiKey}"` + const envPath = isWindows ? 'Command Prompt / PowerShell' : 'Terminal' // config.toml content with WebSocket v2 - const configContent = `model_provider = "OpenAI" + const configContent = `preferred_auth_method = "apikey" model = "gpt-5.5" review_model = "gpt-5.5" +model_provider = "proxy" model_reasoning_effort = "xhigh" disable_response_storage = true network_access = "enabled" windows_wsl_setup_acknowledged = true -[model_providers.OpenAI] -name = "OpenAI" +[model_providers.proxy] +name = "OpenAi" base_url = "${baseUrl}" +env_key = "OPENAI_API_KEY" wire_api = "responses" supports_websockets = true -requires_openai_auth = true [features] responses_websockets_v2 = true goals = true` - // auth.json content - const authContent = `{ - "OPENAI_API_KEY": "${apiKey}" -}` - return [ { - path: `${configDir}/config.toml`, + path: configPath, content: configContent, hint: t('keys.useKeyModal.openai.configTomlHint') }, { - path: `${configDir}/auth.json`, - content: authContent + path: envPath, + content: envCommand } ] } diff --git a/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts b/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts index b3fdeb937ab..cc5ca4dac16 100644 --- a/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts +++ b/frontend/src/components/keys/__tests__/UseKeyModal.spec.ts @@ -38,23 +38,57 @@ describe('UseKeyModal', () => { }) const codeBlocks = wrapper.findAll('pre code').map((code) => code.text()) - const configToml = codeBlocks.find((content) => content.includes('model_provider = "OpenAI"')) + const configToml = codeBlocks.find((content) => content.includes('model_provider = "proxy"')) expect(configToml).toBeDefined() + expect(configToml).toContain('preferred_auth_method = "apikey"') expect(configToml).toContain('model = "gpt-5.5"') expect(configToml).toContain('review_model = "gpt-5.5"') + expect(configToml).toContain('[model_providers.proxy]') + expect(configToml).toContain('base_url = "https://example.com/v1"') + expect(configToml).toContain('env_key = "OPENAI_API_KEY"') expect(configToml).not.toContain('model = "gpt-5.4"') expect(configToml).not.toContain('model_context_window') expect(configToml).not.toContain('model_auto_compact_token_limit') + expect(configToml).not.toContain('requires_openai_auth') expect(configToml).toContain('[features]\ngoals = true') + + const envCommand = codeBlocks.find((content) => content.startsWith('export OPENAI_API_KEY')) + expect(envCommand).toBe('export OPENAI_API_KEY="sk-test"') }) - it('renders GPT-5.5 and goals feature in OpenAI Codex WebSocket config', async () => { + it('normalizes root URLs in OpenAI Codex config', () => { const wrapper = mount(UseKeyModal, { props: { show: true, apiKey: 'sk-test', - baseUrl: 'https://example.com/v1', + baseUrl: 'https://example.com', + platform: 'openai' + }, + global: { + stubs: { + BaseDialog: { + template: '