Skip to content

Commit 4ca3e2d

Browse files
committed
feat(config): update token-plan default models
- switch the default text model to qwen3.8-max-preview - add dedicated T2V, I2V, and R2V model defaults - persist and consume per-mode video model settings - enable thinking when validating the qwen3.8 preview model
1 parent 12ecac4 commit 4ca3e2d

17 files changed

Lines changed: 251 additions & 40 deletions

File tree

docs/token-plan-profile-integration.md

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ token-plan assign-seats
2727
token-plan add-member
2828
```
2929

30-
这些命令属于管理面,继续使用 OpenAPI AK/SK。本方案增加的是模型消费面:用户把 `create-key` 获得的 `PlainApiKey` 保存到 Profile,然后通过现有文本和图片命令调用模型
30+
这些命令属于管理面,继续使用 OpenAPI AK/SK。本方案增加的是模型消费面:用户把 `create-key` 获得的 `PlainApiKey` 保存到 Profile,然后通过现有文本、图片和视频命令调用模型
3131

3232
```text
3333
OpenAPI AK/SK
@@ -42,7 +42,7 @@ OpenAPI AK/SK
4242
- 将 Token Plan 模型 API Key 作为普通 `apiKey` credential 使用。
4343
-`token-plan` 作为内置命名 Profile 管理。
4444
- 支持 Config 激活状态和默认切换。
45-
- 复用现有文本、图片命令与 Client。
45+
- 复用现有文本、图片、视频命令与 Client。
4646
- 对所有来源的模型 Base URL 做统一归一化。
4747
- 登录验证成功后原子保存 API Key 和 Base URL。
4848
- 服务端错误保持原消息,不在 CLI 内翻译。
@@ -52,7 +52,7 @@ OpenAPI AK/SK
5252
- 不重写现有 Token Plan 管控命令。
5353
- 不把模型消费 API Key 合并到 OpenAPI AK/SK 鉴权域。
5454
- 不新增 Token Plan 专用 Client。
55-
- 基础阶段不承诺视频、语音和音频模型消费
55+
- 基础阶段不承诺语音和音频模型消费
5656
- 暂不维护会阻断请求的本地模型白名单。
5757
- 暂不把服务端错误翻译成 CLI 自定义错误。
5858

@@ -76,7 +76,10 @@ CLI 应解析并保存以下配置:
7676
"token-plan": {
7777
"api_key": "<TOKEN_PLAN_API_KEY>",
7878
"base_url": "https://token-plan.cn-beijing.maas.aliyuncs.com",
79-
"default_text_model": "qwen3.7-max",
79+
"default_text_model": "qwen3.8-max-preview",
80+
"default_video_model": "happyhorse-1.1-t2v",
81+
"default_image_to_video_model": "happyhorse-1.1-i2v",
82+
"default_reference_to_video_model": "happyhorse-1.1-r2v",
8083
"default_image_model": "qwen-image-2.0"
8184
}
8285
}
@@ -237,8 +240,11 @@ Config 激活只改变配置文件 block 的选择,`--config` 本身不提升
237240
`token-plan` 是允许用户选择的内置 Profile 名,不应加入非法名称列表。它提供以下默认值:
238241

239242
```text
240-
base_url: https://token-plan.cn-beijing.maas.aliyuncs.com
241-
default_text_model: qwen3.7-max
243+
base_url: https://token-plan.cn-beijing.maas.aliyuncs.com
244+
default_text_model: qwen3.8-max-preview
245+
default_video_model: happyhorse-1.1-t2v
246+
default_image_to_video_model: happyhorse-1.1-i2v
247+
default_reference_to_video_model: happyhorse-1.1-r2v
242248
default_image_model: qwen-image-2.0
243249
```
244250

@@ -253,15 +259,18 @@ Token Plan Base URL 预设只在登录写入阶段提供最低优先级的缺省
253259

254260
登录成功时应把显式 Base URL 或缺失的预设 Base URL,以及默认模型写入 Profile,使 `config show --config token-plan` 能看到完整配置。环境变量不复制进 Profile。运行时不再合并预设;如果手工删除字段,则按统一的环境变量、配置文件和系统默认值链继续解析。
255261

