diff --git a/agent/app/provider/catalog.go b/agent/app/provider/catalog.go index e8721cca3976..bc1753bcbba1 100644 --- a/agent/app/provider/catalog.go +++ b/agent/app/provider/catalog.go @@ -192,12 +192,9 @@ var catalog = map[string]Meta{ EnvKey: "GEMINI_API_KEY", Enabled: true, Models: []Model{ - {ID: "google/gemini-1.5-flash", Name: "Gemini 1.5 Flash"}, - {ID: "google/gemini-1.5-pro", Name: "Gemini 1.5 Pro"}, - {ID: "google/gemini-2.0-flash", Name: "Gemini 2.0 Flash"}, - {ID: "google/gemini-2.5-flash", Name: "Gemini 2.5 Flash"}, - {ID: "google/gemini-2.5-pro", Name: "Gemini 2.5 Pro"}, {ID: "google/gemini-3-flash-preview", Name: "Gemini 3 Flash Preview"}, + {ID: "google/gemini-flash-latest", Name: "Gemini Flash Latest"}, + {ID: "google/gemini-3-pro-preview", Name: "Gemini 3 Pro Preview"}, }, }, "moonshot": { diff --git a/agent/app/provider/openclaw.go b/agent/app/provider/openclaw.go index 7d7d2335d3a3..1a446fea3073 100644 --- a/agent/app/provider/openclaw.go +++ b/agent/app/provider/openclaw.go @@ -24,6 +24,8 @@ func BuildOpenClawPatch(provider, modelName, apiType string, maxTokens, contextW switch provider { case "deepseek": return buildDeepseekPatch(modelName, baseURL, apiKey), nil + case "gemini": + return buildGeminiPatch(modelName), nil case "moonshot", "kimi": return buildMoonshotPatch(provider, modelName, modelID, baseURL, apiKey), nil case "bailian-coding-plan": @@ -45,6 +47,10 @@ func BuildOpenClawPatch(provider, modelName, apiType string, maxTokens, contextW } } +func buildGeminiPatch(modelName string) *OpenClawPatch { + return &OpenClawPatch{PrimaryModel: modelName} +} + func buildDeepseekPatch(modelName, baseURL, apiKey string) *OpenClawPatch { return &OpenClawPatch{ PrimaryModel: modelName, diff --git a/agent/app/provider/verify.go b/agent/app/provider/verify.go index cbc5548aff09..fa4bf3cb2df5 100644 --- a/agent/app/provider/verify.go +++ b/agent/app/provider/verify.go @@ -69,11 +69,21 @@ func BuildVerifyRequest(provider, baseURL, apiKey string) VerifyRequest { request.URL = base + "/v1/models" } case "gemini": + request.Method = http.MethodPost if strings.Contains(base, "/v1beta") { - request.URL = fmt.Sprintf("%s/models?key=%s", base, apiKey) + request.URL = base + "/models/gemini-3-flash-preview:generateContent" } else { - request.URL = fmt.Sprintf("%s/v1beta/models?key=%s", base, apiKey) + request.URL = base + "/v1beta/models/gemini-3-flash-preview:generateContent" } + headers["x-goog-api-key"] = apiKey + headers["Content-Type"] = "application/json" + request.Body = mustJSON(map[string]interface{}{ + "contents": []map[string]interface{}{{ + "parts": []map[string]string{{ + "text": "Explain how AI works in a few words", + }}, + }}, + }) case "zai": headers["Authorization"] = fmt.Sprintf("Bearer %s", apiKey) request.URL = base + "/models" diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index 8752632b4c78..6509ea3fbc63 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -384,7 +384,7 @@ func (a AgentService) UpdateModelConfig(req dto.AgentModelConfigUpdateReq) error if modelName == "" { return buserr.New("ErrAgentProviderMismatch") } - if provider != "custom" && provider != "vllm" && !strings.HasPrefix(modelName, provider+"/") { + if provider != "custom" && provider != "vllm" && !modelMatchesProvider(provider, modelName) { return buserr.New("ErrAgentProviderMismatch") } baseURL := strings.TrimSpace(account.BaseURL) @@ -1950,6 +1950,20 @@ func normalizeAgentType(agentType string) string { return trim } +func modelMatchesProvider(provider, modelName string) bool { + prefix := providerModelPrefix(provider) + return prefix != "" && strings.HasPrefix(strings.TrimSpace(modelName), prefix+"/") +} + +func providerModelPrefix(provider string) string { + switch strings.ToLower(strings.TrimSpace(provider)) { + case "gemini": + return "google" + default: + return strings.ToLower(strings.TrimSpace(provider)) + } +} + func isSupportedAgentType(agentType string) bool { switch normalizeAgentType(agentType) { case constant.AppOpenclaw, constant.AppCopaw: 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 2e1b533a8bab..c76226a518de 100644 --- a/frontend/src/views/ai/agents/agent/config/tabs/model.vue +++ b/frontend/src/views/ai/agents/agent/config/tabs/model.vue @@ -52,6 +52,15 @@ const accountOptions = ref([]); const modelOptions = ref([]); const provdier = ref(''); +const getModelPrefix = (provider: string) => { + switch (provider) { + case 'gemini': + return 'google'; + default: + return provider; + } +}; + const form = reactive({ accountId: undefined as unknown as number, manualModel: false, @@ -128,8 +137,9 @@ const handleAccountChange = () => { setModelsByProvider(selected.provider); return; } + const modelPrefix = getModelPrefix(selected.provider); setModelsByProvider(selected.provider); - if (!form.manualModel && (!form.model || !form.model.startsWith(`${selected.provider}/`))) { + if (!form.manualModel && (!form.model || !form.model.startsWith(`${modelPrefix}/`))) { form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : ''; } }; @@ -150,7 +160,8 @@ const handleManualModelChange = (val: unknown) => { form.model = ''; return; } - if (!form.model || !form.model.startsWith(`${selected.provider}/`)) { + const modelPrefix = getModelPrefix(selected.provider); + if (!form.model || !form.model.startsWith(`${modelPrefix}/`)) { form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : ''; } }; @@ -172,13 +183,14 @@ const load = async (agent: AI.AgentItem) => { form.accountId = currentAccount.id; provdier.value = currentAccount.provider; setModelsByProvider(currentAccount.provider); + const modelPrefix = getModelPrefix(currentAccount.provider); const inProviderModels = modelOptions.value.some((item) => item.id === agent.model); form.manualModel = currentAccount.provider === 'custom' || currentAccount.provider === 'vllm' || currentAccount.provider === 'ollama' || !inProviderModels; - if (agent.model && (form.manualModel || agent.model.startsWith(`${currentAccount.provider}/`))) { + if (agent.model && (form.manualModel || agent.model.startsWith(`${modelPrefix}/`))) { form.model = agent.model; } else { form.model = modelOptions.value.length > 0 ? modelOptions.value[0].id : '';