diff --git a/README.md b/README.md index 8804ec30..a5f680bf 100644 --- a/README.md +++ b/README.md @@ -57,34 +57,6 @@ Sub2API is an AI API gateway platform designed to distribute and manage API quot --- -## Codex CLI WebSocket v2 Example - -To enable OpenAI WebSocket Mode v2 in Codex CLI with Sub2API, add the following to `~/.codex/config.toml`: - -```toml -model_provider = "aicodx2api" -model = "gpt-5.3-codex" -review_model = "gpt-5.3-codex" -model_reasoning_effort = "xhigh" -disable_response_storage = true -network_access = "enabled" -windows_wsl_setup_acknowledged = true - -[model_providers.aicodx2api] -name = "aicodx2api" -base_url = "https://api.sub2api.ai" -wire_api = "responses" -supports_websockets = true -requires_openai_auth = true - -[features] -responses_websockets_v2 = true -``` - -After updating the config, restart Codex CLI. - ---- - ## Deployment ### Method 1: Script Installation (Recommended) diff --git a/README_CN.md b/README_CN.md index 22a772b5..9da089b7 100644 --- a/README_CN.md +++ b/README_CN.md @@ -62,34 +62,6 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅( - 当请求包含 `function_call_output` 时,需要携带 `previous_response_id`,或在 `input` 中包含带 `call_id` 的 `tool_call`/`function_call`,或带非空 `id` 且与 `function_call_output.call_id` 匹配的 `item_reference`。 - 若依赖上游历史记录,网关会强制 `store=true` 并需要复用 `previous_response_id`,以避免出现 “No tool call found for function call output” 错误。 -## Codex CLI 开启 OpenAI WebSocket Mode v2 示例配置 - -如需在 Codex CLI 中通过 Sub2API 启用 OpenAI WebSocket Mode v2,可将以下配置写入 `~/.codex/config.toml`: - -```toml -model_provider = "aicodx2api" -model = "gpt-5.3-codex" -review_model = "gpt-5.3-codex" -model_reasoning_effort = "xhigh" -disable_response_storage = true -network_access = "enabled" -windows_wsl_setup_acknowledged = true - -[model_providers.aicodx2api] -name = "aicodx2api" -base_url = "https://api.sub2api.ai" -wire_api = "responses" -supports_websockets = true -requires_openai_auth = true - -[features] -responses_websockets_v2 = true -``` - -配置更新后,重启 Codex CLI 使其生效。 - ---- - ## 部署方式 ### 方式一:脚本安装(推荐) diff --git a/frontend/src/components/keys/UseKeyModal.vue b/frontend/src/components/keys/UseKeyModal.vue index 4f606410..4dd7ff0c 100644 --- a/frontend/src/components/keys/UseKeyModal.vue +++ b/frontend/src/components/keys/UseKeyModal.vue @@ -268,6 +268,7 @@ const clientTabs = computed((): TabConfig[] => { case 'openai': return [ { id: 'codex', label: t('keys.useKeyModal.cliTabs.codexCli'), icon: TerminalIcon }, + { id: 'codex-ws', label: t('keys.useKeyModal.cliTabs.codexCliWs'), icon: TerminalIcon }, { id: 'opencode', label: t('keys.useKeyModal.cliTabs.opencode'), icon: TerminalIcon } ] case 'gemini': @@ -306,7 +307,7 @@ const showShellTabs = computed(() => activeClientTab.value !== 'opencode') const currentTabs = computed(() => { if (!showShellTabs.value) return [] - if (props.platform === 'openai') { + if (activeClientTab.value === 'codex' || activeClientTab.value === 'codex-ws') { return openaiTabs } return shellTabs @@ -401,6 +402,9 @@ const currentFiles = computed((): FileConfig[] => { switch (props.platform) { case 'openai': + if (activeClientTab.value === 'codex-ws') { + return generateOpenAIWsFiles(baseUrl, apiKey) + } return generateOpenAIFiles(baseUrl, apiKey) case 'gemini': return [generateGeminiCliContent(baseUrl, apiKey)] @@ -524,6 +528,47 @@ requires_openai_auth = true` ] } +function generateOpenAIWsFiles(baseUrl: string, apiKey: string): FileConfig[] { + const isWindows = activeTab.value === 'windows' + const configDir = isWindows ? '%userprofile%\\.codex' : '~/.codex' + + // config.toml content with WebSocket v2 + const configContent = `model_provider = "sub2api" +model = "gpt-5.3-codex" +model_reasoning_effort = "high" +network_access = "enabled" +disable_response_storage = true +windows_wsl_setup_acknowledged = true +model_verbosity = "high" + +[model_providers.sub2api] +name = "sub2api" +base_url = "${baseUrl}" +wire_api = "responses" +supports_websockets = true +requires_openai_auth = true + +[features] +responses_websockets_v2 = true` + + // auth.json content + const authContent = `{ + "OPENAI_API_KEY": "${apiKey}" +}` + + return [ + { + path: `${configDir}/config.toml`, + content: configContent, + hint: t('keys.useKeyModal.openai.configTomlHint') + }, + { + path: `${configDir}/auth.json`, + content: authContent + } + ] +} + function generateOpenCodeConfig(platform: string, baseUrl: string, apiKey: string, pathLabel?: string): FileConfig { const provider: Record = { [platform]: { diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 2c8748cf..50dce51b 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -501,6 +501,7 @@ export default { claudeCode: 'Claude Code', geminiCli: 'Gemini CLI', codexCli: 'Codex CLI', + codexCliWs: 'Codex CLI (WebSocket)', opencode: 'OpenCode', }, antigravity: { diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 2aa8580e..56055a53 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -503,6 +503,7 @@ export default { claudeCode: 'Claude Code', geminiCli: 'Gemini CLI', codexCli: 'Codex CLI', + codexCliWs: 'Codex CLI (WebSocket)', opencode: 'OpenCode' }, antigravity: {