256-
默认模型采用更简单的固定策略:每次执行 `auth login --config token-plan`,都将 `default_text_model` 重置为 `qwen3.7-max`,将 `default_image_model` 重置为 `qwen-image-2.0`。登录不保留用户之前写入的其他 Profile 默认模型;用户需要临时调用其他 Token Plan 模型时,通过具体模型命令的 `--model` 覆盖,不修改这两个内置默认值
262+
默认模型采用更简单的固定策略:每次执行 `auth login --config token-plan`,都将 `default_text_model` 重置为 `qwen3.8-max-preview`,将 `default_video_model` 重置为 `happyhorse-1.1-t2v`,将 `default_image_to_video_model` 重置为 `happyhorse-1.1-i2v`,将 `default_reference_to_video_model` 重置为 `happyhorse-1.1-r2v`,将 `default_image_model` 重置为 `qwen-image-2.0`。登录不保留用户之前写入的其他 Profile 默认模型;用户需要临时调用其他 Token Plan 模型时,通过具体模型命令的 `--model` 覆盖,不修改这些内置默认值
257263

258264
预设建议通过集中 registry 表达,不在 resolver、命令和 Client 中散落名称判断:
259265

260266
```ts
261267
const MODEL_PROFILE_PRESETS = {
262268
"token-plan": {
263269
baseUrl: "https://token-plan.cn-beijing.maas.aliyuncs.com",
264-
defaultTextModel: "qwen3.7-max",
270+
defaultTextModel: "qwen3.8-max-preview",
271+
defaultVideoModel: "happyhorse-1.1-t2v",
272+
defaultImageToVideoModel: "happyhorse-1.1-i2v",
273+
defaultReferenceToVideoModel: "happyhorse-1.1-r2v",
265274
defaultImageModel: "qwen-image-2.0",
266275
},
267276
};
@@ -363,20 +372,23 @@ image: <base_url>/api/v1/services/aigc/.../generation
363372
}
364373
```
365374

366-
登录验证使用的模型必须在目标 Profile 中可用。基础阶段 Token Plan 预设使用 `qwen3.7-max`;后续如不同订阅计划的模型集合分化,应将验证模型纳入 Profile 预设,而不是继续在登录函数里硬编码唯一模型。
375+
登录验证使用的模型必须在目标 Profile 中可用。Token Plan 预设使用 `qwen3.8-max-preview`;后续如不同订阅计划的模型集合分化,应将验证模型纳入 Profile 预设,而不是继续在登录函数里硬编码唯一模型。
367376

368377
## 模型消费范围
369378

370379
基础阶段承诺:
371380

372-
| 能力 | 默认模型 | 调用方式 |
373-
| -------------- | ---------------- | ---------------------------------- |
374-
| 文本生成和推理 | `qwen3.7-max` | OpenAI Compatible Chat Completions |
375-
| 图片生成和编辑 | `qwen-image-2.0` | DashScope 原生图片接口 |
381+
| 能力 | 默认模型 | 调用方式 |
382+
| -------------- | --------------------- | ---------------------------------- |
383+
| 文本生成和推理 | `qwen3.8-max-preview` | OpenAI Compatible Chat Completions |
384+
| 图片生成和编辑 | `qwen-image-2.0` | DashScope 原生图片接口 |
385+
| 文生视频 | `happyhorse-1.1-t2v` | DashScope 原生视频接口 |
386+
| 图生视频 | `happyhorse-1.1-i2v` | `bl video generate --image` |
387+
| 参考生视频 | `happyhorse-1.1-r2v` | `bl video ref` |
376388

377-
Token Plan 当前模型快照中还包含其他文本、视觉理解和图片模型,但该列表可能由后端调整。基础接入不维护阻断请求的本地白名单;用户可通过具体模型命令的 `--model` 临时覆盖本次请求,但再次登录时 Profile 默认模型仍重置为内置版本。
389+
Token Plan 当前模型快照中还包含其他文本、视觉理解、图片和视频模型,但该列表可能由后端调整。基础接入不维护阻断请求的本地白名单;用户可通过具体模型命令的 `--model` 临时覆盖本次请求,但再次登录时 Profile 默认模型仍重置为内置版本。
378390

379-
视频、语音和音频不作为本阶段支持承诺。现有命令仍保持通用实现,但 Token Plan Profile 的验收不包含这些模态。
391+
语音和音频不作为本阶段支持承诺。现有命令仍保持通用实现,但 Token Plan Profile 的验收不包含这些模态。
380392

381393
## 错误处理
382394

@@ -408,9 +420,9 @@ feat(core): add token-plan model profile preset
408420
完成内容:
409421

