diff --git a/src/components/providers/forms/ClaudeFormFields.tsx b/src/components/providers/forms/ClaudeFormFields.tsx index 2b23a5c07..f9ac424c3 100644 --- a/src/components/providers/forms/ClaudeFormFields.tsx +++ b/src/components/providers/forms/ClaudeFormFields.tsx @@ -76,9 +76,6 @@ interface ClaudeFormFieldsProps { // Auth Key Field (ANTHROPIC_AUTH_TOKEN vs ANTHROPIC_API_KEY) apiKeyField: ClaudeApiKeyField; onApiKeyFieldChange: (field: ClaudeApiKeyField) => void; - - // Bedrock 模式标识 - isBedrock?: boolean; } export function ClaudeFormFields({ @@ -115,14 +112,13 @@ export function ClaudeFormFields({ onApiFormatChange, apiKeyField, onApiKeyFieldChange, - isBedrock, }: ClaudeFormFieldsProps) { const { t } = useTranslation(); return ( <> - {/* API Key 输入框 - Bedrock 模式下隐藏(认证通过模板字段处理) */} - {shouldShowApiKey && !isBedrock && ( + {/* API Key 输入框 */} + {shouldShowApiKey && ( )} - {/* Base URL 输入框 - Bedrock 模式下隐藏 */} - {shouldShowSpeedTest && !isBedrock && ( + {/* Base URL 输入框 */} + {shouldShowSpeedTest && ( )} - {/* 端点测速弹窗 - Bedrock 模式下隐藏 */} - {shouldShowSpeedTest && !isBedrock && isEndpointModalOpen && ( + {/* 端点测速弹窗 */} + {shouldShowSpeedTest && isEndpointModalOpen && ( )} - {/* API 格式选择(仅非官方供应商显示) */} - {shouldShowModelSelector && ( + {/* API 格式选择(仅非官方、非云服务商显示) */} + {shouldShowModelSelector && category !== "cloud_provider" && (
{t("providerForm.apiFormat", { defaultValue: "API 格式" })} diff --git a/src/components/providers/forms/ProviderForm.tsx b/src/components/providers/forms/ProviderForm.tsx index b33a41fb4..647e02f10 100644 --- a/src/components/providers/forms/ProviderForm.tsx +++ b/src/components/providers/forms/ProviderForm.tsx @@ -40,7 +40,10 @@ import { import { OpenCodeFormFields } from "./OpenCodeFormFields"; import { OpenClawFormFields } from "./OpenClawFormFields"; import type { UniversalProviderPreset } from "@/config/universalProviderPresets"; -import { applyTemplateValues } from "@/utils/providerConfigUtils"; +import { + applyTemplateValues, + hasApiKeyField, +} from "@/utils/providerConfigUtils"; import { mergeProviderMeta } from "@/utils/providerMetaUtils"; import { getCodexCustomTemplate } from "@/config/codexTemplates"; import CodexConfigEditor from "./CodexConfigEditor"; @@ -539,37 +542,6 @@ export function ProviderForm({ } } - // Bedrock 专属验证 - if (appId === "claude" && category === "cloud_provider") { - // 验证 Region 格式 - const regionValue = templateValues.AWS_REGION?.editorValue?.trim() || ""; - const regionPattern = /^[a-z]{2}(-[a-z]+)+-\d+$/; - if (!regionPattern.test(regionValue)) { - toast.error( - t("providerForm.invalidRegion", { - defaultValue: "请输入有效的 AWS Region 格式(如 us-west-2)", - }), - ); - return; - } - - // 验证至少填写一种认证方式 - const apiKeyValue = templateValues.BEDROCK_API_KEY?.editorValue?.trim() || ""; - const accessKeyValue = templateValues.AWS_ACCESS_KEY_ID?.editorValue?.trim() || ""; - const secretKeyValue = templateValues.AWS_SECRET_ACCESS_KEY?.editorValue?.trim() || ""; - const hasApiKey = apiKeyValue.length > 0; - const hasAksk = accessKeyValue.length > 0 && secretKeyValue.length > 0; - - if (!hasApiKey && !hasAksk) { - toast.error( - t("providerForm.bedrockAuthRequired", { - defaultValue: "请至少填写一种认证方式:Bedrock API Key 或 Access Key ID + Secret Access Key", - }), - ); - return; - } - } - if (!values.name.trim()) { toast.error( t("providerForm.fillSupplierName", { @@ -625,7 +597,7 @@ export function ProviderForm({ } // 非官方供应商必填校验:端点和 API Key - // cloud_provider(如 Bedrock)有自己的认证方式,跳过通用校验 + // cloud_provider(如 Bedrock)通过模板变量处理认证,跳过通用校验 if (category !== "official" && category !== "cloud_provider") { if (appId === "claude") { if (!baseUrl.trim()) { @@ -748,28 +720,6 @@ export function ProviderForm({ } } settingsConfig = JSON.stringify(omoConfig); - } else if (appId === "claude" && category === "cloud_provider") { - // Bedrock: 根据认证方式清理 settingsConfig - try { - const config = JSON.parse(values.settingsConfig.trim()); - const apiKeyValue = (config.apiKey || "").trim(); - const isResolvedValue = apiKeyValue && !apiKeyValue.includes("${"); - - if (isResolvedValue) { - // API Key 模式:移除 AKSK 字段 - if (config.env) { - delete config.env.AWS_ACCESS_KEY_ID; - delete config.env.AWS_SECRET_ACCESS_KEY; - } - } else { - // AKSK 模式:移除空的 apiKey - delete config.apiKey; - } - - settingsConfig = JSON.stringify(config); - } catch { - settingsConfig = values.settingsConfig.trim(); - } } else { settingsConfig = values.settingsConfig.trim(); } @@ -897,7 +847,8 @@ export function ProviderForm({ ); }, [groupedPresets]); - const shouldShowSpeedTest = category !== "official"; + const shouldShowSpeedTest = + category !== "official" && category !== "cloud_provider"; const { shouldShowApiKeyLink: shouldShowClaudeApiKeyLink, @@ -1287,11 +1238,13 @@ export function ProviderForm({ {appId === "claude" && ( AWS \ No newline at end of file +AWS \ No newline at end of file diff --git a/src/icons/extracted/index.ts b/src/icons/extracted/index.ts index 0d87ebf71..a87ab5d88 100644 --- a/src/icons/extracted/index.ts +++ b/src/icons/extracted/index.ts @@ -6,7 +6,7 @@ export const icons: Record = { aigocode: `AiGoCode`, alibaba: `Alibaba`, anthropic: `Anthropic`, - aws: `AWS`, + aws: `AWS`, azure: `Azure`, baidu: `Baidu`, bytedance: `ByteDance`, diff --git a/src/utils/providerConfigUtils.ts b/src/utils/providerConfigUtils.ts index 6d1cd90c5..7d56d4025 100644 --- a/src/utils/providerConfigUtils.ts +++ b/src/utils/providerConfigUtils.ts @@ -29,6 +29,16 @@ export const getApiKeyFromConfig = ( ): string => { try { const config = JSON.parse(jsonString); + + // 优先检查顶层 apiKey 字段(用于 Bedrock API Key 等预设) + if ( + typeof config?.apiKey === "string" && + config.apiKey && + !config.apiKey.includes("${") + ) { + return config.apiKey; + } + const env = config?.env; if (!env) return ""; @@ -112,6 +122,12 @@ export const hasApiKeyField = ( ): boolean => { try { const config = JSON.parse(jsonString); + + // 检查顶层 apiKey 字段(用于 Bedrock API Key 等预设) + if (Object.prototype.hasOwnProperty.call(config, "apiKey")) { + return true; + } + const env = config?.env ?? {}; if (appType === "gemini") { @@ -144,6 +160,13 @@ export const setApiKeyInConfig = ( const { createIfMissing = false, appType, apiKeyField } = options; try { const config = JSON.parse(jsonString); + + // 优先检查顶层 apiKey 字段(用于 Bedrock API Key 等预设) + if (Object.prototype.hasOwnProperty.call(config, "apiKey")) { + config.apiKey = apiKey; + return JSON.stringify(config, null, 2); + } + if (!config.env) { if (!createIfMissing) return jsonString; config.env = {};