mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
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:
co-authored by
Claude Fable 5
parent
c4a120af8f
commit
55628eea02
@@ -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 },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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" },
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -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"),
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user