410422
-`token-plan` 注册为内置、可选择的 Profile 名。
411-
- 提供 canonical 默认 Base URL、文本模型和图片模型
423+
- 提供 canonical 默认 Base URL、文本模型、图片模型和视频模型
412424
- Base URL 登录验证遵循 flag > 环境变量 > 已保存 Profile > 预设;环境变量不复制进 Profile。
413-
- Profile 缺少 Base URL 时物化预设地址;每次 Token Plan 登录都重置并写入内置默认文本和图片模型
425+
- Profile 缺少 Base URL 时物化预设地址;每次 Token Plan 登录都重置并写入内置默认文本、图片和视频模型
414426
- 运行时 loader/resolver 不再合并预设。
415427
- 不新增 AuthRequirement,不修改 Token Plan 管控命令。
416428
- 补充预设值单元测试;不重复增加 Token Plan 专属消费 E2E。
@@ -431,23 +443,23 @@ feat(auth): support token-plan API key login
431443
- 使用 Token Plan 预设文本模型验证 API Key。
432444
- 登录验证前不写配置。
433445
- 验证成功后一次写入 API Key、canonical Base URL 和默认模型。
434-
- 每次登录都将默认模型重置为 `qwen3.7-max``qwen-image-2.0`
446+
- 每次登录都将默认模型重置为 `qwen3.8-max-preview``qwen-image-2.0``happyhorse-1.1-t2v``happyhorse-1.1-i2v``happyhorse-1.1-r2v`
435447
- 验证失败不留下半配置。
436448
- 补充一个最小 Token Plan 登录 E2E,覆盖命名 Profile 落盘、环境变量不复制、预设 Base URL 物化和默认模型重置;通用 API Key 登录 E2E 继续覆盖成功原子保存和失败不写半配置。
437449
- 该 commit 暂不承诺自动归一化用户显式输入的 SDK Base URL。
438450

439-
### Commit 3:Token Plan 文本与图片消费验收(已实现)
451+
### Commit 3:Token Plan 文本、图片与视频消费验收(已实现)
440452

441453
建议提交信息:
442454

443455
```text
444-
feat(cli): enable token-plan text and image consumption
456+
feat(cli): enable token-plan text, image, and video consumption
445457
```
446458

447459
完成内容:
448460

449-
- Token Plan 消费复用现有 API Key、文本和图片调用链,不重复增加专属 E2E。
450-
- 发布前按需人工验证 `auth login --config token-plan --api-key ...`文本和图片调用
461+
- Token Plan 消费复用现有 API Key、文本、图片和视频调用链,不重复增加专属 E2E。
462+
- 发布前按需人工验证 `auth login --config token-plan --api-key ...`文本、图片和视频调用
451463
- 更新 Token Plan 消费方案文档和 Skill reference。
452464
- 到该 commit 为止即可先交付显式 `--config token-plan` 的紧急消费能力。
453465

@@ -475,7 +487,7 @@ feat(config): add active profile selection
475487
- 新增 `bl config use --name <name>`
476488
- `config show``auth status` 展示最终选择项,`config list``config ui` 展示激活状态。
477489
- 删除激活 Profile 时处理状态一致性。
478-
- 验证激活 `token-plan` 后不传 `--config` 的文本和图片请求
490+
- 验证激活 `token-plan` 后不传 `--config` 的文本、图片和视频请求
479491
- 验证临时 `--config default` 不改变激活状态。
480492
- 更新命令导出、`packages/cli/src/commands.ts`、E2E 和生成 reference。
481493

@@ -533,9 +545,10 @@ fix(core): normalize model base URLs across all sources
533545
- `token-plan` 登录初始化时缺省写入官方根地址。
534546
- 显式 Base URL 覆盖预设并经过通用归一化。
535547
- 登录验证失败不写入任何 Token Plan 半配置。
536-
- 文本默认使用 `qwen3.7-max`
548+
- 文本默认使用 `qwen3.8-max-preview`
537549
- 图片默认使用 `qwen-image-2.0`
538-
- 文本和图片均复用现有 `apiKey` Client。
550+
- 视频默认使用 `happyhorse-1.1-t2v`;图生和参考生入口分别使用 `happyhorse-1.1-i2v``happyhorse-1.1-r2v`
551+
- 文本、图片和视频均复用现有 `apiKey` Client。
539552
- 管控命令继续使用 OpenAPI AK/SK,不受模型 Profile 影响。
540553

541554
## 完成后检查

