mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-26 14:35:22 +08:00
refactor(proxy): remove Codex Chat Completions API format support
Codex CLI only uses OpenAI Responses API. Remove unused Chat Completions routes, handler, parser config, URL builder branches, frontend API format selector, and stale i18n keys. Claude openai_chat support is preserved.
This commit is contained in:
@@ -2,22 +2,11 @@ import { useTranslation } from "react-i18next";
|
||||
import EndpointSpeedTest from "./EndpointSpeedTest";
|
||||
import { ApiKeySection, EndpointField } from "./shared";
|
||||
import type { ProviderCategory } from "@/types";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { FormLabel } from "@/components/ui/form";
|
||||
|
||||
interface EndpointCandidate {
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Codex API 格式类型
|
||||
export type CodexApiFormat = "responses" | "chat";
|
||||
|
||||
interface CodexFormFieldsProps {
|
||||
providerId?: string;
|
||||
// API Key
|
||||
@@ -46,11 +35,6 @@ interface CodexFormFieldsProps {
|
||||
|
||||
// Speed Test Endpoints
|
||||
speedTestEndpoints: EndpointCandidate[];
|
||||
|
||||
// API Format (for Codex providers)
|
||||
apiFormat?: CodexApiFormat;
|
||||
onApiFormatChange?: (format: CodexApiFormat) => void;
|
||||
shouldShowApiFormatSelector?: boolean;
|
||||
}
|
||||
|
||||
export function CodexFormFields({
|
||||
@@ -74,21 +58,9 @@ export function CodexFormFields({
|
||||
modelName = "",
|
||||
onModelNameChange,
|
||||
speedTestEndpoints,
|
||||
apiFormat = "responses",
|
||||
onApiFormatChange,
|
||||
shouldShowApiFormatSelector = false,
|
||||
}: CodexFormFieldsProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// 根据 API 格式选择提示文本
|
||||
const apiHint =
|
||||
apiFormat === "chat"
|
||||
? t("providerForm.codexApiHintChat", {
|
||||
defaultValue:
|
||||
"💡 填写兼容 OpenAI Chat Completions 格式的服务端点地址",
|
||||
})
|
||||
: t("providerForm.codexApiHint");
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Codex API Key 输入框 */}
|
||||
@@ -112,37 +84,6 @@ export function CodexFormFields({
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* API 格式选择器 */}
|
||||
{shouldShowApiFormatSelector && onApiFormatChange && (
|
||||
<div className="space-y-2">
|
||||
<FormLabel htmlFor="codexApiFormat">
|
||||
{t("providerForm.apiFormat", { defaultValue: "API 格式" })}
|
||||
</FormLabel>
|
||||
<Select value={apiFormat} onValueChange={onApiFormatChange}>
|
||||
<SelectTrigger id="codexApiFormat" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="responses">
|
||||
{t("providerForm.codexApiFormatResponses", {
|
||||
defaultValue: "OpenAI Responses (默认)",
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem value="chat">
|
||||
{t("providerForm.codexApiFormatChat", {
|
||||
defaultValue: "OpenAI Chat Completions",
|
||||
})}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("providerForm.codexApiFormatHint", {
|
||||
defaultValue: "选择供应商支持的 API 格式",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Codex Base URL 输入框 */}
|
||||
{shouldShowSpeedTest && (
|
||||
<EndpointField
|
||||
@@ -151,10 +92,10 @@ export function CodexFormFields({
|
||||
value={codexBaseUrl}
|
||||
onChange={onBaseUrlChange}
|
||||
placeholder={t("providerForm.codexApiEndpointPlaceholder")}
|
||||
hint={apiHint}
|
||||
hint={t("providerForm.codexApiHint")}
|
||||
onManageClick={() => onEndpointModalToggle(true)}
|
||||
appType="codex"
|
||||
apiFormat={apiFormat}
|
||||
apiFormat="responses"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import { OpenCodeFormFields } from "./OpenCodeFormFields";
|
||||
import type { UniversalProviderPreset } from "@/config/universalProviderPresets";
|
||||
import {
|
||||
applyTemplateValues,
|
||||
extractCodexWireApi,
|
||||
setCodexWireApi,
|
||||
} from "@/utils/providerConfigUtils";
|
||||
import { mergeProviderMeta } from "@/utils/providerMetaUtils";
|
||||
@@ -50,7 +49,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { ProviderPresetSelector } from "./ProviderPresetSelector";
|
||||
import { BasicFormFields } from "./BasicFormFields";
|
||||
import { ClaudeFormFields } from "./ClaudeFormFields";
|
||||
import { CodexFormFields, type CodexApiFormat } from "./CodexFormFields";
|
||||
import { CodexFormFields } from "./CodexFormFields";
|
||||
import { GeminiFormFields } from "./GeminiFormFields";
|
||||
import { OmoFormFields } from "./OmoFormFields";
|
||||
import { type OmoGlobalConfigFieldsRef } from "./OmoGlobalConfigFields";
|
||||
@@ -369,19 +368,6 @@ export function ProviderForm({
|
||||
: "anthropic";
|
||||
});
|
||||
|
||||
const [localCodexApiFormat, setLocalCodexApiFormat] =
|
||||
useState<CodexApiFormat>(() => {
|
||||
if (appId !== "codex") return "responses";
|
||||
if (initialData?.meta?.apiFormat === "chat") return "chat";
|
||||
if (initialData?.meta?.apiFormat === "responses") return "responses";
|
||||
|
||||
const initialConfig = initialData?.settingsConfig?.config;
|
||||
if (typeof initialConfig === "string") {
|
||||
return extractCodexWireApi(initialConfig) ?? "responses";
|
||||
}
|
||||
return "responses";
|
||||
});
|
||||
|
||||
const {
|
||||
codexAuth,
|
||||
codexConfig,
|
||||
@@ -390,7 +376,6 @@ export function ProviderForm({
|
||||
codexModelName,
|
||||
codexAuthError,
|
||||
setCodexAuth,
|
||||
setCodexConfig,
|
||||
handleCodexApiKeyChange,
|
||||
handleCodexBaseUrlChange,
|
||||
handleCodexModelNameChange,
|
||||
@@ -413,14 +398,6 @@ export function ProviderForm({
|
||||
setLocalClaudeApiFormat(format);
|
||||
}, []);
|
||||
|
||||
const handleCodexApiFormatChange = useCallback(
|
||||
(format: CodexApiFormat) => {
|
||||
setLocalCodexApiFormat(format);
|
||||
setCodexConfig((prev) => setCodexWireApi(prev, format));
|
||||
},
|
||||
[setCodexConfig],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (appId === "codex" && !initialData && selectedPresetId === "custom") {
|
||||
const template = getCodexCustomTemplate();
|
||||
@@ -1078,7 +1055,7 @@ export function ProviderForm({
|
||||
const authJson = JSON.parse(codexAuth);
|
||||
const configObj = {
|
||||
auth: authJson,
|
||||
config: codexConfig ?? "",
|
||||
config: setCodexWireApi(codexConfig ?? "", "responses"),
|
||||
};
|
||||
settingsConfig = JSON.stringify(configObj);
|
||||
} catch (err) {
|
||||
@@ -1198,9 +1175,7 @@ export function ProviderForm({
|
||||
const providerApiFormat =
|
||||
appId === "claude" && category !== "official"
|
||||
? localClaudeApiFormat
|
||||
: appId === "codex" && category !== "official"
|
||||
? localCodexApiFormat
|
||||
: undefined;
|
||||
: undefined;
|
||||
|
||||
const baseMeta: ProviderMeta | undefined =
|
||||
payload.meta ?? (initialData?.meta ? { ...initialData.meta } : undefined);
|
||||
@@ -1310,9 +1285,6 @@ export function ProviderForm({
|
||||
|
||||
if (appId === "codex") {
|
||||
const template = getCodexCustomTemplate();
|
||||
setLocalCodexApiFormat(
|
||||
extractCodexWireApi(template.config) ?? "responses",
|
||||
);
|
||||
resetCodexConfig(template.auth, template.config);
|
||||
}
|
||||
if (appId === "gemini") {
|
||||
@@ -1347,7 +1319,6 @@ export function ProviderForm({
|
||||
const auth = preset.auth ?? {};
|
||||
const config = preset.config ?? "";
|
||||
|
||||
setLocalCodexApiFormat(extractCodexWireApi(config) ?? "responses");
|
||||
resetCodexConfig(auth, config);
|
||||
|
||||
form.reset({
|
||||
@@ -1584,9 +1555,6 @@ export function ProviderForm({
|
||||
modelName={codexModelName}
|
||||
onModelNameChange={handleCodexModelNameChange}
|
||||
speedTestEndpoints={speedTestEndpoints}
|
||||
apiFormat={localCodexApiFormat}
|
||||
onApiFormatChange={handleCodexApiFormatChange}
|
||||
shouldShowApiFormatSelector={category !== "official"}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -515,10 +515,6 @@
|
||||
"apiHint": "💡 Fill in Claude API compatible service endpoint, avoid trailing slash",
|
||||
"apiHintOAI": "💡 Fill in OpenAI Chat Completions compatible service endpoint, avoid trailing slash",
|
||||
"codexApiHint": "💡 Fill in service endpoint compatible with OpenAI Response format",
|
||||
"codexApiHintChat": "💡 Fill in service endpoint compatible with OpenAI Chat Completions format",
|
||||
"codexApiFormatResponses": "OpenAI Responses (Default)",
|
||||
"codexApiFormatChat": "OpenAI Chat Completions",
|
||||
"codexApiFormatHint": "Select the API format supported by the provider",
|
||||
"directRequestUrl": "CLI Direct Request URL:",
|
||||
"directRequestUrlDesc": "Actual request URL after CLI appends default suffix",
|
||||
"proxyRequestUrl": "CCS Proxy Request URL:",
|
||||
|
||||
@@ -515,10 +515,6 @@
|
||||
"apiHint": "💡 Claude API 互換サービスのエンドポイントを入力してください。末尾にスラッシュを付けないでください",
|
||||
"apiHintOAI": "💡 OpenAI Chat Completions 互換サービスのエンドポイントを入力してください。末尾にスラッシュを付けないでください",
|
||||
"codexApiHint": "💡 OpenAI Response 互換のサービスエンドポイントを入力してください",
|
||||
"codexApiHintChat": "💡 OpenAI Chat Completions 互換のサービスエンドポイントを入力してください",
|
||||
"codexApiFormatResponses": "OpenAI Responses(デフォルト)",
|
||||
"codexApiFormatChat": "OpenAI Chat Completions",
|
||||
"codexApiFormatHint": "プロバイダーがサポートする API フォーマットを選択",
|
||||
"directRequestUrl": "CLI 直接リクエスト URL:",
|
||||
"directRequestUrlDesc": "CLI がデフォルトサフィックスを追加した後の実際のリクエスト URL",
|
||||
"proxyRequestUrl": "CCS プロキシリクエスト URL:",
|
||||
|
||||
@@ -515,10 +515,6 @@
|
||||
"apiHint": "💡 填写兼容 Claude API 的服务端点地址,不要以斜杠结尾",
|
||||
"apiHintOAI": "💡 填写兼容 OpenAI Chat Completions 的服务端点地址,不要以斜杠结尾",
|
||||
"codexApiHint": "💡 填写兼容 OpenAI Response 格式的服务端点地址",
|
||||
"codexApiHintChat": "💡 填写兼容 OpenAI Chat Completions 格式的服务端点地址",
|
||||
"codexApiFormatResponses": "OpenAI Responses (默认)",
|
||||
"codexApiFormatChat": "OpenAI Chat Completions",
|
||||
"codexApiFormatHint": "选择供应商支持的 API 格式",
|
||||
"directRequestUrl": "CLI 直连请求地址:",
|
||||
"directRequestUrlDesc": "CLI 硬拼接默认后缀后的实际请求地址",
|
||||
"proxyRequestUrl": "CCS 代理请求地址:",
|
||||
|
||||
+1
-2
@@ -146,8 +146,7 @@ export interface ProviderMeta {
|
||||
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
|
||||
// Codex:
|
||||
// - "responses": OpenAI Responses API
|
||||
// - "chat": OpenAI Chat Completions API
|
||||
apiFormat?: "anthropic" | "openai_chat" | "responses" | "chat";
|
||||
apiFormat?: "anthropic" | "openai_chat" | "responses";
|
||||
}
|
||||
|
||||
// Skill 同步方式
|
||||
|
||||
@@ -468,27 +468,10 @@ export const setCodexBaseUrl = (
|
||||
return `${prefix}${replacementLine}\n`;
|
||||
};
|
||||
|
||||
// 从 Codex 的 TOML 配置文本中提取 wire_api 字段(responses/chat)
|
||||
export const extractCodexWireApi = (
|
||||
configText: string | undefined | null,
|
||||
): "responses" | "chat" | undefined => {
|
||||
try {
|
||||
const raw = typeof configText === "string" ? configText : "";
|
||||
const text = normalizeQuotes(raw);
|
||||
if (!text) return undefined;
|
||||
|
||||
const m = text.match(/^wire_api\s*=\s*(['"])(responses|chat)\1/m);
|
||||
if (!m || !m[2]) return undefined;
|
||||
return m[2] === "chat" ? "chat" : "responses";
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// 在 Codex 的 TOML 配置文本中写入或更新 wire_api 字段
|
||||
// 在 Codex 的 TOML 配置文本中写入或更新 wire_api 字段(仅保留 responses)
|
||||
export const setCodexWireApi = (
|
||||
configText: string,
|
||||
wireApi: "responses" | "chat",
|
||||
wireApi: "responses" = "responses",
|
||||
): string => {
|
||||
const normalizedText = normalizeQuotes(configText);
|
||||
const replacementLine = `wire_api = "${wireApi}"`;
|
||||
|
||||
Reference in New Issue
Block a user