From f2e7a98ce093c81d0b2d5e002942fdce2f77a371 Mon Sep 17 00:00:00 2001 From: kenlin Date: Fri, 24 Apr 2026 10:28:50 +0800 Subject: [PATCH] feat: add built-in Volcengine Ark provider support (#741) Add Volcengine Ark as a first-class API key provider with official model presets, endpoint configuration, API key validation, model discovery, connection testing, provider logo, and runtime alias mapping for `ark/*` model IDs. Made-with: Cursor Co-authored-by: kingsy --- open-sse/config/providerModels.js | 13 +++++++++++++ open-sse/config/providers.js | 5 +++++ open-sse/services/model.js | 2 ++ public/providers/volcengine-ark.png | Bin 0 -> 41730 bytes src/app/api/providers/[id]/models/route.js | 1 + src/app/api/providers/[id]/test/testUtils.js | 9 +++++++++ src/app/api/providers/validate/route.js | 17 +++++++++++++++++ src/shared/constants/config.js | 1 + src/shared/constants/providers.js | 1 + 9 files changed, 49 insertions(+) create mode 100644 public/providers/volcengine-ark.png diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index b913360a..17fc91e3 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -327,6 +327,19 @@ export const PROVIDER_MODELS = { { id: "qwen3-coder-plus", name: "Qwen3 Coder Plus" }, { id: "glm-4.7", name: "GLM 4.7" }, ], + "volcengine-ark": [ + { id: "Doubao-Seed-2.0-Code", name: "Doubao-Seed-2.0-Code" }, + { id: "Doubao-Seed-2.0-pro", name: "Doubao-Seed-2.0-pro" }, + { id: "Doubao-Seed-2.0-lite", name: "Doubao-Seed-2.0-lite" }, + { id: "Doubao-Seed-Code", name: "Doubao-Seed-Code" }, + { id: "GLM-5.1", name: "GLM-5.1" }, + { id: "MiniMax-M2.7", name: "MiniMax-M2.7" }, + { id: "Kimi-K2.6", name: "Kimi-K2.6" }, + { id: "MiniMax-M2.5", name: "MiniMax-M2.5" }, + { id: "Kimi-K2.5", name: "Kimi-K2.5" }, + { id: "GLM-4.7", name: "GLM-4.7" }, + { id: "DeepSeek-V3.2", name: "DeepSeek-V3.2" }, + ], deepseek: [ { id: "deepseek-chat", name: "DeepSeek V3.2 Chat" }, { id: "deepseek-reasoner", name: "DeepSeek V3.2 Reasoner" }, diff --git a/open-sse/config/providers.js b/open-sse/config/providers.js index 3c5dabdc..e118bd1a 100644 --- a/open-sse/config/providers.js +++ b/open-sse/config/providers.js @@ -156,6 +156,11 @@ export const PROVIDERS = { format: "openai", headers: {} }, + "volcengine-ark": { + baseUrl: "https://ark.cn-beijing.volces.com/api/coding/v3/chat/completions", + format: "openai", + headers: {} + }, github: { baseUrl: "https://api.githubcopilot.com/chat/completions", responsesUrl: "https://api.githubcopilot.com/responses", diff --git a/open-sse/services/model.js b/open-sse/services/model.js index ebe8d90b..674d94a8 100644 --- a/open-sse/services/model.js +++ b/open-sse/services/model.js @@ -49,6 +49,8 @@ const ALIAS_TO_PROVIDER_ID = { nanobanana: "nanobanana", ch: "chutes", chutes: "chutes", + ark: "volcengine-ark", + "volcengine-ark": "volcengine-ark", cursor: "cursor", vx: "vertex", vertex: "vertex", diff --git a/public/providers/volcengine-ark.png b/public/providers/volcengine-ark.png new file mode 100644 index 0000000000000000000000000000000000000000..60625a1642889791408c647095b22364a421a830 GIT binary patch literal 41730 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 z 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 data.data || [] }, + "volcengine-ark": createOpenAIModelsConfig("https://ark.cn-beijing.volces.com/api/coding/v3/models"), // OpenAI-compatible API key providers deepseek: createOpenAIModelsConfig("https://api.deepseek.com/models"), diff --git a/src/app/api/providers/[id]/test/testUtils.js b/src/app/api/providers/[id]/test/testUtils.js index b5e54ef9..67745da5 100644 --- a/src/app/api/providers/[id]/test/testUtils.js +++ b/src/app/api/providers/[id]/test/testUtils.js @@ -439,6 +439,15 @@ async function testApiKeyConnection(connection, effectiveProxy = null) { const valid = res.status !== 401 && res.status !== 403; return { valid, error: valid ? null : "Invalid API key" }; } + case "volcengine-ark": { + const res = await fetchWithConnectionProxy("https://ark.cn-beijing.volces.com/api/coding/v3/chat/completions", { + method: "POST", + headers: { "Authorization": `Bearer ${connection.apiKey}`, "content-type": "application/json" }, + body: JSON.stringify({ model: getDefaultModel(connection.provider), max_tokens: 1, messages: [{ role: "user", content: "test" }] }), + }, effectiveProxy); + const valid = res.status !== 401 && res.status !== 403; + return { valid, error: valid ? null : "Invalid API key" }; + } case "deepseek": { const res = await fetchWithConnectionProxy("https://api.deepseek.com/models", { headers: { Authorization: `Bearer ${connection.apiKey}` } }, effectiveProxy); return { valid: res.ok, error: res.ok ? null : "Invalid API key" }; diff --git a/src/app/api/providers/validate/route.js b/src/app/api/providers/validate/route.js index 6e518ff6..23bdc1d2 100644 --- a/src/app/api/providers/validate/route.js +++ b/src/app/api/providers/validate/route.js @@ -151,6 +151,23 @@ export async function POST(request) { } break; } + case "volcengine-ark": { + const testModel = getDefaultModel(provider); + const res = await fetch("https://ark.cn-beijing.volces.com/api/coding/v3/chat/completions", { + method: "POST", + headers: { + "Authorization": `Bearer ${apiKey}`, + "content-type": "application/json", + }, + body: JSON.stringify({ + model: testModel, + max_tokens: 1, + messages: [{ role: "user", content: "test" }], + }), + }); + isValid = res.status !== 401 && res.status !== 403; + break; + } case "deepseek": case "groq": diff --git a/src/shared/constants/config.js b/src/shared/constants/config.js index cf9003e2..73f334ad 100644 --- a/src/shared/constants/config.js +++ b/src/shared/constants/config.js @@ -56,6 +56,7 @@ export const PROVIDER_ENDPOINTS = { "minimax-cn": "https://api.minimaxi.com/anthropic/v1/messages", alicode: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", "alicode-intl": "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions", + "volcengine-ark": "https://ark.cn-beijing.volces.com/api/coding/v3/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 a024080e..6830be8b 100644 --- a/src/shared/constants/providers.js +++ b/src/shared/constants/providers.js @@ -59,6 +59,7 @@ export const APIKEY_PROVIDERS = { "minimax-cn": { id: "minimax-cn", alias: "minimax-cn", name: "Minimax (China)", icon: "memory", color: "#DC2626", textIcon: "MC", website: "https://www.minimaxi.com" }, alicode: { id: "alicode", alias: "alicode", name: "Alibaba", icon: "cloud", color: "#FF6A00", textIcon: "ALi" }, "alicode-intl": { id: "alicode-intl", alias: "alicode-intl", name: "Alibaba Intl", icon: "cloud", color: "#FF6A00", textIcon: "ALi" }, + "volcengine-ark": { id: "volcengine-ark", alias: "ark", name: "Volcengine Ark", icon: "cloud", color: "#1677FF", textIcon: "ARK", website: "https://ark.cn-beijing.volces.com" }, openai: { id: "openai", alias: "openai", name: "OpenAI", icon: "auto_awesome", color: "#10A37F", textIcon: "OA", website: "https://platform.openai.com", serviceKinds: ["llm", "embedding", "tts", "image", "imageToText", "webSearch"], thinkingConfig: THINKING_CONFIG.effort }, anthropic: { id: "anthropic", alias: "anthropic", name: "Anthropic", icon: "smart_toy", color: "#D97757", textIcon: "AN", website: "https://console.anthropic.com", serviceKinds: ["llm", "imageToText"] }, "opencode-go": { id: "opencode-go", alias: "ocg", name: "OpenCode Go", icon: "terminal", color: "#E87040", textIcon: "OC", website: "https://opencode.ai/auth", notice: { text: "OpenCode Go subscription: $5/mo (then $10/mo). Access to Kimi, GLM, Qwen, MiMo, MiniMax models.", apiKeyUrl: "https://opencode.ai/auth" } },