From 8cead06d7ba8d61832a4cd7fa4e266309d76d46e Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:43:06 +0800 Subject: [PATCH] feat(ai-agents): add anthropic-messages support for custom account apiType (#12013) --- agent/app/provider/catalog.go | 2 +- agent/app/service/agents.go | 46 +++++++++++++------ frontend/src/lang/modules/en.ts | 1 - frontend/src/lang/modules/es-es.ts | 1 - frontend/src/lang/modules/ja.ts | 1 - frontend/src/lang/modules/ko.ts | 1 - frontend/src/lang/modules/ms.ts | 1 - frontend/src/lang/modules/pt-br.ts | 1 - frontend/src/lang/modules/ru.ts | 1 - frontend/src/lang/modules/tr.ts | 1 - frontend/src/lang/modules/zh-Hant.ts | 1 - frontend/src/lang/modules/zh.ts | 1 - .../src/views/ai/agents/agent/add/index.vue | 7 +-- .../ai/agents/agent/config/tabs/model.vue | 7 +-- .../src/views/ai/agents/model/add/index.vue | 1 + 15 files changed, 38 insertions(+), 35 deletions(-) diff --git a/agent/app/provider/catalog.go b/agent/app/provider/catalog.go index a94c67bd8..624a626b1 100644 --- a/agent/app/provider/catalog.go +++ b/agent/app/provider/catalog.go @@ -137,7 +137,7 @@ var catalog = map[string]Meta{ Key: "kimi-coding", DisplayName: "Kimi Coding", Sort: 100, - DefaultBaseURL: "https://api.moonshot.cn/anthropic/v1", + DefaultBaseURL: "https://kimi-code.moonshot.cn/api", EnvKey: "KIMI_API_KEY", Enabled: true, Models: []Model{ diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index cdc53eda3..680ae3f6e 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -94,6 +94,14 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) { return nil, buserr.New("ErrAgentApiKeyRequired") } apiType, maxTokens, contextWindow := resolveRuntimeParams(provider, account.APIType, account.MaxTokens, account.ContextWindow) + runtimeModel := strings.TrimSpace(req.Model) + if provider == "custom" { + primaryID := customPrimaryModelID(req.Model) + if primaryID == "" { + primaryID = normalizeCustomModel(req.Model) + } + runtimeModel = "custom/" + primaryID + } if err := checkPortExist(req.WebUIPort); err != nil { return nil, err } @@ -121,7 +129,7 @@ func (a AgentService) Create(req dto.AgentCreateReq) (*dto.AgentItem, error) { } params := map[string]interface{}{ "PROVIDER": provider, - "MODEL": req.Model, + "MODEL": runtimeModel, "API_TYPE": apiType, "MAX_TOKENS": maxTokens, "CONTEXT_WINDOW": contextWindow, @@ -291,7 +299,7 @@ func (a AgentService) UpdateModelConfig(req dto.AgentModelConfigUpdateReq) error if modelName == "" { return buserr.New("ErrAgentProviderMismatch") } - if !strings.HasPrefix(modelName, provider+"/") { + if provider != "custom" && !strings.HasPrefix(modelName, provider+"/") { return buserr.New("ErrAgentProviderMismatch") } baseURL := strings.TrimSpace(account.BaseURL) @@ -526,7 +534,7 @@ func (a AgentService) VerifyAccount(req dto.AgentAccountVerifyReq) error { if provider == "ollama" { return nil } - if provider == "custom" { + if provider == "custom" || provider == "kimi-coding" { return nil } return verifyProvider(provider, baseURL, apiKey) @@ -1412,20 +1420,15 @@ func writeOpenclawConfig(confDir, provider, modelName, apiType string, maxTokens }, } } else if provider == "custom" { - primary := modelName - if !strings.Contains(primary, "/") { - primary = "custom/" + strings.TrimSpace(primary) + customModelID := normalizeCustomModel(modelName) + primaryID := customPrimaryModelID(customModelID) + if primaryID == "" { + primaryID = customModelID } + primary := "custom/" + primaryID cfg.Agents.Defaults.Model.Primary = primary base := strings.TrimSpace(baseURL) plainKey := strings.TrimSpace(apiKey) - if !strings.Contains(modelName, "/") { - modelName = primary - } - customModelID := modelID - if parts := strings.SplitN(modelName, "/", 2); len(parts) == 2 { - customModelID = parts[1] - } useAPIType, useMaxTokens, useContextWindow := resolveRuntimeParams(provider, apiType, maxTokens, contextWindow) cfg.Models = &modelsConfig{ Mode: "merge", @@ -1702,6 +1705,21 @@ func normalizeCustomModel(modelName string) string { return trim } +func customPrimaryModelID(modelName string) string { + trim := normalizeCustomModel(modelName) + if trim == "" { + return "" + } + parts := strings.Split(trim, "/") + for i := len(parts) - 1; i >= 0; i-- { + part := strings.TrimSpace(parts[i]) + if part != "" { + return part + } + } + return "" +} + func normalizeAPIType(apiType string) string { trim := strings.ToLower(strings.TrimSpace(apiType)) if trim == "" { @@ -1712,7 +1730,7 @@ func normalizeAPIType(apiType string) string { func isSupportedAPIType(apiType string) bool { switch normalizeAPIType(apiType) { - case "openai-completions", "openai-responses": + case "openai-completions", "openai-responses", "anthropic-messages": return true default: return false diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 187bdedb7..d4cff108e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -720,7 +720,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'For custom model accounts, model names must start with custom/.', customProviderHelper: 'Custom model providers do not validate whether the account is available.', }, model: { diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index a4582a510..cc4255f94 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -716,7 +716,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'En la cuenta de modelo personalizada, el nombre del modelo debe empezar por custom/', customProviderHelper: 'En el proveedor de modelo personalizado no se valida si la cuenta está disponible', }, model: { diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 557cdd933..187edf912 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -708,7 +708,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'カスタムモデルアカウントでは、モデル名は必ず custom/ で始めてください', customProviderHelper: 'カスタムモデルプロバイダーでは、アカウントの有効性を検証しません', }, model: { diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 7f5bbfce4..e821ee927 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -703,7 +703,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: '사용자 정의 모델 계정의 모델명은 반드시 custom/ 로 시작해야 합니다', customProviderHelper: '사용자 정의 모델 공급자는 계정 사용 가능 여부를 검증하지 않습니다', }, model: { diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 860125a24..37d36ca17 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -719,7 +719,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'Akaun model tersuai, nama model mesti bermula dengan custom/', customProviderHelper: 'Penyedia model tersuai tidak mengesahkan sama ada akaun boleh digunakan', }, model: { diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index fd6f66621..12efb52eb 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -716,7 +716,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'Conta de modelo personalizada: o nome do modelo deve começar com custom/', customProviderHelper: 'Provedores de modelo personalizados não validam se a conta está disponível', }, model: { diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index c0026d64f..e0959a799 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -711,7 +711,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'Для пользовательской учетной записи модели имя модели должно начинаться с custom/', customProviderHelper: 'Для пользовательского провайдера модели доступность учетной записи не проверяется', }, model: { diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 52d6c0273..1b0d2ec3b 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -725,7 +725,6 @@ const message = { saveSuccess: 'Saved successfully', pairingCodeRequired: 'Please enter pairing code', pairingApproveSuccess: 'Pairing approved successfully', - customModelHelper: 'Özel model hesabında model adı custom/ ile başlamalıdır', customProviderHelper: 'Özel model sağlayıcısında hesabın kullanılabilirliği doğrulanmaz', }, model: { diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index f1e78fc9c..22c203065 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -694,7 +694,6 @@ const message = { saveSuccess: '保存成功', pairingCodeRequired: '請輸入配對碼', pairingApproveSuccess: '配對成功', - customModelHelper: '自訂模型帳號,模型需固定以 custom/ 開頭', customProviderHelper: '自訂模型供應商不驗證帳號是否可用', }, model: { diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 38120e99b..fd3058ce0 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -678,7 +678,6 @@ const message = { feishuSaveSuccess: '保存成功', pairingCodeRequired: '请输入配对码', pairingApproveSuccess: '配对成功', - customModelHelper: '自定义模型账号,模型固定以 custom/ 开头', customProviderHelper: '自定义模型供应商不验证账号是否可用', }, model: { diff --git a/frontend/src/views/ai/agents/agent/add/index.vue b/frontend/src/views/ai/agents/agent/add/index.vue index 5949a10b6..e7d7b9ca3 100644 --- a/frontend/src/views/ai/agents/agent/add/index.vue +++ b/frontend/src/views/ai/agents/agent/add/index.vue @@ -60,9 +60,6 @@ - - {{ $t('aiTools.agents.customModelHelper') }} - @@ -256,7 +253,7 @@ const handleAccountChange = () => { form.maxTokens = selected.maxTokens || 8192; form.contextWindow = selected.contextWindow || 128000; if (selected.provider === 'custom' && selected.model && !manualModel.value) { - form.model = `custom/${selected.model}`; + form.model = selected.model; } } setDefaultModel(); @@ -274,7 +271,7 @@ const setDefaultModel = () => { if (form.provider === 'custom') { const selected = accountOptions.value.find((item) => item.id === form.accountId); if (selected?.model && !form.model) { - form.model = `custom/${selected.model}`; + form.model = selected.model; } } }; diff --git a/frontend/src/views/ai/agents/agent/config/tabs/model.vue b/frontend/src/views/ai/agents/agent/config/tabs/model.vue index b947612b3..768622d2c 100644 --- a/frontend/src/views/ai/agents/agent/config/tabs/model.vue +++ b/frontend/src/views/ai/agents/agent/config/tabs/model.vue @@ -15,9 +15,6 @@ - - {{ $t('aiTools.agents.customModelHelper') }} - @@ -96,7 +93,7 @@ const handleAccountChange = () => { provdier.value = selected.provider; if (selected.provider === 'custom') { form.manualModel = true; - form.model = selected.model ? `custom/${selected.model}` : form.model; + form.model = selected.model || form.model; modelOptions.value = []; return; } @@ -148,7 +145,7 @@ const load = async (agent: AI.AgentItem) => { form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : ''; } if (currentAccount.provider === 'custom' && currentAccount.model && !form.model) { - form.model = `custom/${currentAccount.model}`; + form.model = currentAccount.model; } } finally { loading.value = false; diff --git a/frontend/src/views/ai/agents/model/add/index.vue b/frontend/src/views/ai/agents/model/add/index.vue index 56f6d5186..c930d19e4 100644 --- a/frontend/src/views/ai/agents/model/add/index.vue +++ b/frontend/src/views/ai/agents/model/add/index.vue @@ -31,6 +31,7 @@ +