diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..97550816 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(test:*)", + "Bash(PORT=20127 NEXT_PUBLIC_BASE_URL=http://localhost:20127 npm run dev:*)" + ] + } +} diff --git a/open-sse/config/constants.js b/open-sse/config/constants.js index ee456100..c4314b4f 100644 --- a/open-sse/config/constants.js +++ b/open-sse/config/constants.js @@ -174,6 +174,11 @@ export const PROVIDERS = { "User-Agent": "connect-es/1.6.1" }, clientVersion: "1.1.3" + }, + alicloud: { + baseUrl: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", + format: "openai", + headers: {} } }; diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index 460664b7..26e73fa8 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -160,6 +160,16 @@ export const PROVIDER_MODELS = { "minimax-cn": [ { id: "MiniMax-M2.1", name: "MiniMax M2.1" }, ], + alicloud: [ + { id: "qwen3.5-plus", name: "Qwen3.5 Plus" }, + { id: "kimi-k2.5", name: "Kimi K2.5" }, + { id: "glm-5", name: "GLM 5" }, + { id: "MiniMax-M2.5", name: "MiniMax M2.5" }, + { id: "qwen3-max-2026-01-23", name: "Qwen3 Max" }, + { id: "qwen3-coder-next", name: "Qwen3 Coder Next" }, + { id: "qwen3-coder-plus", name: "Qwen3 Coder Plus" }, + { id: "glm-4.7", name: "GLM 4.7" }, + ], }; // Helper functions @@ -213,6 +223,7 @@ export const PROVIDER_ID_TO_ALIAS = { kimi: "kimi", minimax: "minimax", "minimax-cn": "minimax-cn", + alicloud: "alicloud", }; export function getModelsByProviderId(providerId) { diff --git a/src/app/api/providers/[id]/models/route.js b/src/app/api/providers/[id]/models/route.js index b1dff57c..5e1b55f3 100644 --- a/src/app/api/providers/[id]/models/route.js +++ b/src/app/api/providers/[id]/models/route.js @@ -71,6 +71,14 @@ const PROVIDER_MODELS_CONFIG = { }, authHeader: "x-api-key", parseResponse: (data) => data.data || [] + }, + alicloud: { + url: "https://coding.dashscope.aliyuncs.com/v1/models", + method: "GET", + headers: { "Content-Type": "application/json" }, + authHeader: "Authorization", + authPrefix: "Bearer ", + parseResponse: (data) => data.data || [] } }; diff --git a/src/app/api/providers/[id]/test/route.js b/src/app/api/providers/[id]/test/route.js index 26abcf0c..958361c6 100644 --- a/src/app/api/providers/[id]/test/route.js +++ b/src/app/api/providers/[id]/test/route.js @@ -464,6 +464,24 @@ async function testApiKeyConnection(connection) { return { valid, error: valid ? null : "Invalid API key" }; } + case "alicloud": { + // 阿里云百炼 Coding Plan uses OpenAI-compatible API + const res = await fetch("https://coding.dashscope.aliyuncs.com/v1/chat/completions", { + method: "POST", + headers: { + "Authorization": `Bearer ${connection.apiKey}`, + "content-type": "application/json", + }, + body: JSON.stringify({ + model: "qwen3.5-plus", + max_tokens: 1, + messages: [{ role: "user", content: "test" }], + }), + }); + const valid = res.status !== 401 && res.status !== 403; + return { valid, error: valid ? null : "Invalid API key" }; + } + case "deepseek": { const res = await fetch("https://api.deepseek.com/models", { headers: { Authorization: `Bearer ${connection.apiKey}` }, diff --git a/src/app/api/providers/validate/route.js b/src/app/api/providers/validate/route.js index c06844a6..3ddb8877 100644 --- a/src/app/api/providers/validate/route.js +++ b/src/app/api/providers/validate/route.js @@ -102,17 +102,20 @@ export async function POST(request) { case "glm-cn": case "kimi": case "minimax": - case "minimax-cn": { + case "minimax-cn": + case "alicloud": { const claudeBaseUrls = { glm: "https://api.z.ai/api/anthropic/v1/messages", "glm-cn": "https://open.bigmodel.cn/api/coding/paas/v4/chat/completions", kimi: "https://api.kimi.com/coding/v1/messages", minimax: "https://api.minimax.io/anthropic/v1/messages", "minimax-cn": "https://api.minimaxi.com/anthropic/v1/messages", + alicloud: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", }; - // glm-cn uses OpenAI format - if (provider === "glm-cn") { + // glm-cn and alicloud use OpenAI format + if (provider === "glm-cn" || provider === "alicloud") { + const testModel = provider === "alicloud" ? "qwen3.5-plus" : "glm-4.7"; const glmCnRes = await fetch(claudeBaseUrls[provider], { method: "POST", headers: { @@ -120,7 +123,7 @@ export async function POST(request) { "content-type": "application/json", }, body: JSON.stringify({ - model: "glm-4.7", + model: testModel, max_tokens: 1, messages: [{ role: "user", content: "test" }], }), @@ -145,7 +148,7 @@ export async function POST(request) { break; } - default: + default: return NextResponse.json({ error: "Provider validation not supported" }, { status: 400 }); } } catch (err) { diff --git a/src/shared/constants/config.js b/src/shared/constants/config.js index a0bcdb45..aed253c0 100644 --- a/src/shared/constants/config.js +++ b/src/shared/constants/config.js @@ -37,6 +37,7 @@ export const PROVIDER_ENDPOINTS = { kimi: "https://api.kimi.com/coding/v1/messages", minimax: "https://api.minimax.io/anthropic/v1/messages", "minimax-cn": "https://api.minimaxi.com/anthropic/v1/messages", + alicloud: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", openai: "https://api.openai.com/v1/chat/completions", anthropic: "https://api.anthropic.com/v1/messages", gemini: "https://generativelanguage.googleapis.com/v1beta/models", diff --git a/src/shared/constants/providers.js b/src/shared/constants/providers.js index 936504fa..dee5209d 100644 --- a/src/shared/constants/providers.js +++ b/src/shared/constants/providers.js @@ -24,6 +24,7 @@ export const APIKEY_PROVIDERS = { kimi: { id: "kimi", alias: "kimi", name: "Kimi Coding", icon: "psychology", color: "#1E3A8A", textIcon: "KM" }, minimax: { id: "minimax", alias: "minimax", name: "Minimax Coding", icon: "memory", color: "#7C3AED", textIcon: "MM" }, "minimax-cn": { id: "minimax-cn", alias: "minimax-cn", name: "Minimax (China)", icon: "memory", color: "#DC2626", textIcon: "MC" }, + alicloud: { id: "alicloud", alias: "alicloud", name: "阿里云百炼 Coding Plan", icon: "cloud", color: "#FF6A00", textIcon: "ALi" }, openai: { id: "openai", alias: "openai", name: "OpenAI", icon: "auto_awesome", color: "#10A37F", textIcon: "OA" }, anthropic: { id: "anthropic", alias: "anthropic", name: "Anthropic", icon: "smart_toy", color: "#D97757", textIcon: "AN" }, gemini: { id: "gemini", alias: "gemini", name: "Gemini", icon: "diamond", color: "#4285F4", textIcon: "GE" },