feat(providers): refresh Qwen3.8 model catalogs (#10226)

This commit is contained in:
backryun
2026-08-18 22:57:20 +09:00
committed by GitHub
parent 7f6958960c
commit acd740908f
10 changed files with 54 additions and 37 deletions

View File

@@ -369,7 +369,7 @@ export const FREE_MODEL_BUDGETS: FreeModelBudget[] = [
{ provider: "qoder", modelId: "deepseek-v4-pro", displayName: "DeepSeek-V4-Pro", monthlyTokens: 0, creditTokens: 1000000, freeType: "one-time-initial", poolKey: "qoder", tos: "caution" },
{ provider: "qoder", modelId: "deepseek-v4-flash", displayName: "DeepSeek-V4-Flash", monthlyTokens: 0, creditTokens: 1000000, freeType: "one-time-initial", poolKey: "qoder", tos: "caution" },
{ provider: "qoder", modelId: "minimax-m3", displayName: "MiniMax-M3", monthlyTokens: 0, creditTokens: 1000000, freeType: "one-time-initial", poolKey: "qoder", tos: "caution" },
{ provider: "qwen-web", modelId: "qwen3.8-max-preview", displayName: "Qwen3.8 Max Preview", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "qwen-web", tos: "avoid" },
{ provider: "qwen-web", modelId: "qwen3.8-max", displayName: "Qwen3.8 Max", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "qwen-web", tos: "avoid" },
{ provider: "qwen-web", modelId: "qwen3.7-max", displayName: "Qwen3.7 Max", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "qwen-web", tos: "avoid" },
{ provider: "qwen-web", modelId: "qwen3.7-plus", displayName: "Qwen3.7 Plus", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "qwen-web", tos: "avoid" },
{ provider: "qwen-web", modelId: "qwen3.6-plus", displayName: "Qwen3.6 Plus", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "qwen-web", tos: "avoid" },

View File

@@ -1,6 +1,7 @@
import type { RegistryEntry, RegistryModel } from "../../shared.ts";
export const ALIBABA_MODEL_STUDIO_MODELS: RegistryModel[] = [
{ id: "qwen3.8-max", name: "Qwen3.8 Max" },
{ id: "qwen3.7-max", name: "Qwen3.7 Max" },
{ id: "qwen3.7-plus", name: "Qwen3.7 Plus" },
{ id: "qwen3.6-plus", name: "Qwen3.6 Plus" },

View File

@@ -32,7 +32,7 @@ export const clinepassProvider: RegistryEntry = {
"HTTP-Referer": "https://cline.bot",
"X-Title": "Cline",
},
// Offline fallback copied from Cline CLI 3.0.46's generated catalog. Live
// Offline fallback copied from Cline CLI 3.0.53's generated catalog. Live
// discovery replaces it with the authored recommended-models order.
models: [
{
@@ -111,6 +111,15 @@ export const clinepassProvider: RegistryEntry = {
maxInputTokens: 1048576,
maxOutputTokens: 131072,
},
{
id: "cline-pass/qwen3.8-max",
name: "Qwen3.8 Max",
toolCalling: true,
supportsReasoning: true,
contextLength: 1000000,
maxInputTokens: 1000000,
maxOutputTokens: 65536,
},
{
id: "cline-pass/qwen3.7-max",
name: "Qwen3.7 Max",

View File

@@ -11,13 +11,13 @@ export const qwen_cloud_token_planProvider: RegistryEntry = {
authHeader: "bearer",
models: [
{
id: "qwen3.8-max-preview",
name: "Qwen3.8 Max Preview",
id: "qwen3.8-max",
name: "Qwen3.8 Max",
supportsReasoning: true,
supportsVision: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 65_536,
maxOutputTokens: 131_072,
},
{
id: "qwen3.7-max",
@@ -25,7 +25,7 @@ export const qwen_cloud_token_planProvider: RegistryEntry = {
supportsReasoning: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 65_536,
maxOutputTokens: 131_072,
},
{
id: "qwen3.7-plus",
@@ -34,7 +34,7 @@ export const qwen_cloud_token_planProvider: RegistryEntry = {
supportsVision: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 65_536,
maxOutputTokens: 131_072,
},
{
id: "qwen3.6-flash",
@@ -43,7 +43,7 @@ export const qwen_cloud_token_planProvider: RegistryEntry = {
supportsVision: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 32_768,
maxOutputTokens: 65_536,
},
{
id: "glm-5.2",
@@ -51,15 +51,23 @@ export const qwen_cloud_token_planProvider: RegistryEntry = {
supportsReasoning: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 16_384,
maxOutputTokens: 131_072,
},
{
id: "deepseek-v4-pro",
name: "DeepSeek V4 Pro",
supportsReasoning: true,
toolCalling: true,
contextLength: 163_840,
maxOutputTokens: 32_768,
contextLength: 1_000_000,
maxOutputTokens: 393_216,
},
{
id: "deepseek-v4-flash-0731",
name: "DeepSeek V4 Flash",
supportsReasoning: true,
toolCalling: true,
contextLength: 1_000_000,
maxOutputTokens: 393_216,
},
],
};

View File

@@ -1,6 +1,7 @@
import type { RegistryEntry, RegistryModel } from "../../shared.ts";
export const QWEN_CLOUD_TEXT_MODELS: RegistryModel[] = [
{ id: "qwen3.8-max", name: "Qwen3.8 Max" },
{ id: "qwen3.7-max-2026-06-08", name: "Qwen3.7 Max (2026-06-08)" },
{ id: "qwen3.7-plus", name: "Qwen3.7 Plus" },
{ id: "qwen3.6-plus", name: "Qwen3.6 Plus" },

View File

@@ -17,13 +17,13 @@ export const qwen_webProvider: RegistryEntry = {
// MODEL_ALIASES map for backward compatibility.
models: [
{
id: "qwen3.8-max-preview",
name: "Qwen3.8 Max Preview",
id: "qwen3.8-max",
name: "Qwen3.8 Max",
toolCalling: false,
supportsReasoning: true,
supportsVision: true,
contextLength: 1_000_000,
maxOutputTokens: 65_536,
maxOutputTokens: 131_072,
},
{
id: "qwen3.7-max",

View File

@@ -58,6 +58,7 @@ const MODEL_ALIASES: Record<string, string> = {
"qwen3-plus": "qwen3.7-plus",
"qwen3-max": "qwen3.7-max",
"qwen3-flash": "qwen3.6-plus",
"qwen3.8-max-preview": "qwen3.8-max",
// Note: `qwen3-coder-plus` is a real upstream model id (Qwen3-Coder) and
// must NOT be aliased — the previous `"qwen3-coder-plus": "qwen3.7-max"`
// entry silently rewrote valid coder requests to the wrong model.
@@ -67,7 +68,7 @@ const MODEL_ALIASES: Record<string, string> = {
};
const DEFAULT_MODEL = "qwen3.7-max";
const REQUIRED_THINKING_MODELS = new Set(["qwen3.8-max-preview"]);
const REQUIRED_THINKING_MODELS = new Set(["qwen3.8-max"]);
function mapModel(modelId: string): string {
return MODEL_ALIASES[modelId] || modelId;

View File

@@ -208,6 +208,7 @@ test("Qwen Cloud is a first-class metered API-key provider", () => {
assert.deepEqual(
REGISTRY["qwen-cloud"].models.map((model) => model.id),
[
"qwen3.8-max",
"qwen3.7-max-2026-06-08",
"qwen3.7-plus",
"qwen3.6-plus",
@@ -227,6 +228,7 @@ test("Qwen Cloud is a first-class metered API-key provider", () => {
test("Alibaba Model Studio exposes the curated modern text catalog", () => {
const expectedModels = [
"qwen3.8-max",
"qwen3.7-max",
"qwen3.7-plus",
"qwen3.6-plus",
@@ -276,19 +278,20 @@ test("Qwen Cloud Token Plan remains a flat-rate provider with chat models only",
const modelIds = REGISTRY["qwen-cloud-token-plan"].models.map((model) => model.id);
assert.deepEqual(modelIds, [
"qwen3.8-max-preview",
"qwen3.8-max",
"qwen3.7-max",
"qwen3.7-plus",
"qwen3.6-flash",
"glm-5.2",
"deepseek-v4-pro",
"deepseek-v4-flash-0731",
]);
const preview = REGISTRY["qwen-cloud-token-plan"].models[0];
assert.equal(preview.supportsReasoning, true);
assert.equal(preview.supportsVision, true);
assert.equal(preview.contextLength, 1_000_000);
assert.equal(preview.maxOutputTokens, 65_536);
const qwen38 = REGISTRY["qwen-cloud-token-plan"].models[0];
assert.equal(qwen38.supportsReasoning, true);
assert.equal(qwen38.supportsVision, true);
assert.equal(qwen38.contextLength, 1_000_000);
assert.equal(qwen38.maxOutputTokens, 131_072);
});
test("dashboard folds legacy China connections into the unified Alibaba card", () => {

View File

@@ -68,6 +68,7 @@ test("ClinePass fallback is the official subscription-only catalog", () => {
"cline-pass/kimi-k2.7-code",
"cline-pass/mimo-v2.5-pro",
"cline-pass/mimo-v2.5",
"cline-pass/qwen3.8-max",
"cline-pass/qwen3.7-max",
"cline-pass/qwen3.7-plus",
]);

View File

@@ -288,24 +288,17 @@ describe("QwenWebExecutor (v2 migration)", () => {
"registry must use v2 endpoint"
);
const ids = provider.models.map((m: any) => m.id);
assert.deepEqual(ids.sort(), [
"qwen3.6-plus",
"qwen3.7-max",
"qwen3.7-plus",
"qwen3.8-max-preview",
]);
assert.deepEqual(ids.sort(), ["qwen3.6-plus", "qwen3.7-max", "qwen3.7-plus", "qwen3.8-max"]);
const qwen38 = provider.models.find(
(model: RegistryModel) => model.id === "qwen3.8-max-preview"
);
const qwen38 = provider.models.find((model: RegistryModel) => model.id === "qwen3.8-max");
assert.deepEqual(qwen38, {
id: "qwen3.8-max-preview",
name: "Qwen3.8 Max Preview",
id: "qwen3.8-max",
name: "Qwen3.8 Max",
toolCalling: false,
supportsReasoning: true,
supportsVision: true,
contextLength: 1_000_000,
maxOutputTokens: 65_536,
maxOutputTokens: 131_072,
});
const qwen37Max = provider.models.find((model: RegistryModel) => model.id === "qwen3.7-max");
@@ -315,7 +308,7 @@ describe("QwenWebExecutor (v2 migration)", () => {
it("free-model catalog lists the current qwen-web ids (not the retired ones)", () => {
const qwenModels = (FREE_MODEL_BUDGETS as any[]).filter((m) => m.provider === "qwen-web");
const ids = qwenModels.map((m) => m.modelId);
assert.ok(ids.includes("qwen3.8-max-preview"), "catalog must list qwen3.8-max-preview");
assert.ok(ids.includes("qwen3.8-max"), "catalog must list qwen3.8-max");
assert.ok(ids.includes("qwen3.7-max"), "catalog must list qwen3.7-max");
assert.ok(!ids.includes("qwen-plus"), "retired qwen-plus must be gone");
assert.ok(
@@ -324,7 +317,7 @@ describe("QwenWebExecutor (v2 migration)", () => {
);
});
it("passes qwen3.8-max-preview through unchanged", async () => {
it("uses qwen3.8-max and maps its preview id for compatibility", async () => {
globalThis.fetch = (async (url: string | URL | Request, init: RequestInit = {}) => {
calls.push({ url: String(url), init });
if (String(url).includes("/api/v2/chats/new")) return chatCreatedResponse();
@@ -347,8 +340,8 @@ describe("QwenWebExecutor (v2 migration)", () => {
const newBody = JSON.parse(calls[0].init.body);
const completionBody = JSON.parse(calls[1].init.body);
assert.deepEqual(newBody.models, ["qwen3.8-max-preview"]);
assert.equal(completionBody.model, "qwen3.8-max-preview");
assert.deepEqual(newBody.models, ["qwen3.8-max"]);
assert.equal(completionBody.model, "qwen3.8-max");
assert.equal(completionBody.messages[0].feature_config.thinking_enabled, true);
assert.equal(completionBody.messages[0].feature_config.auto_thinking, true);
});