diff --git a/src/components/providers/forms/ProviderAdvancedConfig.tsx b/src/components/providers/forms/ProviderAdvancedConfig.tsx index 47f727bf6..dfc8c7c84 100644 --- a/src/components/providers/forms/ProviderAdvancedConfig.tsx +++ b/src/components/providers/forms/ProviderAdvancedConfig.tsx @@ -8,19 +8,33 @@ import { Eye, EyeOff, X, + ArrowLeftRight, } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Button } from "@/components/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { cn } from "@/lib/utils"; -import type { ProviderTestConfig, ProviderProxyConfig } from "@/types"; +import type { + ProviderTestConfig, + ProviderProxyConfig, + FormatTransformConfig, +} from "@/types"; interface ProviderAdvancedConfigProps { testConfig: ProviderTestConfig; proxyConfig: ProviderProxyConfig; + formatTransform?: FormatTransformConfig; onTestConfigChange: (config: ProviderTestConfig) => void; onProxyConfigChange: (config: ProviderProxyConfig) => void; + onFormatTransformChange?: (config: FormatTransformConfig) => void; } /** 从 ProviderProxyConfig 构建完整 URL */ @@ -71,14 +85,19 @@ function parseProxyUrl(url: string): Partial { export function ProviderAdvancedConfig({ testConfig, proxyConfig, + formatTransform, onTestConfigChange, onProxyConfigChange, + onFormatTransformChange, }: ProviderAdvancedConfigProps) { const { t } = useTranslation(); const [isTestConfigOpen, setIsTestConfigOpen] = useState(testConfig.enabled); const [isProxyConfigOpen, setIsProxyConfigOpen] = useState( proxyConfig.enabled, ); + const [isFormatTransformOpen, setIsFormatTransformOpen] = useState( + formatTransform?.enabled ?? false, + ); const [showPassword, setShowPassword] = useState(false); // 代理 URL 输入状态(仅在初始化时从 proxyConfig 构建) @@ -97,6 +116,11 @@ export function ProviderAdvancedConfig({ setIsProxyConfigOpen(proxyConfig.enabled); }, [proxyConfig.enabled]); + // 同步外部 formatTransform.enabled 变化到展开状态 + useEffect(() => { + setIsFormatTransformOpen(formatTransform?.enabled ?? false); + }, [formatTransform?.enabled]); + // 仅在外部 proxyConfig 变化且非用户输入时同步(如:重置表单、加载数据) useEffect(() => { if (!isUserTyping) { @@ -450,6 +474,135 @@ export function ProviderAdvancedConfig({ + + {/* 格式转换配置 */} + {onFormatTransformChange && ( +
+ +
+
+

+ {t("providerAdvanced.formatTransformDesc")} +

+
+
+ + +
+
+ + +
+
+
+ + onFormatTransformChange({ + ...(formatTransform ?? { enabled: false }), + transformStreaming: checked, + }) + } + disabled={!formatTransform?.enabled} + /> + +
+
+
+
+ )} ); } diff --git a/src/components/providers/forms/ProviderForm.tsx b/src/components/providers/forms/ProviderForm.tsx index d2cc70efa..dd92e28dc 100644 --- a/src/components/providers/forms/ProviderForm.tsx +++ b/src/components/providers/forms/ProviderForm.tsx @@ -13,6 +13,7 @@ import type { ProviderMeta, ProviderTestConfig, ProviderProxyConfig, + FormatTransformConfig, } from "@/types"; import { providerPresets, @@ -168,6 +169,9 @@ export function ProviderForm({ const [proxyConfig, setProxyConfig] = useState( () => initialData?.meta?.proxyConfig ?? { enabled: false }, ); + const [formatTransform, setFormatTransform] = useState( + () => initialData?.meta?.formatTransform ?? { enabled: false }, + ); // 使用 category hook const { category } = useProviderCategory({ @@ -940,6 +944,7 @@ export function ProviderForm({ // 添加高级配置 testConfig: testConfig.enabled ? testConfig : undefined, proxyConfig: proxyConfig.enabled ? proxyConfig : undefined, + formatTransform: formatTransform.enabled ? formatTransform : undefined, }; onSubmit(payload); @@ -1464,8 +1469,10 @@ export function ProviderForm({ {showButtons && ( diff --git a/src/types.ts b/src/types.ts index c4fba8fb7..4efadb35f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -119,6 +119,18 @@ export interface ProviderProxyConfig { proxyPassword?: string; } +// 格式转换配置(用于 OpenRouter 等需要 API 格式转换的供应商) +export interface FormatTransformConfig { + // 是否启用格式转换 + enabled: boolean; + // 源格式:anthropic, openai, gemini + sourceFormat?: "anthropic" | "openai" | "gemini"; + // 目标格式:anthropic, openai, gemini + targetFormat?: "anthropic" | "openai" | "gemini"; + // 是否转换流式响应(默认 true) + transformStreaming?: boolean; +} + // 供应商元数据(字段名与后端一致,保持 snake_case) export interface ProviderMeta { // 自定义端点:以 URL 为键,值为端点信息 @@ -135,6 +147,8 @@ export interface ProviderMeta { testConfig?: ProviderTestConfig; // 供应商单独的代理配置 proxyConfig?: ProviderProxyConfig; + // 格式转换配置(用于 OpenRouter 等需要 API 格式转换的供应商) + formatTransform?: FormatTransformConfig; } // Skill 同步方式