packages/commands/src/commands/auth/login-api-key.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ interface ApiKeyLoginProfile {
2020
baseUrl: string;
2121
persistBaseUrl?: string;
2222
defaultTextModel?: string;
23+
defaultVideoModel?: string;
24+
defaultImageToVideoModel?: string;
25+
defaultReferenceToVideoModel?: string;
2326
defaultImageModel?: string;
2427
persistPatch?: AuthPersistPatch;
2528
}
@@ -54,17 +57,18 @@ export async function validateAndPersistApiKey(
5457
const persistBaseUrl = profile.persistBaseUrl
5558
? normalizeModelBaseUrl(profile.persistBaseUrl)
5659
: undefined;
60+
const validationModel = profile.defaultTextModel || "qwen3.7-max";
5761
const requestOpts = {
5862
url: baseUrl + chatPath(),
5963
method: "POST",
6064
headers: { Authorization: `Bearer ${key}` },
6165
timeout: Math.min(deps.settings.timeout, 30),
6266
body: {
63-
model: profile.defaultTextModel || "qwen3.7-max",
67+
model: validationModel,
6468
messages: [{ role: "user", content: "hi" }],
6569
max_tokens: 1,
6670
stream: false,
67-
enable_thinking: false,
71+
enable_thinking: validationModel === "qwen3.8-max-preview",
6872
},
6973
};
7074

@@ -88,6 +92,9 @@ export async function validateAndPersistApiKey(
8892
api_key: key,
8993
base_url: persistBaseUrl,
9094
default_text_model: profile.defaultTextModel,
95+
default_video_model: profile.defaultVideoModel,
96+
default_image_to_video_model: profile.defaultImageToVideoModel,
97+
default_reference_to_video_model: profile.defaultReferenceToVideoModel,
9198
default_image_model: profile.defaultImageModel,
9299
});
93100
}

packages/commands/src/commands/auth/login.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ export default defineCommand({
150150
baseUrl: resolvedBaseUrl,
151151
persistBaseUrl,
152152
defaultTextModel: profilePreset?.defaultTextModel,
153+
defaultVideoModel: profilePreset?.defaultVideoModel,
154+
defaultImageToVideoModel: profilePreset?.defaultImageToVideoModel,
155+
defaultReferenceToVideoModel: profilePreset?.defaultReferenceToVideoModel,
153156
defaultImageModel: profilePreset?.defaultImageModel,
154157
});
155158
},

