From 4b2d6f0ef2a74d4dfa33995dfdb031a8663c34cf Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:22:09 +0800 Subject: [PATCH] feat(ai-agents): add bailian-coding-plan account support (#12014) --- agent/app/provider/catalog.go | 18 ++++ agent/app/service/agents.go | 87 +++++++++++++++++++ .../src/views/ai/agents/model/add/index.vue | 4 +- frontend/src/views/ai/agents/model/index.vue | 2 +- 4 files changed, 109 insertions(+), 2 deletions(-) diff --git a/agent/app/provider/catalog.go b/agent/app/provider/catalog.go index 624a626b1..6776febe6 100644 --- a/agent/app/provider/catalog.go +++ b/agent/app/provider/catalog.go @@ -144,6 +144,24 @@ var catalog = map[string]Meta{ {ID: "kimi-coding/k2p5", Name: "Kimi K2.5"}, }, }, + "bailian-coding-plan": { + Key: "bailian-coding-plan", + DisplayName: "阿里云百炼 Coding Plan", + Sort: 105, + DefaultBaseURL: "https://coding.dashscope.aliyuncs.com/v1", + EnvKey: "QWEN_API_KEY", + Enabled: true, + Models: []Model{ + {ID: "bailian-coding-plan/qwen3.5-plus", Name: "Qwen3.5-Plus"}, + {ID: "bailian-coding-plan/qwen3-max", Name: "Qwen3-Max"}, + {ID: "bailian-coding-plan/qwen3-coder-next", Name: "Qwen3-Coder-Next"}, + {ID: "bailian-coding-plan/qwen3-coder-plus", Name: "Qwen3-Coder-Plus"}, + {ID: "bailian-coding-plan/minimax-m2.5", Name: "MiniMax M2.5"}, + {ID: "bailian-coding-plan/glm-5", Name: "GLM-5"}, + {ID: "bailian-coding-plan/kimi-k2.5", Name: "Kimi-k2.5"}, + {ID: "bailian-coding-plan/glm-4.7", Name: "GLM-4.7"}, + }, + }, "qwen": { Key: "qwen", DisplayName: "Qwen", diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index 680ae3f6e..16c1186e7 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -369,6 +369,9 @@ func (a AgentService) CreateAccount(req dto.AgentAccountCreateReq) error { return buserr.New("ErrAgentApiKeyRequired") } baseURL := strings.TrimSpace(req.BaseURL) + if fixedURL, ok := fixedProviderBaseURL(provider); ok { + baseURL = fixedURL + } if provider == "custom" && baseURL == "" { return buserr.New("ErrAgentBaseURLRequired") } @@ -425,6 +428,9 @@ func (a AgentService) UpdateAccount(req dto.AgentAccountUpdateReq) error { } provider := strings.ToLower(strings.TrimSpace(account.Provider)) baseURL := strings.TrimSpace(req.BaseURL) + if fixedURL, ok := fixedProviderBaseURL(provider); ok { + baseURL = fixedURL + } if provider == "custom" && baseURL == "" { return buserr.New("ErrAgentBaseURLRequired") } @@ -523,6 +529,9 @@ func (a AgentService) VerifyAccount(req dto.AgentAccountVerifyReq) error { return buserr.New("ErrAgentApiKeyRequired") } baseURL := strings.TrimSpace(req.BaseURL) + if fixedURL, ok := fixedProviderBaseURL(provider); ok { + baseURL = fixedURL + } if baseURL == "" { if defaultURL, ok := providerDefaultBaseURL(provider); ok { baseURL = defaultURL @@ -1017,6 +1026,9 @@ func verifyProvider(provider, baseURL, apiKey string) error { if provider == "minimax" { return verifyMinimax("https://api.minimax.chat/v1", apiKey) } + if provider == "bailian-coding-plan" { + return verifyBailianCodingPlan(baseURL, apiKey) + } client := &http.Client{Timeout: 10 * time.Second} reqURL, headers := buildVerifyRequest(provider, baseURL, apiKey) request, err := http.NewRequest(http.MethodGet, reqURL, nil) @@ -1037,6 +1049,41 @@ func verifyProvider(provider, baseURL, apiKey string) error { return nil } +func verifyBailianCodingPlan(baseURL, apiKey string) error { + client := &http.Client{Timeout: 10 * time.Second} + base := strings.TrimRight(baseURL, "/") + if !strings.Contains(base, "/v1") { + base = base + "/v1" + } + reqURL := base + "/chat/completions" + body := map[string]interface{}{ + "model": "qwen3.5-plus", + "messages": []map[string]string{ + {"role": "user", "content": "test"}, + }, + "max_tokens": 1, + } + payload, err := json.Marshal(body) + if err != nil { + return err + } + request, err := http.NewRequest(http.MethodPost, reqURL, bytes.NewBuffer(payload)) + if err != nil { + return err + } + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey)) + request.Header.Set("Content-Type", "application/json") + resp, err := client.Do(request) + if err != nil { + return buserr.WithErr("ErrAgentAccountUnavailable", err) + } + defer resp.Body.Close() + if resp.StatusCode >= 400 { + return buserr.WithErr("ErrAgentAccountUnavailable", fmt.Errorf("verify failed: %s", resp.Status)) + } + return nil +} + func verifyMinimax(baseURL, apiKey string) error { client := &http.Client{Timeout: 10 * time.Second} base := strings.TrimRight(baseURL, "/") @@ -1384,6 +1431,37 @@ func writeOpenclawConfig(confDir, provider, modelName, apiType string, maxTokens }, }, } + } else if provider == "bailian-coding-plan" { + cfg.Agents.Defaults.Model.Primary = modelName + base := baseURL + if base == "" { + if defaultURL, ok := providerDefaultBaseURL(provider); ok { + base = defaultURL + } + } + plainKey := strings.TrimSpace(apiKey) + _, useMaxTokens, useContextWindow := resolveRuntimeParams(provider, apiType, maxTokens, contextWindow) + cfg.Models = &modelsConfig{ + Mode: "merge", + Providers: map[string]modelProvider{ + "bailian-coding-plan": { + ApiKey: plainKey, + BaseUrl: base, + Api: "openai-completions", + Models: []modelEntry{ + { + ID: modelID, + Name: modelID, + Reasoning: strings.Contains(strings.ToLower(modelID), "reason") || strings.Contains(strings.ToLower(modelID), "thinking"), + Input: []string{"text"}, + ContextWindow: useContextWindow, + MaxTokens: useMaxTokens, + Cost: modelCost{}, + }, + }, + }, + }, + } } else if provider == "minimax" { normalizedID := modelID switch strings.ToLower(modelID) { @@ -1617,6 +1695,15 @@ func providerDefaultBaseURL(provider string) (string, bool) { return providercatalog.DefaultBaseURL(provider) } +func fixedProviderBaseURL(provider string) (string, bool) { + switch strings.ToLower(strings.TrimSpace(provider)) { + case "bailian-coding-plan": + return providerDefaultBaseURL(provider) + default: + return "", false + } +} + func isSupportedAgentProvider(provider string) bool { return providercatalog.IsEnabled(provider) } diff --git a/frontend/src/views/ai/agents/model/add/index.vue b/frontend/src/views/ai/agents/model/add/index.vue index c930d19e4..1a1f22af4 100644 --- a/frontend/src/views/ai/agents/model/add/index.vue +++ b/frontend/src/views/ai/agents/model/add/index.vue @@ -16,7 +16,9 @@ - {{ $t('aiTools.agents.customProviderHelper') }} + + {{ $t('aiTools.agents.customProviderHelper') }} + {{ $t('terminal.rememberPassword') }} diff --git a/frontend/src/views/ai/agents/model/index.vue b/frontend/src/views/ai/agents/model/index.vue index d9e9966c6..0fef0877b 100644 --- a/frontend/src/views/ai/agents/model/index.vue +++ b/frontend/src/views/ai/agents/model/index.vue @@ -12,7 +12,7 @@