Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ CLI 只为「自己能权威解释的错误」发出语义化信号,服务端的

如果命令调用 Console Gateway,`defineCommand` 必须设置 `auth: "console"`。runtime 会基于 `CONSOLE_AUTH_FLAGS` 自动在 help 中展示 `--console-region`、`--console-site`、`--console-switch-agent`、`--workspace-id`,并由 `authStage` 解析/注入 console credential。命令不要重复声明这些凭证域 flag,也不要手动从 env/config 解析 token。

### 5. 禁止单字母变量命名

所有变量、参数、回调形参必须使用有语义的命名,不允许单字母(如 `i`、`m`、`p`、`t`、`e`、`s`)。具体表现:

- 回调参数: `.map((m) => ...)` → `.map((model) => ...)`, `.find((t) => ...)` → `.find((template) => ...)`
- catch 变量: `catch (e)` → `catch (error)`
- for-of 循环: `for (const i of items)` → `for (const item of items)`
- 临时变量: `const s = ...` → `const strategy = ...`

例外: 仅当作用域极小(≤3 行)且语义从上下文完全明确时,可使用 `k`/`v`(Object.entries 的 key/value)。

## 完成改动后的快速验证

```sh
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Equip your AI Agent out-of-the-box with these capabilities, composable across co
- **MCP integration** — Orchestrate Bailian MCP servers: list services, inspect tools, and invoke any tool directly from the terminal
- **Web search** — Real-time internet retrieval for up-to-date, accurate answers
- **Model recommendation** — Describe your scenario and get best-fit model suggestions; supports scoped search, model comparison, and alternative discovery
- **Fine-tuning & deployment** — Upload datasets, create SFT/LoRA/DPO/CPT jobs (`finetune create`), probe job status non-blockingly (`finetune watch`), query per-model training capability (`finetune capability`), and deploy trained models as endpoints (`deploy create`)
- **Fine-tuning & deployment** — Upload datasets, create text/audio/image fine-tune jobs (`finetune text|audio|image create`; text covers SFT/LoRA/DPO/CPT), probe job status non-blockingly (`finetune watch`), query per-model training capability (`finetune capability`), and deploy trained models as endpoints (`deploy text|audio|image create`)
- **Console capabilities** — Browse Bailian apps (`app list`), check free-tier quota (`usage free`), view model usage statistics (`usage stats`), manage workspaces (`workspace list`), and manage rate limits (`quota list/request/check/history`)
- **Local file auto-upload** — Every URL parameter accepts a local path; uploaded to free temp storage with 48-hour validity

Expand Down Expand Up @@ -114,10 +114,10 @@ bl auth login --console

# Fine-tune & deploy — a one-shot train-to-serve workflow
bl dataset upload --file ./train.jsonl # Upload a .jsonl dataset (validated first)
bl finetune create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
bl finetune watch --job-id ft-xxx --output json # Non-blocking status probe (exit 0/1/3 = done/failed/running)
bl finetune capability --model qwen3-8b # Which training types a model supports
bl deploy create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint
bl deploy text create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint

# Browse apps / free-tier quota / usage statistics / workspaces
bl app list
Expand Down
6 changes: 3 additions & 3 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_
- **MCP 集成** — 统一调度百炼 MCP 服务:列出服务、查看工具、直接在终端调用任意工具
- **联网搜索** — 实时互联网信息检索,提升回答准确性及时效性
- **模型推荐** — 描述你的场景,智能推荐最适合的模型;支持限定范围搜索、模型对比和替代发现
- **微调与部署** — 上传数据集、创建 SFT/LoRA/DPO/CPT 调优任务(`finetune create`)、非阻塞探测任务状态(`finetune watch`)、按模型查训练能力(`finetune capability`),并把训练好的模型部署为推理服务(`deploy create`)
- **微调与部署** — 上传数据集、创建文本/音频/图像调优任务(`finetune text|audio|image create`;文本涵盖 SFT/LoRA/DPO/CPT)、非阻塞探测任务状态(`finetune watch`)、按模型查训练能力(`finetune capability`),并把训练好的模型部署为推理服务(`deploy text|audio|image create`)
- **控制台能力** — 浏览百炼应用(`app list`),查询模型免费额度(`usage free`),查看模型用量统计(`usage stats`),管理业务空间(`workspace list`),管理限流与提额(`quota list/request/check/history`)
- **本地文件自动上传** — 所有 URL 参数同时支持本地路径,免费临时存储 48 小时

Expand Down Expand Up @@ -112,10 +112,10 @@ bl auth login --console

# 微调与部署 — 从训练到服务的一站式流程
bl dataset upload --file ./train.jsonl # 上传 .jsonl 数据集(先校验)
bl finetune create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
bl finetune watch --job-id ft-xxx --output json # 非阻塞状态探测(退出码 0/1/3 = 成功/失败/进行中)
bl finetune capability --model qwen3-8b # 查询模型支持哪些训练方式
bl deploy create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务
bl deploy text create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务

# 浏览应用 / 免费额度 / 用量统计 / 业务空间
bl app list
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Equip your AI Agent out-of-the-box with these capabilities, composable across co
- **MCP integration** — Orchestrate Bailian MCP servers: list services, inspect tools, and invoke any tool directly from the terminal
- **Web search** — Real-time internet retrieval for up-to-date, accurate answers
- **Model recommendation** — Describe your scenario and get best-fit model suggestions; supports scoped search, model comparison, and alternative discovery
- **Fine-tuning & deployment** — Upload datasets, create SFT/LoRA/DPO/CPT jobs (`finetune create`), probe job status non-blockingly (`finetune watch`), query per-model training capability (`finetune capability`), and deploy trained models as endpoints (`deploy create`)
- **Fine-tuning & deployment** — Upload datasets, create text/audio/image fine-tune jobs (`finetune text|audio|image create`; text covers SFT/LoRA/DPO/CPT), probe job status non-blockingly (`finetune watch`), query per-model training capability (`finetune capability`), and deploy trained models as endpoints (`deploy text|audio|image create`)
- **Console capabilities** — Browse Bailian apps (`app list`), check free-tier quota (`usage free`), view model usage statistics (`usage stats`), manage workspaces (`workspace list`), and manage rate limits (`quota list/request/check/history`)
- **Local file auto-upload** — Every URL parameter accepts a local path; uploaded to free temp storage with 48-hour validity

Expand Down Expand Up @@ -114,10 +114,10 @@ bl auth login --console

# Fine-tune & deploy — a one-shot train-to-serve workflow
bl dataset upload --file ./train.jsonl # Upload a .jsonl dataset (validated first)
bl finetune create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # Local paths auto-upload
bl finetune watch --job-id ft-xxx --output json # Non-blocking status probe (exit 0/1/3 = done/failed/running)
bl finetune capability --model qwen3-8b # Which training types a model supports
bl deploy create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint
bl deploy text create --model qwen3-8b --name my-svc --plan mu # Deploy the trained model as an endpoint

# Browse apps / free-tier quota / usage statistics / workspaces
bl app list
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_
- **MCP 集成** — 统一调度百炼 MCP 服务:列出服务、查看工具、直接在终端调用任意工具
- **联网搜索** — 实时互联网信息检索,提升回答准确性及时效性
- **模型推荐** — 描述你的场景,智能推荐最适合的模型;支持限定范围搜索、模型对比和替代发现
- **微调与部署** — 上传数据集、创建 SFT/LoRA/DPO/CPT 调优任务(`finetune create`)、非阻塞探测任务状态(`finetune watch`)、按模型查训练能力(`finetune capability`),并把训练好的模型部署为推理服务(`deploy create`)
- **微调与部署** — 上传数据集、创建文本/音频/图像调优任务(`finetune text|audio|image create`;文本涵盖 SFT/LoRA/DPO/CPT)、非阻塞探测任务状态(`finetune watch`)、按模型查训练能力(`finetune capability`),并把训练好的模型部署为推理服务(`deploy text|audio|image create`)
- **控制台能力** — 浏览百炼应用(`app list`),查询模型免费额度(`usage free`),查看模型用量统计(`usage stats`),管理业务空间(`workspace list`),管理限流与提额(`quota list/request/check/history`)
- **本地文件自动上传** — 所有 URL 参数同时支持本地路径,免费临时存储 48 小时

Expand Down Expand Up @@ -112,10 +112,10 @@ bl auth login --console

# 微调与部署 — 从训练到服务的一站式流程
bl dataset upload --file ./train.jsonl # 上传 .jsonl 数据集(先校验)
bl finetune create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
bl finetune text create --model qwen3-8b --datasets ./train.jsonl --training-type sft-lora # 本地路径自动上传
bl finetune watch --job-id ft-xxx --output json # 非阻塞状态探测(退出码 0/1/3 = 成功/失败/进行中)
bl finetune capability --model qwen3-8b # 查询模型支持哪些训练方式
bl deploy create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务
bl deploy text create --model qwen3-8b --name my-svc --plan mu # 把训练好的模型部署为推理服务

# 浏览应用 / 免费额度 / 用量统计 / 业务空间
bl app list
Expand Down
16 changes: 12 additions & 4 deletions packages/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ import {
datasetGet,
datasetDelete,
datasetValidate,
finetuneCreate,
finetuneTextCreate,
finetuneAudioCreate,
finetuneImageCreate,
finetuneList,
finetuneGet,
finetuneCancel,
Expand All @@ -62,7 +64,9 @@ import {
finetuneExport,
finetuneWatch,
finetuneCapability,
deployCreate,
deployTextCreate,
deployAudioCreate,
deployImageCreate,
deployList,
deployGet,
deployModels,
Expand Down Expand Up @@ -133,7 +137,9 @@ export const commands: Record<string, AnyCommand> = {
"dataset get": datasetGet,
"dataset delete": datasetDelete,
"dataset validate": datasetValidate,
"finetune create": finetuneCreate,
"finetune text create": finetuneTextCreate,
"finetune audio create": finetuneAudioCreate,
"finetune image create": finetuneImageCreate,
"finetune list": finetuneList,
"finetune get": finetuneGet,
"finetune cancel": finetuneCancel,
Expand All @@ -143,7 +149,9 @@ export const commands: Record<string, AnyCommand> = {
"finetune export": finetuneExport,
"finetune watch": finetuneWatch,
"finetune capability": finetuneCapability,
"deploy create": deployCreate,
"deploy text create": deployTextCreate,
"deploy audio create": deployAudioCreate,
"deploy image create": deployImageCreate,
"deploy list": deployList,
"deploy get": deployGet,
"deploy models": deployModels,
Expand Down
77 changes: 77 additions & 0 deletions packages/cli/tests/e2e/dataset.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,83 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: dataset (offline)", () => {
expect(data.action).toBe("dataset.upload");
expect(data.schema).toBe("dpo");
});

test("dataset upload --schema image --no-validate --dry-run 采用 1GB 媒体上限", async () => {
// image schema raises the upload cap to 1 GiB (vs 300 MB for text).
// --no-validate keeps this offline (the jsonl fixture is not a real zip).
const file = join(__dirname, ".dataset-valid.jsonl");
const { stdout, stderr, exitCode } = await runCli([
"dataset",
"upload",
"--file",
file,
"--schema",
"image",
"--no-validate",
"--dry-run",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{ action: string; schema: string; max_bytes: number }>(stdout);
expect(data.action).toBe("dataset.upload");
expect(data.schema).toBe("image");
expect(data.max_bytes).toBe(1024 * 1024 * 1024);
});

test.each(["tts", "image"])("dataset upload --dry-run 接受媒体 schema %s", async (schema) => {
const file = join(__dirname, ".dataset-valid.jsonl");
const { stdout, stderr, exitCode } = await runCli([
"dataset",
"upload",
"--file",
file,
"--schema",
schema,
"--no-validate",
"--dry-run",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{ action: string; schema: string }>(stdout);
expect(data.action).toBe("dataset.upload");
expect(data.schema).toBe(schema);
});

test("dataset validate --schema video 拒绝(视频生成入口已隐藏)", async () => {
const file = join(__dirname, ".dataset-valid.jsonl");
const { stdout, stderr, exitCode } = await runCli([
"dataset",
"validate",
"--file",
file,
"--schema",
"video",
"--output",
"json",
]);
expect(exitCode, stdout + stderr).not.toBe(0);
expect(`${stdout}\n${stderr}`).toMatch(/--schema video is not supported/);
});

test("dataset upload --schema video 拒绝(视频生成入口已隐藏)", async () => {
const file = join(__dirname, ".dataset-valid.jsonl");
const { stdout, stderr, exitCode } = await runCli([
"dataset",
"upload",
"--file",
file,
"--schema",
"video",
"--no-validate",
"--dry-run",
"--output",
"json",
]);
expect(exitCode, stdout + stderr).not.toBe(0);
expect(`${stdout}\n${stderr}`).toMatch(/--schema video is not supported/);
});
});

describe.skipIf(!isDashScopeE2EReady())("e2e: dataset (DashScope)", () => {
Expand Down
62 changes: 61 additions & 1 deletion packages/cli/tests/e2e/deploy.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: deploy (offline)", () => {
});

test("deploy create --help 正常退出并展示必填项", async () => {
const { stderr, exitCode } = await runCli(["deploy", "create", "--help"]);
const { stderr, exitCode } = await runCli(["deploy", "text", "create", "--help"]);
expect(exitCode, stderr).toBe(0);
expect(stderr).toMatch(/--model|--name/i);
});

test("deploy create --dry-run 构造 lora 部署请求体", async () => {
const { stdout, stderr, exitCode } = await runCli([
"deploy",
"text",
"create",
"--model",
"qwen-plus-2025-12-01",
Expand All @@ -56,6 +57,65 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: deploy (offline)", () => {
expect(data.body.capacity).toBe(1);
});

test("deploy create --plan mu --deploy-spec --dry-run 透传 deploy_spec", async () => {
const { stdout, stderr, exitCode } = await runCli([
"deploy",
"text",
"create",
"--model",
"qwen3-8b",
"--name",
"my-qwen3-mu",
"--plan",
"mu",
"--deploy-spec",
"MU1",
"--capacity",
"2",
"--dry-run",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{
action: string;
body: { plan: string; deploy_spec?: string; capacity?: number };
}>(stdout);
expect(data.action).toBe("deploy.create");
expect(data.body.plan).toBe("mu");
expect(data.body.deploy_spec).toBe("MU1");
expect(data.body.capacity).toBe(2);
});

test("deploy audio create --dry-run 默认 plan=mu(CosyVoice 部署契约)", async () => {
// Audio (CosyVoice TTS) outputs deploy model-unit-billed: the modality fixes
// the default plan to `mu` (text/image stay `lora`). In dry-run the mu
// strategy skips the catalog lookup, so deploy_spec is omitted and capacity
// falls back to 1 with billing_method POST_PAY.
const { stdout, stderr, exitCode } = await runCli([
"deploy",
"audio",
"create",
"--model",
"my-cosyvoice-ft",
"--name",
"my-tts",
"--dry-run",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{
action: string;
body: { plan: string; name: string; billing_method?: string; capacity?: number };
}>(stdout);
expect(data.action).toBe("deploy.create");
expect(data.body.plan).toBe("mu");
expect(data.body.name).toBe("my-tts");
expect(data.body.billing_method).toBe("POST_PAY");
expect(data.body.capacity).toBe(1);
});

test("deploy scale --dry-run 转发 capacity", async () => {
const { stdout, stderr, exitCode } = await runCli([
"deploy",
Expand Down
Loading