feat(ai-agents): add bailian-coding-plan account support (#12014)

This commit is contained in:
CityFun
2026-03-02 14:22:09 +08:00
committed by GitHub
parent f1c9ad45a7
commit 4b2d6f0ef2
4 changed files with 109 additions and 2 deletions
+18
View File
@@ -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",
+87
View File
@@ -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)
}
@@ -16,7 +16,9 @@
</el-form-item>
<el-form-item :label="$t('aiTools.agents.apiKey')" prop="apiKey">
<el-input v-model="form.apiKey" type="password" show-password />
<span class="input-help">{{ $t('aiTools.agents.customProviderHelper') }}</span>
<span class="input-help" v-if="form.provider === 'custom'">
{{ $t('aiTools.agents.customProviderHelper') }}
</span>
</el-form-item>
<el-form-item>
<el-checkbox v-model="form.rememberApiKey">{{ $t('terminal.rememberPassword') }}</el-checkbox>
+1 -1
View File
@@ -12,7 +12,7 @@
<template #main>
<ComplexTable :data="items" :pagination-config="paginationConfig" @search="search">
<el-table-column :label="$t('commons.table.name')" prop="name" min-width="200" />
<el-table-column :label="$t('aiTools.agents.provider')" prop="provider" width="120">
<el-table-column :label="$t('aiTools.agents.provider')" prop="provider" width="200">
<template #default="{ row }">
{{ getAgentProviderDisplayName(row.provider, row.providerName) }}
</template>