fix(alicode-intl): split into Coding Plan + Model Studio providers

8b9cac1 swapped alicode-intl to the DashScope compatible-mode endpoint to
fix #2591 for standard DashScope keys, but that broke Coding Plan keys
(sk-sp-...) which only work on coding-intl.dashscope.aliyuncs.com. The two
key types use two different hosts and are not interchangeable.

- alicode-intl: revert to coding-intl endpoint (Coding Plan keys)
- alims-intl: new provider for dashscope-intl/compatible-mode (standard keys)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
decolua
2026-07-19 16:29:55 +07:00
co-authored by Claude Fable 5
parent c4a120af8f
commit 55628eea02
9 changed files with 86 additions and 19 deletions
+4 -4
View File
@@ -3,18 +3,18 @@ export default {
priority: 10, priority: 10,
alias: "alicode-intl", alias: "alicode-intl",
display: { display: {
name: "Alibaba Intl", name: "Alibaba Coding",
icon: "cloud", icon: "cloud",
color: "#FF6A00", color: "#FF6A00",
textIcon: "ALi", textIcon: "ALi",
website: "https://modelstudio.console.alibabacloud.com", website: "https://www.alibabacloud.com/product/coding",
notice: { notice: {
apiKeyUrl: "https://modelstudio.console.alibabacloud.com/?apiKey=1", apiKeyUrl: "https://www.alibabacloud.com/product/coding",
}, },
}, },
category: "apikey", category: "apikey",
transport: { transport: {
baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions", baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions",
headers: {}, headers: {},
quirks: { preserveCacheControl: true }, quirks: { preserveCacheControl: true },
}, },
+32
View File
@@ -0,0 +1,32 @@
// Model Studio Intl — standard DashScope API keys (sk-...), NOT Coding Plan keys.
// Sibling of alicode-intl (Coding Plan). Two key types use two different hosts.
export default {
id: "alims-intl",
priority: 11,
alias: "alims-intl",
display: {
name: "Alibaba Studio",
icon: "cloud",
color: "#FF6A00",
textIcon: "ALi",
website: "https://modelstudio.console.alibabacloud.com",
notice: {
apiKeyUrl: "https://modelstudio.console.alibabacloud.com/?apiKey=1",
},
},
category: "apikey",
transport: {
baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
headers: {},
quirks: { preserveCacheControl: true },
},
models: [
{ 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-coder-next", name: "Qwen3 Coder Next" },
{ id: "qwen3-coder-plus", name: "Qwen3 Coder Plus" },
{ id: "glm-4.7", name: "GLM 4.7" },
],
};
+2
View File
@@ -98,6 +98,7 @@ import p95 from "./xai.js";
import p96 from "./xiaomi-mimo.js"; import p96 from "./xiaomi-mimo.js";
import p97 from "./xiaomi-tokenplan.js"; import p97 from "./xiaomi-tokenplan.js";
import p98 from "./youcom.js"; import p98 from "./youcom.js";
import p99 from "./alims-intl.js";
export default [ export default [
p0, p0,
@@ -199,4 +200,5 @@ export default [
p96, p96,
p97, p97,
p98, p98,
p99,
]; ];
@@ -229,6 +229,14 @@ const PROVIDER_MODELS_CONFIG = {
authPrefix: "Bearer ", authPrefix: "Bearer ",
parseResponse: (data) => data.data || [] parseResponse: (data) => data.data || []
}, },
"alims-intl": {
url: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/models",
method: "GET",
headers: { "Content-Type": "application/json" },
authHeader: "Authorization",
authPrefix: "Bearer ",
parseResponse: (data) => data.data || []
},
"volcengine-ark": createOpenAIModelsConfig("https://ark.cn-beijing.volces.com/api/coding/v3/models"), "volcengine-ark": createOpenAIModelsConfig("https://ark.cn-beijing.volces.com/api/coding/v3/models"),
byteplus: createOpenAIModelsConfig("https://ark.ap-southeast.bytepluses.com/api/coding/v3/models"), byteplus: createOpenAIModelsConfig("https://ark.ap-southeast.bytepluses.com/api/coding/v3/models"),
+5 -2
View File
@@ -620,10 +620,13 @@ async function testApiKeyConnection(connection, effectiveProxy = null) {
return { valid, error: valid ? null : "Invalid API key" }; return { valid, error: valid ? null : "Invalid API key" };
} }
case "alicode": case "alicode":
case "alicode-intl": { case "alicode-intl":
// Aliyun Coding Plan uses OpenAI-compatible API case "alims-intl": {
// Aliyun Coding Plan uses OpenAI-compatible API; alims-intl uses Model Studio compatible-mode
const aliBaseUrl = connection.provider === "alicode-intl" const aliBaseUrl = connection.provider === "alicode-intl"
? "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions" ? "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions"
: connection.provider === "alims-intl"
? "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions"
: "https://coding.dashscope.aliyuncs.com/v1/chat/completions"; : "https://coding.dashscope.aliyuncs.com/v1/chat/completions";
const res = await fetchWithConnectionProxy(aliBaseUrl, { const res = await fetchWithConnectionProxy(aliBaseUrl, {
method: "POST", method: "POST",
+2 -1
View File
@@ -301,11 +301,12 @@ export async function POST(request) {
case "minimax": case "minimax":
case "minimax-cn": case "minimax-cn":
case "alicode-intl": case "alicode-intl":
case "alims-intl":
case "alicode": case "alicode":
case "agentrouter": { case "agentrouter": {
// Use baseUrl from PROVIDERS (DRY); separate openai-format vs claude-format flow // Use baseUrl from PROVIDERS (DRY); separate openai-format vs claude-format flow
const cfg = PROVIDERS[provider]; const cfg = PROVIDERS[provider];
const isOpenAiFormat = provider === "glm-cn" || provider === "alicode" || provider === "alicode-intl"; const isOpenAiFormat = provider === "glm-cn" || provider === "alicode" || provider === "alicode-intl" || provider === "alims-intl";
if (isOpenAiFormat) { if (isOpenAiFormat) {
const testModel = getDefaultModel(provider); const testModel = getDefaultModel(provider);
+2
View File
@@ -98,6 +98,7 @@
"idToAlias": { "idToAlias": {
"alicode": "alicode", "alicode": "alicode",
"alicode-intl": "alicode-intl", "alicode-intl": "alicode-intl",
"alims-intl": "alims-intl",
"anthropic": "anthropic", "anthropic": "anthropic",
"antigravity": "ag", "antigravity": "ag",
"assemblyai": "assemblyai", "assemblyai": "assemblyai",
@@ -168,6 +169,7 @@
"ag", "ag",
"alicode", "alicode",
"alicode-intl", "alicode-intl",
"alims-intl",
"anthropic", "anthropic",
"assemblyai", "assemblyai",
"black-forest-labs", "black-forest-labs",
+9 -1
View File
@@ -1,6 +1,6 @@
{ {
"alicode-intl": { "alicode-intl": {
"baseUrl": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions", "baseUrl": "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions",
"headers": {}, "headers": {},
"quirks": { "quirks": {
"preserveCacheControl": true "preserveCacheControl": true
@@ -872,5 +872,13 @@
} }
} }
] ]
},
"alims-intl": {
"baseUrl": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
"headers": {},
"quirks": {
"preserveCacheControl": true
},
"format": "openai"
} }
} }
+22 -11
View File
@@ -1,24 +1,35 @@
// #2591 — Alibaba Intl (alicode-intl) must use the OpenAI-compatible-mode // #2591 — Alibaba Intl key types split across two hosts:
// DashScope endpoint so standard DashScope API keys work. The previous // - alicode-intl: Coding Plan keys (sk-sp-...) → coding-intl.dashscope.aliyuncs.com
// coding-intl host only accepted Alibaba Coding Plan keys and rejected // - alims-intl: standard DashScope API keys (sk-...) → dashscope-intl.aliyuncs.com/compatible-mode
// ordinary DashScope keys with "Invalid API key". // The two key types are NOT interchangeable across hosts. Split into two providers
// so each key type reaches its own host.
import { describe, it, expect } from "vitest"; import { describe, it, expect } from "vitest";
import alicodeIntl from "../../open-sse/providers/registry/alicode-intl.js"; import alicodeIntl from "../../open-sse/providers/registry/alicode-intl.js";
import alimsIntl from "../../open-sse/providers/registry/alims-intl.js";
describe("alicode-intl endpoint (issue #2591)", () => { describe("alicode-intl endpoint (Coding Plan keys)", () => {
it("routes to the compatible-mode DashScope endpoint", () => { it("routes to the coding-intl host for Coding Plan keys", () => {
expect(alicodeIntl.id).toBe("alicode-intl"); expect(alicodeIntl.id).toBe("alicode-intl");
expect(alicodeIntl.transport.baseUrl).toBe( expect(alicodeIntl.transport.baseUrl).toBe(
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions" "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions"
); );
}); });
it("does not use the coding-intl host that rejects standard keys", () => {
expect(alicodeIntl.transport.baseUrl).not.toContain("coding-intl.dashscope.aliyuncs.com");
});
it("keeps the chat/completions path and preserveCacheControl quirk", () => { it("keeps the chat/completions path and preserveCacheControl quirk", () => {
expect(alicodeIntl.transport.baseUrl).toContain("/v1/chat/completions"); expect(alicodeIntl.transport.baseUrl).toContain("/v1/chat/completions");
expect(alicodeIntl.transport.quirks.preserveCacheControl).toBe(true); expect(alicodeIntl.transport.quirks.preserveCacheControl).toBe(true);
}); });
}); });
describe("alims-intl endpoint (standard DashScope keys)", () => {
it("routes to the compatible-mode DashScope endpoint for standard keys", () => {
expect(alimsIntl.id).toBe("alims-intl");
expect(alimsIntl.transport.baseUrl).toBe(
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions"
);
});
it("does not use the coding-intl host that rejects standard keys", () => {
expect(alimsIntl.transport.baseUrl).not.toContain("coding-intl.dashscope.aliyuncs.com");
});
});