From b04c03c6b513677da120596f881d611c3d42eeb2 Mon Sep 17 00:00:00 2001 From: Nguyen Thanh Dat Date: Fri, 14 Aug 2026 16:29:06 +0700 Subject: [PATCH] feat(providers): add Alibaba Token Plan (token-plan.ap-southeast-1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fourth Alibaba key type — Coding Plan (alicode/alicode-intl) and Model Studio (alims-intl) both reject Token Plan keys. Registry entry only; PROVIDER_MODELS builds from providers/registry so no executor or translator work is needed. Singapore-only (eu-central-1 answers IllegalEndpoint) and OpenAI-compatible transport only (the Anthropic surface is not authorized for this plan). Closes #2754 Closes #2806 --- open-sse/providers/registry/alitp-intl.js | 35 +++++++++++++++ open-sse/providers/registry/index.js | 2 + tests/__baseline__/alias-baseline.json | 2 + tests/__baseline__/providers-baseline.json | 10 ++++- .../unit/alibaba-token-plan-provider.test.js | 45 +++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 open-sse/providers/registry/alitp-intl.js create mode 100644 tests/unit/alibaba-token-plan-provider.test.js diff --git a/open-sse/providers/registry/alitp-intl.js b/open-sse/providers/registry/alitp-intl.js new file mode 100644 index 00000000..bebc4d7f --- /dev/null +++ b/open-sse/providers/registry/alitp-intl.js @@ -0,0 +1,35 @@ +// Token Plan — credit subscription keys on token-plan..maas.aliyuncs.com. +// Fourth Alibaba key type: Coding Plan (alicode/alicode-intl) and Model Studio +// (alims-intl) both reject these keys, and they reject Model Studio keys back. +// Singapore is the only region that serves the plan; eu-central-1 answers +// IllegalEndpoint. The Anthropic surface (/apps/anthropic/v1/messages) is not +// authorized for this plan, so OpenAI-compatible mode is the only transport. +export default { + id: "alitp-intl", + priority: 11, + alias: "alitp-intl", + display: { + name: "Alibaba Token Plan", + icon: "cloud", + color: "#FF6A00", + textIcon: "ATP", + website: "https://www.alibabacloud.com/campaign/ai-landing-page-token", + notice: { + apiKeyUrl: "https://modelstudio.console.alibabacloud.com/?apiKey=1", + }, + }, + category: "apikey", + transport: { + baseUrl: "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions", + headers: {}, + quirks: { preserveCacheControl: true }, + }, + models: [ + { id: "qwen3.8-max-preview", name: "Qwen3.8 Max Preview" }, + { id: "qwen3.7-max", name: "Qwen3.7 Max" }, + { id: "qwen3.7-plus", name: "Qwen3.7 Plus" }, + { id: "qwen3.6-flash", name: "Qwen3.6 Flash" }, + { id: "glm-5.2", name: "GLM 5.2" }, + { id: "deepseek-v4-pro", name: "DeepSeek V4 Pro" }, + ], +}; diff --git a/open-sse/providers/registry/index.js b/open-sse/providers/registry/index.js index 3adffde5..6482293a 100644 --- a/open-sse/providers/registry/index.js +++ b/open-sse/providers/registry/index.js @@ -120,6 +120,7 @@ import p117 from "./selfhosted-stt.js"; import p118 from "./selfhosted-tts.js"; import p119 from "./selfhosted-embedding.js"; import p120 from "./fish-audio.js"; +import p121 from "./alitp-intl.js"; export default [ p0, @@ -241,4 +242,5 @@ export default [ p118, p119, p120, + p121, ]; diff --git a/tests/__baseline__/alias-baseline.json b/tests/__baseline__/alias-baseline.json index eda1604e..ae3a452f 100644 --- a/tests/__baseline__/alias-baseline.json +++ b/tests/__baseline__/alias-baseline.json @@ -122,6 +122,7 @@ "alicode": "alicode", "alicode-intl": "alicode-intl", "alims-intl": "alims-intl", + "alitp-intl": "alitp-intl", "anthropic": "anthropic", "antigravity": "ag", "api-airforce": "af", @@ -206,6 +207,7 @@ "alicode", "alicode-intl", "alims-intl", + "alitp-intl", "anthropic", "assemblyai", "black-forest-labs", diff --git a/tests/__baseline__/providers-baseline.json b/tests/__baseline__/providers-baseline.json index 7cc326c9..9f814a9c 100644 --- a/tests/__baseline__/providers-baseline.json +++ b/tests/__baseline__/providers-baseline.json @@ -968,7 +968,15 @@ "tokenrouter": { "baseUrl": "https://api.tokenrouter.com/v1/chat/completions", "validateUrl": "https://api.tokenrouter.com/v1/models", - "thinkingFormat": "openai", + "thinkingFormat": "tokenrouter", + "format": "openai" + }, + "alitp-intl": { + "baseUrl": "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions", + "headers": {}, + "quirks": { + "preserveCacheControl": true + }, "format": "openai" } } \ No newline at end of file diff --git a/tests/unit/alibaba-token-plan-provider.test.js b/tests/unit/alibaba-token-plan-provider.test.js new file mode 100644 index 00000000..bd3e7c02 --- /dev/null +++ b/tests/unit/alibaba-token-plan-provider.test.js @@ -0,0 +1,45 @@ +import { describe, expect, it } from "vitest"; + +import REGISTRY from "../../open-sse/providers/registry/index.js"; +import { PROVIDERS, PROVIDER_MODELS } from "../../open-sse/providers/index.js"; + +describe("Alibaba Token Plan provider", () => { + const entry = REGISTRY.find((e) => e.id === "alitp-intl"); + + it("is registered as an OpenAI-compatible apikey provider", () => { + expect(entry).toBeDefined(); + expect(entry.category).toBe("apikey"); + expect(PROVIDERS["alitp-intl"]).toBeDefined(); + expect(PROVIDERS["alitp-intl"].format).toBe("openai"); + }); + + it("targets the Singapore Token Plan host in compatible mode", () => { + // eu-central-1 answers IllegalEndpoint; the plan is Singapore-only. + expect(PROVIDERS["alitp-intl"].baseUrl).toBe( + "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions", + ); + }); + + it("does not collide with the other three Alibaba key types", () => { + const hosts = ["alicode", "alicode-intl", "alims-intl", "alitp-intl"] + .map((id) => new URL(PROVIDERS[id].baseUrl).host); + expect(new Set(hosts).size).toBe(hosts.length); + }); + + it("exposes the models the plan actually serves", () => { + const ids = (PROVIDER_MODELS["alitp-intl"] || []).map((m) => m.id); + expect(ids).toEqual(expect.arrayContaining([ + "qwen3.8-max-preview", + "qwen3.7-max", + "qwen3.7-plus", + "qwen3.6-flash", + "glm-5.2", + "deepseek-v4-pro", + ])); + }); + + it("keeps every registry id unique after adding the provider", () => { + const ids = REGISTRY.map((e) => e.id); + expect(new Set(ids).size).toBe(ids.length); + }); +});