packages/commands/src/commands/config/shared.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export const VALID_KEYS = [
1313
"security_token",
1414
"default_text_model",
1515
"default_video_model",
16+
"default_image_to_video_model",
17+
"default_reference_to_video_model",
1618
"default_image_model",
1719
"default_speech_model",
1820
"default_omni_model",
@@ -41,6 +43,8 @@ export const KEY_ALIASES: Record<string, string> = {
4143
"security-token": "security_token",
4244
"default-text-model": "default_text_model",
4345
"default-video-model": "default_video_model",
46+
"default-image-to-video-model": "default_image_to_video_model",
47+
"default-reference-to-video-model": "default_reference_to_video_model",
4448
"default-image-model": "default_image_model",
4549
"default-speech-model": "default_speech_model",
4650
"default-omni-model": "default_omni_model",

packages/commands/src/commands/video/generate.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ export default defineCommand({
103103

104104
const model =
105105
flags.model ||
106-
settings.defaultVideoModel ||
107-
(flags.image ? "happyhorse-1.1-i2v" : "happyhorse-1.1-t2v");
106+
(flags.image
107+
? settings.defaultImageToVideoModel || "happyhorse-1.1-i2v"
108+
: settings.defaultVideoModel || "happyhorse-1.1-t2v");
108109
const format = detectOutputFormat(settings.output);
109110

110111
const imageUrl = flags.image;

packages/commands/src/commands/video/ref.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export default defineCommand({
117117
const imageVoices = flags.imageVoice || [];
118118
const videoVoices = flags.videoVoice || [];
119119

120-
const model = flags.model || "happyhorse-1.1-r2v";
120+
const model = flags.model || settings.defaultReferenceToVideoModel || "happyhorse-1.1-r2v";
121121
const format = detectOutputFormat(settings.output);
122122

123123
// --- Resolve file URLs (auto-upload local files) ---

packages/commands/tests/config-ui.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ test("GET /api/config 返回全部 profile、明文密钥与持久化激活项",
8181
expect(res.json.default).toMatchObject({ api_key: "sk-default", output: "json" });
8282
expect(res.json.named.dev).toMatchObject({ api_key: "sk-dev", access_token: "tok-dev" });
8383
expect(res.json.secretKeys).toContain("api_key");
84+
expect(res.json.keys).toContain("default_image_to_video_model");
85+
expect(res.json.keys).toContain("default_reference_to_video_model");
8486
});
8587
});
8688

packages/commands/tests/e2e/auth.e2e.test.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,10 @@ describe("e2e: auth", () => {
267267
expect(config["token-plan"]).toMatchObject({
268268
api_key: "sk-sp-e2e-placeholder",
269269
base_url: validationServer.baseUrl,
270-
default_text_model: "qwen3.7-max",
270+
default_text_model: "qwen3.8-max-preview",
271+
default_video_model: "happyhorse-1.1-t2v",
272+
default_image_to_video_model: "happyhorse-1.1-i2v",
273+
default_reference_to_video_model: "happyhorse-1.1-r2v",
271274
default_image_model: "qwen-image-2.0",
272275
});
273276
} finally {
@@ -284,6 +287,9 @@ describe("e2e: auth", () => {
284287
{
285288
"token-plan": {
286289
default_text_model: "custom-text-model",
290+
default_video_model: "custom-video-model",
291+
default_image_to_video_model: "custom-image-to-video-model",
292+
default_reference_to_video_model: "custom-reference-to-video-model",
287293
default_image_model: "custom-image-model",
288294
},
289295
},
@@ -309,9 +315,9 @@ describe("e2e: auth", () => {
309315
authorization: "Bearer sk-sp-e2e-placeholder",
310316
sourceConfig: expect.any(String),
311317
body: {
312-
model: "qwen3.7-max",
318+
model: "qwen3.8-max-preview",
313319
stream: false,
314-
enable_thinking: false,
320+
enable_thinking: true,
315321
},
316322
});
317323

@@ -324,7 +330,10 @@ describe("e2e: auth", () => {
324330
expect(config["token-plan"]).toMatchObject({
325331
api_key: "sk-sp-e2e-placeholder",
326332
base_url: "https://token-plan.cn-beijing.maas.aliyuncs.com",
327-
default_text_model: "qwen3.7-max",
333+
default_text_model: "qwen3.8-max-preview",
334+
default_video_model: "happyhorse-1.1-t2v",
335+
default_image_to_video_model: "happyhorse-1.1-i2v",
336+
default_reference_to_video_model: "happyhorse-1.1-r2v",
328337
default_image_model: "qwen-image-2.0",
329338
});
330339
expect((config["token-plan"] as Record<string, unknown>).base_url).not.toBe(

packages/commands/tests/e2e/config.e2e.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,44 @@ describe("e2e: config", () => {
299299
expect(data.would_set?.default_text_model).toBe("qwen3.7-max");
300300
});
301301

302+
test("config set --dry-run 支持图生视频默认模型别名", async () => {
303+
const { stdout, stderr, exitCode } = await runCommandE2e(CONFIG_ROUTES, [
304+
"config",
305+
"set",
306+
"--dry-run",
307+
"--key",
308+
"default-image-to-video-model",
309+
"--value",
310+
"happyhorse-1.1-i2v",
311+
"--output",
312+
"json",
313+
]);
314+
expect(exitCode, stderr).toBe(0);
315+
const data = parseStdoutJson<{
316+
would_set?: { default_image_to_video_model?: string };
317+
}>(stdout);
318+
expect(data.would_set?.default_image_to_video_model).toBe("happyhorse-1.1-i2v");
319+
});
320+
321+
test("config set --dry-run 支持参考生视频默认模型别名", async () => {
322+
const { stdout, stderr, exitCode } = await runCommandE2e(CONFIG_ROUTES, [
323+
"config",
324+
"set",
325+
"--dry-run",
326+
"--key",
327+
"default-reference-to-video-model",
328+
"--value",
329+
"happyhorse-1.1-r2v",
330+
"--output",
331+
"json",
332+
]);
333+
expect(exitCode, stderr).toBe(0);
334+
const data = parseStdoutJson<{
335+
would_set?: { default_reference_to_video_model?: string };
336+
}>(stdout);
337+
expect(data.would_set?.default_reference_to_video_model).toBe("happyhorse-1.1-r2v");
338+
});
339+
302340
test("config set --dry-run 展示归一化后的 Base URL", async () => {
303341
const { stdout, stderr, exitCode } = await runCommandE2e(CONFIG_ROUTES, [
304342
"config",

0 commit comments

Comments
 (0)