mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7d32504ab | |||
| cdf94a8c89 | |||
| ce4d66b736 | |||
| 196a0aa506 | |||
| a9b0a752a8 | |||
| 2b7a0c742a | |||
| e5818e103c | |||
| 7797940626 | |||
| 94ccab0898 | |||
| b895f88abb | |||
| 7eedc05b99 | |||
| f3c7b6fb10 | |||
| eb196cb4a6 | |||
| 4ec0f6828b | |||
| 9ae5dc924d | |||
| d6cb075629 | |||
| 0e33c70e65 |
@@ -35,7 +35,7 @@ packages/core/src/auth/ # apiKey / console credential 解析与落盘
|
||||
packages/core/src/client/ # HTTP client / endpoints / console gateway
|
||||
```
|
||||
|
||||
Skill / 命令手册随 `skills/bailian-*/` 经 `npx skills add modelstudioai/cli --all -g` 安装(整包装齐,含共享协议 `bailian-protocol`)。业务 skill(`bailian-cli` / `bailian-gen` / `bailian-finetune` / `bailian-managed-agent`)执行前读 `skills/bailian-protocol/`;不要依赖 frontmatter `companions`(安装器不强制)。`tools/generate-reference.ts` 从 **`packages/cli/src/commands.ts`** 按一级命令归属表分流写入各 `skills/<skill>/reference/`(纳入 git);`tools/sync-skill-metadata.ts` 从 `packages/cli/package.json` 同步各 `skills/*/SKILL.md` 的 `metadata.version`。两者由根脚本 `pnpm run sync:skill-assets` 和 `.vite-hooks/pre-commit` 执行。hub `bailian-cli` 的路由表不复述领域命令明细;SKILL 文案 / 安装约定 / hand-off 见 [docs/agents/skill-change.md](docs/agents/skill-change.md)。
|
||||
Skill / 命令手册随 `skills/bailian-*/` 经 `bl skill init` 安装(装齐 registry 中全部 `bailian-*`,含共享协议 `bailian-protocol`)。业务 skill(`bailian-cli` / `bailian-gen` / `bailian-finetune` / `bailian-managed-agent`)执行前读 `skills/bailian-protocol/`;不要依赖 frontmatter `companions`(安装器不强制)。`tools/generate-reference.ts` 从 **`packages/cli/src/commands.ts`** 按一级命令归属表分流写入各 `skills/<skill>/reference/`(纳入 git);`tools/sync-skill-metadata.ts` 从 `packages/cli/package.json` 同步各 `skills/*/SKILL.md` 的 `metadata.version`。两者由根脚本 `pnpm run sync:skill-assets` 和 `.vite-hooks/pre-commit` 执行。hub `bailian-cli` 的路由表不复述领域命令明细;SKILL 文案 / 安装约定 / hand-off 见 [docs/agents/skill-change.md](docs/agents/skill-change.md)。
|
||||
|
||||
约定:
|
||||
|
||||
|
||||
@@ -6,6 +6,43 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
||||
|
||||
[中文版](CHANGELOG.zh.md) · [README](README.md) · [Contributing](CONTRIBUTING.md)
|
||||
|
||||
## [1.15.0] - 2026-08-14
|
||||
|
||||
### Added
|
||||
|
||||
- **Responses API for `bl text chat`** — Use `--api responses` to call the DashScope Responses API with streaming, tool definitions, and structured JSON output; Chat Completions remains the default.
|
||||
- **Subscription plan usage views** — `bl usage token-plan` displays 5-hour and weekly quota usage, while `bl usage coding-plan` displays 5-hour, weekly, and monthly usage; both support text and JSON output.
|
||||
- **Authentication requirements in command help** — Help output now states whether a command requires an API Key, Console login, or Alibaba Cloud OpenAPI credentials.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Broader speech-recognition model support** — `bl speech recognize` now routes asynchronous file-transcription and synchronous Flash ASR models to the appropriate DashScope APIs, with clear guidance for unsupported realtime models.
|
||||
- **MCP transport compatibility** — MCP commands now fall back from Streamable HTTP to classic SSE for compatible Bailian and custom endpoints.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Binary updates now refresh installed Agent Skills after a successful CLI upgrade.
|
||||
- Fixed unavailable Token Plan quota values and missing reset times.
|
||||
- Fixed Qwen3 file-transcription result handling so waiting mode and `--out` work correctly.
|
||||
- Fixed MCP SSE chunk parsing, header timeouts, abort cleanup, and fallback status matching.
|
||||
- Network failures in JSON output now preserve the errno value in `cause.code`.
|
||||
|
||||
## [1.14.3] - 2026-08-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Free-tier quota compatibility** — `bl usage free` and `bl usage freetier` now use the current Bailian Commerce console APIs for quota queries, activation, and deactivation, with consistent asynchronous-task polling.
|
||||
|
||||
## [1.14.2] - 2026-08-07
|
||||
|
||||
### Added
|
||||
|
||||
- **`bl skill init`** — Install all first-party `bailian-*` skills into detected local AI Agents in one step.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Skill command interface** — Skill management commands now default to JSON output for Agent workflows; `bl skill add` and `bl skill update` use explicit `--all` and `--name` selectors.
|
||||
|
||||
## [1.14.1] - 2026-08-05
|
||||
|
||||
### Added
|
||||
|
||||
@@ -6,6 +6,43 @@
|
||||
|
||||
[English](CHANGELOG.md) · [README](README.zh.md) · [参与贡献](CONTRIBUTING.zh.md)
|
||||
|
||||
## [1.15.0] - 2026-08-14
|
||||
|
||||
### 新增
|
||||
|
||||
- **`bl text chat` 支持 Responses API** —— 可通过 `--api responses` 调用 DashScope Responses API,支持流式输出、工具定义和结构化 JSON 输出;默认仍使用 Chat Completions。
|
||||
- **订阅套餐用量视图** —— `bl usage token-plan` 支持查看 5 小时和每周额度,`bl usage coding-plan` 支持查看 5 小时、每周和每月额度;两者均提供文本与 JSON 输出。
|
||||
- **命令帮助展示鉴权要求** —— Help 输出现在会明确标注命令需要 API Key、控制台登录还是阿里云 OpenAPI 凭证。
|
||||
|
||||
### 变更
|
||||
|
||||
- **扩展语音识别模型支持** —— `bl speech recognize` 现在会将异步文件转写和同步 Flash ASR 模型路由至对应的 DashScope API,并为暂不支持的实时模型提供明确提示。
|
||||
- **增强 MCP 传输兼容性** —— MCP 命令现在可为兼容的百炼及自定义端点从 Streamable HTTP 自动回退至经典 SSE。
|
||||
|
||||
### 修复
|
||||
|
||||
- 二进制方式升级 CLI 成功后,现在会同步刷新已安装的 Agent Skills。
|
||||
- 修复 Token Plan 额度不可用或缺少重置时间时的展示问题。
|
||||
- 修复 Qwen3 文件转写结果处理,使等待模式和 `--out` 能够正常工作。
|
||||
- 修复 MCP SSE 分块解析、响应头超时、中止清理和回退状态匹配问题。
|
||||
- JSON 输出中的网络错误现在会在 `cause.code` 中保留 errno。
|
||||
|
||||
## [1.14.3] - 2026-08-12
|
||||
|
||||
### 修复
|
||||
|
||||
- **免费额度兼容性** —— `bl usage free` 和 `bl usage freetier` 现在使用最新的 Bailian Commerce 控制台 API 查询、开通和关闭免费额度,并统一处理异步任务轮询。
|
||||
|
||||
## [1.14.2] - 2026-08-07
|
||||
|
||||
### 新增
|
||||
|
||||
- **`bl skill init`** —— 一次性将全部官方 `bailian-*` Skill 安装到本机检测到的 AI Agent。
|
||||
|
||||
### 变更
|
||||
|
||||
- **Skill 命令接口** —— Skill 管理命令现在默认输出适合 Agent 工作流的 JSON;`bl skill add` 和 `bl skill update` 使用明确的 `--all` 与 `--name` 选择参数。
|
||||
|
||||
## [1.14.1] - 2026-08-05
|
||||
|
||||
### 新增
|
||||
|
||||
+34
-31
@@ -1,8 +1,38 @@
|
||||
# 阿里云百炼CLI 安装说明(供 AI Agent 阅读)
|
||||
|
||||
本文档面向 **AI Agent**:按下列步骤为用户安装并校验 **阿里云百炼CLI**(命令 `bl` / `bailian`)。**优先**使用二进制一键安装(无需 Node);若环境已有 Node / 需要 Command Pack,再用 npm。不要臆造版本号或路径;以用户环境为准。
|
||||
本文档面向 **AI Agent**:按下列步骤为用户安装并校验 **阿里云百炼CLI**(命令 `bl` / `bailian`)。**优先**在已有 Node.js(**≥ 18.17.0**)的环境用 npm 安装;若没有可用 Node / npm,再走二进制一键安装。不要臆造版本号或路径;以用户环境为准。
|
||||
|
||||
## 1. 推荐:二进制安装(无需 Node)
|
||||
## 1. 推荐:npm 安装(要求 **≥ 18.17.0**)
|
||||
|
||||
1. `node -v` 确认版本 ≥ 18.17.0。
|
||||
2. `npm -v` 确认可用(**仅允许 npm** 全局安装,不要用 pnpm/yarn)。
|
||||
3. 执行:
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
```
|
||||
|
||||
4. 校验:`bl --version`。
|
||||
|
||||
安装 skills(CLI 内置,无需 Git / npx skills):
|
||||
|
||||
```bash
|
||||
bl skill init
|
||||
```
|
||||
|
||||
**Supported:** `bl skill init` 一次装齐 registry 中全部 `bailian-*`(含共享协议 `bailian-protocol`)。
|
||||
|
||||
**Advanced / 按需子集:**
|
||||
|
||||
```bash
|
||||
bl skill add --name bailian-protocol,bailian-gen
|
||||
```
|
||||
|
||||
安装成功后,用中文简要说明已安装的 skills 及用户可做什么。
|
||||
|
||||
## 2. 备选:二进制安装(无需 Node)
|
||||
|
||||
当环境没有 Node / npm,或 Node 版本过低无法走 npm 时,使用二进制安装脚本。脚本安装 CLI 成功后会自动执行 `bl skill init`。
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
@@ -37,36 +67,9 @@ bl --version
|
||||
which bl # Windows: where.exe bl
|
||||
```
|
||||
|
||||
> CDN / GitHub Release 未就绪或下载失败时,回退到下方 npm 安装。
|
||||
若自动 skill 安装失败,再手动执行:`bl skill init`。
|
||||
|
||||
## 2. 备选:npm 安装(要求 **≥ 18.17.0**)
|
||||
|
||||
1. `node -v` 确认版本。
|
||||
2. `npm -v` 确认可用(**仅允许 npm** 全局安装,不要用 pnpm/yarn)。
|
||||
3. 执行:
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
```
|
||||
|
||||
4. 校验:`bl --version`。
|
||||
|
||||
可选 skills(与 CLI 本体无关,按需):
|
||||
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
```
|
||||
|
||||
**Supported:** 始终使用 `--all -g`,一次装齐整套 `bailian-*`(含共享协议 `bailian-protocol`)。Agent Skills / `npx skills` **不会**按 metadata 自动拉依赖。
|
||||
|
||||
**Advanced / 不推荐:** 子集 `-s` 时 skills CLI 不会自动带上 `bailian-protocol`;若坚持子集,必须手动同时指定,例如:
|
||||
|
||||
```bash
|
||||
# Advanced: you MUST include bailian-protocol yourself — installer does not pull it
|
||||
npx skills add modelstudioai/cli -g -s bailian-protocol -s bailian-gen
|
||||
```
|
||||
|
||||
安装成功后,用中文简要说明已安装的 skills 及用户可做什么。
|
||||
> CDN / GitHub Release 未就绪或下载失败时,若本机已有合格 Node,回退到上方 npm 安装。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -82,15 +82,31 @@ Send the following to your Agent — it will detect your environment, then insta
|
||||
Please read https://bailian.aliyun.com/cli/install.md and install the Aliyun Model Studio CLI for me
|
||||
```
|
||||
|
||||
**Manual install (npm)**
|
||||
**Install with NPM**
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
> Requires Node.js >= 18.17.
|
||||
|
||||
**Install on macOS/Linux**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
```
|
||||
|
||||
> No Node.js required. The installer automatically installs Bailian Skills.
|
||||
|
||||
**Install on Windows**
|
||||
|
||||
```powershell
|
||||
irm https://bailian.aliyun.com/cli/install.ps1 | iex
|
||||
```
|
||||
|
||||
> No Node.js required. The installer automatically installs Bailian Skills.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Once installed, just describe your task to your AI Agent — no need to assemble commands by hand.
|
||||
|
||||
+18
-2
@@ -81,15 +81,31 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_
|
||||
请阅读:https://bailian.aliyun.com/cli/install.md 并按照说明为我安装阿里云百炼 CLI
|
||||
```
|
||||
|
||||
**手动安装(npm)**
|
||||
**NPM 安装**
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
> 需要预先安装 Node.js >= 18.17。
|
||||
|
||||
**macOS/Linux 安装**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
```
|
||||
|
||||
> 无需预先安装 Node.js,安装脚本会自动安装 Bailian Skills。
|
||||
|
||||
**Windows 安装**
|
||||
|
||||
```powershell
|
||||
irm https://bailian.aliyun.com/cli/install.ps1 | iex
|
||||
```
|
||||
|
||||
> 无需预先安装 Node.js,安装脚本会自动安装 Bailian Skills。
|
||||
|
||||
## 快速开始
|
||||
|
||||
安装完成后,直接在 AI Agent 中描述你的任务,无需手动拼接命令。
|
||||
|
||||
+12
-11
@@ -11,16 +11,17 @@
|
||||
|
||||
## 统一口径(安装)
|
||||
|
||||
1. **Supported install:** `npx skills add modelstudioai/cli --all -g`(整包装齐,含 `bailian-protocol`)
|
||||
2. **`bailian-protocol` 是共享协议 skill**,业务 skill 执行前应 Read 它;Agent Skills / `npx skills` **不会**按 frontmatter 自动拉依赖
|
||||
1. **Supported install:** `bl skill init`(装齐 registry 中全部 `bailian-*`,含 `bailian-protocol`)
|
||||
2. **`bailian-protocol` 是共享协议 skill**,业务 skill 执行前应 Read 它
|
||||
3. **不要**在 frontmatter 写 `companions`,也不要对外说「companions = 安装器硬依赖」
|
||||
4. 子集安装(`-s`)为 **advanced / 不推荐**:skills CLI 不会自动带上 protocol;漏装会导致相对路径 Read 失败
|
||||
4. 子集安装:`bl skill add --name bailian-protocol,<skill>`;漏装 protocol 会导致相对路径 Read 失败
|
||||
5. **`bl skill add --all`:** 安装 registry 全量(含 `spark-video` 等非 bailian 技能);一键安装 / `bl update` 用 `skill init`,不要用 `--all`
|
||||
|
||||
## 概念图
|
||||
|
||||
```text
|
||||
bailian-protocol ← 共享协议(consent / 鉴权 / 版本 / 错误上报)
|
||||
▲ 靠 --all -g 与业务 skill 同装;非安装器强制 companions
|
||||
▲ 靠 `bl skill init` 与业务 skill 同装;非安装器强制 companions
|
||||
│
|
||||
┌───────┴────────┬────────────────┬──────────────────┐
|
||||
bailian-gen bailian-finetune bailian-managed-agent
|
||||
@@ -37,8 +38,8 @@ bailian-gen bailian-finetune bailian-managed-agent
|
||||
|
||||
### A. 分层边界
|
||||
|
||||
- [ ] **整包装齐**:安装/升级文案主推 `--all -g`;业务 skill **不**声明 `companions`
|
||||
- [ ] **协议读取**:CRITICAL / references 可链 `../bailian-protocol/…`;若读不到 → 停止执行 `bl`,提示 `npx skills add modelstudioai/cli --all -g`
|
||||
- [ ] **整包装齐**:安装/升级文案主推 `bl skill init`;业务 skill **不**声明 `companions`
|
||||
- [ ] **协议读取**:CRITICAL / references 可链 `../bailian-protocol/…`;若读不到 → 停止执行 `bl`,提示 `bl skill init`
|
||||
- [ ] **软 hand-off**:兄弟业务 skill **只写 skill 名**;已安装则 Read,未安装则 `bl … --help` 或提示整包安装;**不要**把 `../bailian-gen/…` 等写成执行前提
|
||||
- [ ] **Hub vs 领域**:`bailian-cli` 的「When to use which command」只列 hub 拥有的意图;媒体 / 精调 / managed-agent 各留 hand-off 行,**不抄**领域默认模型与子命令明细
|
||||
- [ ] **渐进披露**:SKILL 写意图路由与领域硬规则;flags / usage / examples 以 `reference/` 或 `bl <command> --help` 为准,表后保留「勿猜 flag」指向句
|
||||
@@ -46,9 +47,9 @@ bailian-gen bailian-finetune bailian-managed-agent
|
||||
### B. 文案与落款一致性
|
||||
|
||||
- [ ] 领域 skill(gen / finetune / managed-agent)路由或命令表后有指向 `reference/` 的句;文末 `## references`(protocol + reference)与家族对齐
|
||||
- [ ] description 含 WHAT + WHEN + 反触发;安装说明指向 `--all -g`,不写 companions 必装
|
||||
- [ ] description 含 WHAT + WHEN + 反触发;安装说明指向 `bl skill init`,不写 companions 必装
|
||||
- [ ] Quick examples 只演示本 skill 职责(hub 不示范 `bl image` / `bl video` 等)
|
||||
- [ ] 若改了安装方式:同步 `README.md` / `README.zh.md` / `INSTALL.md` / `skills/*/README*` / `skills/bailian-protocol/assets/setup.md` 中的 `npx skills add …` 示例(改 `INSTALL.md` 时按 [install-doc-change.md](install-doc-change.md) 同步静态页)
|
||||
- [ ] 若改了安装方式:同步 `README.md` / `README.zh.md` / `INSTALL.md` / `skills/*/README*` / `skills/bailian-protocol/assets/setup.md` 中的 `bl skill init` / `bl skill add …` 示例(改 `INSTALL.md` 时按 [install-doc-change.md](install-doc-change.md) 同步静态页)
|
||||
|
||||
### C. 归属与生成
|
||||
|
||||
@@ -60,8 +61,8 @@ bailian-gen bailian-finetune bailian-managed-agent
|
||||
|
||||
```sh
|
||||
pnpm run sync:skill-assets
|
||||
# 本地试装(测本仓库改动,勿只拉远端)
|
||||
npx skills add "$(pwd)" --all -g -y
|
||||
# 已发布版本试装
|
||||
bl skill init
|
||||
```
|
||||
|
||||
抽查:打开 `skills/bailian-cli/SKILL.md` 确认无领域子命令明细表、无 `companions`;打开对应领域 skill 确认有「勿猜 flag」与 hand-off。
|
||||
@@ -69,7 +70,7 @@ npx skills add "$(pwd)" --all -g -y
|
||||
## 常见漏点
|
||||
|
||||
- ✗ hub 路由表再次抄回 image / video / finetune / managed-agent 明细 → token 膨胀且与领域 skill 双份漂移
|
||||
- ✗ 重新加回 `companions` 并宣称安装器硬依赖 → 与 Agent Skills / `npx skills` 合同不符
|
||||
- ✗ 重新加回 `companions` 并宣称安装器硬依赖 → 与 `bl skill add` 合同不符
|
||||
- ✗ 软 hand-off 写成硬路径 `../bailian-*/SKILL.md` 当执行前提 → 子集安装断链
|
||||
- ✗ 只改 SKILL、忘改 `GROUP_OWNER_SKILL` → reference 落错 skill
|
||||
- ✗ 手改 `skills/*/reference/*.md` → 下次 generate 被覆盖
|
||||
|
||||
+18
-2
@@ -82,15 +82,31 @@ Send the following to your Agent — it will detect your environment, then insta
|
||||
Please read https://bailian.aliyun.com/cli/install.md and install the Aliyun Model Studio CLI for me
|
||||
```
|
||||
|
||||
**Manual install (npm)**
|
||||
**Install with NPM**
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
> Requires Node.js >= 18.17.
|
||||
|
||||
**Install on macOS/Linux**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
```
|
||||
|
||||
> No Node.js required. The installer automatically installs Bailian Skills.
|
||||
|
||||
**Install on Windows**
|
||||
|
||||
```powershell
|
||||
irm https://bailian.aliyun.com/cli/install.ps1 | iex
|
||||
```
|
||||
|
||||
> No Node.js required. The installer automatically installs Bailian Skills.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Once installed, just describe your task to your AI Agent — no need to assemble commands by hand.
|
||||
|
||||
@@ -81,15 +81,31 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_
|
||||
请阅读:https://bailian.aliyun.com/cli/install.md 并按照说明为我安装阿里云百炼 CLI
|
||||
```
|
||||
|
||||
**手动安装(npm)**
|
||||
**NPM 安装**
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
> 需要预先安装 Node.js >= 18.17。
|
||||
|
||||
**macOS/Linux 安装**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
```
|
||||
|
||||
> 无需预先安装 Node.js,安装脚本会自动安装 Bailian Skills。
|
||||
|
||||
**Windows 安装**
|
||||
|
||||
```powershell
|
||||
irm https://bailian.aliyun.com/cli/install.ps1 | iex
|
||||
```
|
||||
|
||||
> 无需预先安装 Node.js,安装脚本会自动安装 Bailian Skills。
|
||||
|
||||
## 快速开始
|
||||
|
||||
安装完成后,直接在 AI Agent 中描述你的任务,无需手动拼接命令。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bailian-cli",
|
||||
"version": "1.14.3",
|
||||
"version": "1.15.0",
|
||||
"description": "CLI for Aliyun Model Studio (DashScope) AI Platform.",
|
||||
"keywords": [
|
||||
"agent",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bailian-cli-commands",
|
||||
"version": "1.14.3",
|
||||
"version": "1.15.0",
|
||||
"description": "Command library for bailian-cli products (knowledge, memory, media, …). See https://www.npmjs.com/package/bailian-cli for usage.",
|
||||
"homepage": "https://bailian.console.aliyun.com/cli",
|
||||
"bugs": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Read-only discovery of locally installed AI tooling, surfaced by `config ui`:
|
||||
// - Agent skills installed under ~/.agents/skills (via `npx skills add`).
|
||||
// - Agent skills installed under ~/.agents/skills (via `bl skill add`).
|
||||
// - MCP servers declared in each coding agent's local config file.
|
||||
// - Coding agent frameworks and whether the bailian-cli provider is wired in.
|
||||
//
|
||||
@@ -128,8 +128,8 @@ function countFiles(dir: string, budget = 500): number {
|
||||
}
|
||||
|
||||
/**
|
||||
* Skill directories to scan, keyed by the module that owns them. `npx skills
|
||||
* add --all` fans skills out into each installed agent, so the same skill can
|
||||
* Skill directories to scan, keyed by the module that owns them. `bl skill init` /
|
||||
* `bl skill add` fans skills out into each installed agent, so the same skill can
|
||||
* live in several of these roots at once.
|
||||
*/
|
||||
function skillRoots(home: string): Array<{ source: string; dir: string }> {
|
||||
|
||||
@@ -548,7 +548,7 @@ export const PAGE_HTML = `<!doctype html>
|
||||
<section id="view-skills" class="view">
|
||||
<div class="view-head">
|
||||
<h2 class="view-title">Installed <span class="grad">Skills</span></h2>
|
||||
<p class="view-sub">Agent skills discovered across every local agent module (~/.agents/skills plus each agent's skills folder). Installed via <code style="font-family:var(--mono)">npx skills add</code>.</p>
|
||||
<p class="view-sub">Agent skills discovered across every local agent module (~/.agents/skills plus each agent's skills folder). Installed via <code style="font-family:var(--mono)">bl skill add</code>.</p>
|
||||
</div>
|
||||
<div class="toolbar"><input id="skillSearch" class="search" type="search" placeholder="Search skills…" autocomplete="off"><button id="addSkillBtn" class="btn-dark" type="button">+ Add skill</button></div>
|
||||
<div id="skillsBody"><div class="loading">Loading…</div></div>
|
||||
@@ -1444,7 +1444,7 @@ export const PAGE_HTML = `<!doctype html>
|
||||
function renderSkills() {
|
||||
var body = document.getElementById('skillsBody');
|
||||
var pager = document.getElementById('skillsPager');
|
||||
if (!SKILLS.length) { pager.innerHTML = ''; renderEmpty(body, 'No skills installed.', 'Install with <code>npx skills add modelstudioai/cli --all -g</code>'); return; }
|
||||
if (!SKILLS.length) { pager.innerHTML = ''; renderEmpty(body, 'No skills installed.', 'Install with <code>bl skill init</code>'); return; }
|
||||
var list = SKILLS.filter(function (s) { return skillMatches(s, SKILL_Q); });
|
||||
if (!list.length) { pager.innerHTML = ''; renderEmpty(body, 'No skills match "' + SKILL_Q + '".', ''); return; }
|
||||
var info = pageSlice(list, SKILL_PAGE, getPageSize('skills')); SKILL_PAGE = info.page;
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import {
|
||||
defineCommand,
|
||||
chatPath,
|
||||
responsesPath,
|
||||
parseSSE,
|
||||
detectOutputFormat,
|
||||
readTextFromPathOrStdin,
|
||||
type ChatMessage,
|
||||
type ChatRequest,
|
||||
type ChatResponse,
|
||||
type ResponsesRequest,
|
||||
type ResponsesResponse,
|
||||
type ResponsesStreamEvent,
|
||||
type StreamChunk,
|
||||
type FlagsDef,
|
||||
type ParsedFlags,
|
||||
} from "bailian-cli-core";
|
||||
import { ansi, emitResult, emitBare } from "bailian-cli-runtime";
|
||||
import { readFileSync } from "fs";
|
||||
import {
|
||||
assertResponsesStreamCompleted,
|
||||
inspectResponsesStreamEvent,
|
||||
extractResponsesText,
|
||||
} from "./responses.ts";
|
||||
|
||||
const CHAT_FLAGS = {
|
||||
api: {
|
||||
type: "string",
|
||||
valueHint: "<chat|responses>",
|
||||
choices: ["chat", "responses"] as const,
|
||||
description: "API to call (default: chat)",
|
||||
},
|
||||
model: { type: "string", valueHint: "<model>", description: "Model ID (default: qwen3.8-max)" },
|
||||
message: {
|
||||
type: "array",
|
||||
@@ -72,31 +87,31 @@ function parseMessages(flags: ChatFlags): ParsedMessages {
|
||||
if (flags.messagesFile) {
|
||||
const raw = readTextFromPathOrStdin(flags.messagesFile);
|
||||
const parsed = JSON.parse(raw) as Array<{ role: string; content: string }>;
|
||||
for (const m of parsed) {
|
||||
if (m.role === "system") {
|
||||
system = typeof m.content === "string" ? m.content : "";
|
||||
for (const parsedMessage of parsed) {
|
||||
if (parsedMessage.role === "system") {
|
||||
system = typeof parsedMessage.content === "string" ? parsedMessage.content : "";
|
||||
} else {
|
||||
messages.push(m as ChatMessage);
|
||||
messages.push(parsedMessage as ChatMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.message) {
|
||||
const validRoles = new Set(["system", "user", "assistant"]);
|
||||
const msgs = flags.message;
|
||||
for (const m of msgs) {
|
||||
const colonIdx = m.indexOf(":");
|
||||
const maybeRole = colonIdx !== -1 ? m.slice(0, colonIdx) : "";
|
||||
const messageValues = flags.message;
|
||||
for (const messageValue of messageValues) {
|
||||
const colonIndex = messageValue.indexOf(":");
|
||||
const maybeRole = colonIndex !== -1 ? messageValue.slice(0, colonIndex) : "";
|
||||
|
||||
if (validRoles.has(maybeRole)) {
|
||||
const content = m.slice(colonIdx + 1);
|
||||
const content = messageValue.slice(colonIndex + 1);
|
||||
if (maybeRole === "system") {
|
||||
system = content;
|
||||
} else {
|
||||
messages.push({ role: maybeRole as "user" | "assistant", content });
|
||||
}
|
||||
} else {
|
||||
messages.push({ role: "user", content: m });
|
||||
messages.push({ role: "user", content: messageValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,24 +120,33 @@ function parseMessages(flags: ChatFlags): ParsedMessages {
|
||||
}
|
||||
|
||||
export default defineCommand({
|
||||
description: "Send a chat completion (OpenAI compatible, DashScope)",
|
||||
description: "Send a text model request (OpenAI compatible, DashScope)",
|
||||
auth: "apiKey",
|
||||
usageArgs: "--message <text> [flags]",
|
||||
flags: CHAT_FLAGS,
|
||||
exampleArgs: [
|
||||
'--message "What is Qwen?"',
|
||||
`--api responses --model qwen3.8-max --tool '{"type":"web_search"}' --message "Search for recent Alibaba Cloud news"`,
|
||||
'--model qwen-max --system "You are a coding assistant." --message "Write fizzbuzz in Python"',
|
||||
'--message "Hello" --message "assistant:Hi!" --message "How are you?"',
|
||||
"--messages-file - --stream",
|
||||
'--message "Hello" --output json',
|
||||
'--model qwq-plus --message "Solve 1+1" --enable-thinking',
|
||||
],
|
||||
validate: (f) =>
|
||||
!f.message && !f.messagesFile ? "Provide --message or --messages-file." : undefined,
|
||||
validate: (flags) => {
|
||||
if (!flags.message && !flags.messagesFile) {
|
||||
return "Provide --message or --messages-file.";
|
||||
}
|
||||
if (flags.api === "responses" && flags.thinkingBudget !== undefined) {
|
||||
return "--thinking-budget is not supported by the Responses API.";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
async run(ctx) {
|
||||
const { settings, flags } = ctx;
|
||||
const { system, messages } = parseMessages(flags);
|
||||
|
||||
const api = flags.api ?? "chat";
|
||||
const model = flags.model || settings.defaultTextModel || "qwen3.8-max";
|
||||
const shouldStream = flags.stream || process.stdout.isTTY;
|
||||
const format = detectOutputFormat(settings.output);
|
||||
@@ -134,29 +158,39 @@ export default defineCommand({
|
||||
}
|
||||
allMessages.push(...messages);
|
||||
|
||||
const body: ChatRequest = {
|
||||
model,
|
||||
messages: allMessages,
|
||||
max_tokens: flags.maxTokens ?? 4096,
|
||||
stream: shouldStream,
|
||||
};
|
||||
let body: ChatRequest | ResponsesRequest;
|
||||
if (api === "responses") {
|
||||
body = {
|
||||
model,
|
||||
input: allMessages,
|
||||
max_output_tokens: flags.maxTokens ?? 4096,
|
||||
stream: shouldStream,
|
||||
};
|
||||
} else {
|
||||
body = {
|
||||
model,
|
||||
messages: allMessages,
|
||||
max_tokens: flags.maxTokens ?? 4096,
|
||||
stream: shouldStream,
|
||||
};
|
||||
}
|
||||
|
||||
if (flags.temperature !== undefined) body.temperature = flags.temperature;
|
||||
if (flags.topP !== undefined) body.top_p = flags.topP;
|
||||
|
||||
if (flags.enableThinking) {
|
||||
body.enable_thinking = true;
|
||||
if (flags.thinkingBudget !== undefined) {
|
||||
if (api === "chat" && "messages" in body && flags.thinkingBudget !== undefined) {
|
||||
body.thinking_budget = flags.thinkingBudget;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.tool) {
|
||||
const tools = flags.tool.map((t) => {
|
||||
const tools = flags.tool.map((toolValue) => {
|
||||
try {
|
||||
return JSON.parse(t);
|
||||
return JSON.parse(toolValue);
|
||||
} catch {
|
||||
const raw = readFileSync(t, "utf-8");
|
||||
const raw = readFileSync(toolValue, "utf-8");
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
});
|
||||
@@ -169,8 +203,8 @@ export default defineCommand({
|
||||
}
|
||||
|
||||
if (shouldStream) {
|
||||
const res = await ctx.client.request({
|
||||
path: chatPath(),
|
||||
const responseStream = await ctx.client.request({
|
||||
path: api === "responses" ? responsesPath() : chatPath(),
|
||||
method: "POST",
|
||||
body,
|
||||
stream: true,
|
||||
@@ -178,6 +212,7 @@ export default defineCommand({
|
||||
|
||||
let textContent = "";
|
||||
let inThinking = false;
|
||||
let responsesCompleted = false;
|
||||
const writesStreamingStdout = format === "text";
|
||||
const isTTY = process.stdout.isTTY;
|
||||
const statusOut =
|
||||
@@ -185,8 +220,28 @@ export default defineCommand({
|
||||
const resultOut = process.stdout;
|
||||
const statusColor = ansi(statusOut);
|
||||
|
||||
for await (const event of parseSSE(res)) {
|
||||
for await (const event of parseSSE(responseStream)) {
|
||||
if (event.data === "[DONE]") break;
|
||||
if (api === "responses") {
|
||||
let parsedEvent: ResponsesStreamEvent;
|
||||
try {
|
||||
parsedEvent = JSON.parse(event.data) as ResponsesStreamEvent;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
const update = inspectResponsesStreamEvent(parsedEvent);
|
||||
if (update.delta) {
|
||||
textContent += update.delta;
|
||||
if (writesStreamingStdout) resultOut.write(update.delta);
|
||||
}
|
||||
if (update.completed) {
|
||||
responsesCompleted = true;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(event.data) as StreamChunk;
|
||||
|
||||
@@ -216,6 +271,7 @@ export default defineCommand({
|
||||
// Skip unparseable chunks
|
||||
}
|
||||
}
|
||||
if (api === "responses") assertResponsesStreamCompleted(responsesCompleted);
|
||||
if (inThinking) statusOut.write(statusColor.reset);
|
||||
|
||||
if (format === "json") {
|
||||
@@ -223,6 +279,20 @@ export default defineCommand({
|
||||
} else {
|
||||
resultOut.write("\n");
|
||||
}
|
||||
} else if (api === "responses") {
|
||||
const response = await ctx.client.requestJson<ResponsesResponse>({
|
||||
path: responsesPath(),
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
|
||||
const text = extractResponsesText(response);
|
||||
|
||||
if (settings.quiet || format === "text") {
|
||||
emitBare(text);
|
||||
} else {
|
||||
emitResult(response, format);
|
||||
}
|
||||
} else {
|
||||
const response = await ctx.client.requestJson<ChatResponse>({
|
||||
path: chatPath(),
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import {
|
||||
BailianError,
|
||||
ExitCode,
|
||||
type ResponsesResponse,
|
||||
type ResponsesStreamEvent,
|
||||
} from "bailian-cli-core";
|
||||
|
||||
export interface ResponsesStreamUpdate {
|
||||
delta: string;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
export function extractResponsesText(response: ResponsesResponse): string {
|
||||
return response.output
|
||||
.filter((outputItem) => outputItem.type === "message")
|
||||
.flatMap((outputItem) => outputItem.content ?? [])
|
||||
.filter((contentItem) => contentItem.type === "output_text")
|
||||
.map((contentItem) => contentItem.text ?? "")
|
||||
.join("");
|
||||
}
|
||||
|
||||
export function extractResponsesStreamDelta(event: ResponsesStreamEvent): string {
|
||||
return event.type === "response.output_text.delta" ? (event.delta ?? "") : "";
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
||||
return typeof value === "object" && value !== null
|
||||
? (value as Record<string, unknown>)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function stringProperty(record: Record<string, unknown> | undefined, property: string) {
|
||||
const value = record?.[property];
|
||||
return typeof value === "string" && value.trim() ? value : undefined;
|
||||
}
|
||||
|
||||
function responsesErrorMessage(event: ResponsesStreamEvent): string | undefined {
|
||||
const response = asRecord(event.response);
|
||||
const responseError = asRecord(response?.error);
|
||||
const eventError = asRecord(event.error);
|
||||
return (
|
||||
stringProperty(responseError, "message") ??
|
||||
stringProperty(eventError, "message") ??
|
||||
stringProperty(event, "message")
|
||||
);
|
||||
}
|
||||
|
||||
export function inspectResponsesStreamEvent(event: ResponsesStreamEvent): ResponsesStreamUpdate {
|
||||
if (event.type === "response.failed" || event.type === "error") {
|
||||
throw new BailianError(responsesErrorMessage(event) ?? "Response failed.", ExitCode.GENERAL);
|
||||
}
|
||||
|
||||
if (event.type === "response.incomplete") {
|
||||
const response = asRecord(event.response);
|
||||
const incompleteDetails = asRecord(response?.incomplete_details);
|
||||
const reason = stringProperty(incompleteDetails, "reason");
|
||||
throw new BailianError(
|
||||
responsesErrorMessage(event) ??
|
||||
(reason ? `Response incomplete: ${reason}` : "Response incomplete."),
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
delta: extractResponsesStreamDelta(event),
|
||||
completed: event.type === "response.completed",
|
||||
};
|
||||
}
|
||||
|
||||
export function assertResponsesStreamCompleted(completed: boolean): void {
|
||||
if (completed) return;
|
||||
throw new BailianError(
|
||||
"Stream disconnected before completion: stream closed before response.completed.",
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
@@ -20,8 +20,7 @@ import {
|
||||
type AnsiStyles,
|
||||
} from "bailian-cli-runtime";
|
||||
|
||||
const SKILL_SOURCE = "modelstudioai/cli";
|
||||
const SKILL_INSTALL_CMD = `npx skills add ${SKILL_SOURCE} --all -g -y`;
|
||||
const SKILL_INSTALL_CMD = "bl skill init";
|
||||
|
||||
function updateAgentSkill(color: AnsiStyles): void {
|
||||
process.stderr.write("\nUpdating agent skill...\n");
|
||||
@@ -143,6 +142,7 @@ export default defineCommand({
|
||||
`\n${color.green(`\u2713 Update complete: ${currentVersion} \u2192 ${newVer}`)}\n`,
|
||||
);
|
||||
writeUpdateState(newVer);
|
||||
updateAgentSkill(color);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const reinstall =
|
||||
|
||||
@@ -10,8 +10,37 @@ describe("e2e: text chat", () => {
|
||||
test("text chat --help 正常退出", async () => {
|
||||
const { stderr, exitCode } = await runCommandE2e(TEXT_CHAT_ROUTES, ["text", "chat", "--help"]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
expect(stderr).toMatch(/--api\s+<chat\|responses>/i);
|
||||
expect(stderr).toMatch(/chat|--message|model|stream/i);
|
||||
});
|
||||
|
||||
test("text chat 拒绝未知的 --api 值", async () => {
|
||||
const { stderr, exitCode } = await runCommandE2e(TEXT_CHAT_ROUTES, [
|
||||
"text",
|
||||
"chat",
|
||||
"--api",
|
||||
"legacy",
|
||||
"--message",
|
||||
"hello",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--api|chat.*responses/i);
|
||||
});
|
||||
|
||||
test("text chat 在 Responses 模式拒绝 --thinking-budget", async () => {
|
||||
const { stderr, exitCode } = await runCommandE2e(TEXT_CHAT_ROUTES, [
|
||||
"text",
|
||||
"chat",
|
||||
"--api",
|
||||
"responses",
|
||||
"--message",
|
||||
"hello",
|
||||
"--thinking-budget",
|
||||
"8",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/thinking-budget.*Responses/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skipIf(!isDashScopeE2EReady())("e2e: text chat(DashScope)", () => {
|
||||
@@ -45,7 +74,42 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: text chat(DashScope)", () => {
|
||||
request?: { model?: string; messages?: Array<{ content?: string }> };
|
||||
}>(stdout);
|
||||
expect(data.request?.model).toBe("qwen3.8-max");
|
||||
expect(data.request?.messages?.some((m) => m.content === "干跑")).toBe(true);
|
||||
expect(data.request?.messages?.some((message) => message.content === "干跑")).toBe(true);
|
||||
});
|
||||
|
||||
test("text chat --api responses --dry-run 生成 Responses 请求", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCommandE2e(TEXT_CHAT_ROUTES, [
|
||||
"text",
|
||||
"chat",
|
||||
"--dry-run",
|
||||
"--api",
|
||||
"responses",
|
||||
"--model",
|
||||
"qwen3.8-max",
|
||||
"--system",
|
||||
"system",
|
||||
"--message",
|
||||
"hello",
|
||||
"--max-tokens",
|
||||
"8",
|
||||
"--tool",
|
||||
'{"type":"web_search"}',
|
||||
"--output",
|
||||
"json",
|
||||
]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<{ request?: Record<string, unknown> }>(stdout);
|
||||
expect(data.request).toMatchObject({
|
||||
model: "qwen3.8-max",
|
||||
input: [
|
||||
{ role: "system", content: "system" },
|
||||
{ role: "user", content: "hello" },
|
||||
],
|
||||
max_output_tokens: 8,
|
||||
tools: [{ type: "web_search" }],
|
||||
});
|
||||
expect(data.request).not.toHaveProperty("messages");
|
||||
expect(data.request).not.toHaveProperty("max_tokens");
|
||||
});
|
||||
|
||||
test("【qwen3.8-max】文本对话", async () => {
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import { BailianError, ExitCode } from "bailian-cli-core";
|
||||
import { afterEach, describe, expect, test, vi } from "vite-plus/test";
|
||||
import chatCommand from "../src/commands/text/chat.ts";
|
||||
import {
|
||||
extractResponsesStreamDelta,
|
||||
extractResponsesText,
|
||||
} from "../src/commands/text/responses.ts";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
function responsesStreamResponse(events: unknown[]): Response {
|
||||
const body = events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join("");
|
||||
return new Response(body, { headers: { "content-type": "text/event-stream" } });
|
||||
}
|
||||
|
||||
async function runResponsesStream(events: unknown[]): Promise<BailianError | undefined> {
|
||||
vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
||||
|
||||
try {
|
||||
await chatCommand.run({
|
||||
settings: { output: "json" },
|
||||
flags: {
|
||||
api: "responses",
|
||||
message: ["hello"],
|
||||
stream: true,
|
||||
},
|
||||
client: {
|
||||
request: async () => responsesStreamResponse(events),
|
||||
},
|
||||
} as never);
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(BailianError);
|
||||
return error as BailianError;
|
||||
}
|
||||
}
|
||||
|
||||
describe("Responses output", () => {
|
||||
test("extracts only output_text from message items", () => {
|
||||
const text = extractResponsesText({
|
||||
id: "resp_1",
|
||||
object: "response",
|
||||
status: "completed",
|
||||
output: [
|
||||
{ type: "reasoning", summary: [{ type: "summary_text", text: "thinking" }] },
|
||||
{ type: "web_search_call", status: "completed" },
|
||||
{ type: "message", content: [{ type: "output_text", text: "first" }] },
|
||||
{
|
||||
type: "message",
|
||||
content: [
|
||||
{ type: "refusal", text: "ignored" },
|
||||
{ type: "output_text", text: " second" },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(text).toBe("first second");
|
||||
});
|
||||
|
||||
test("extracts only response.output_text.delta stream events", () => {
|
||||
expect(extractResponsesStreamDelta({ type: "response.output_text.delta", delta: "hi" })).toBe(
|
||||
"hi",
|
||||
);
|
||||
expect(extractResponsesStreamDelta({ type: "response.web_search_call.completed" })).toBe("");
|
||||
});
|
||||
|
||||
test("streaming response.completed finishes successfully", async () => {
|
||||
const error = await runResponsesStream([
|
||||
{ type: "response.output_text.delta", sequence_number: 1, delta: "done" },
|
||||
{
|
||||
type: "response.completed",
|
||||
sequence_number: 2,
|
||||
response: {
|
||||
id: "resp_completed",
|
||||
object: "response",
|
||||
status: "completed",
|
||||
output: [],
|
||||
error: null,
|
||||
incomplete_details: null,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
test("streaming response.failed throws the original service message", async () => {
|
||||
const error = await runResponsesStream([
|
||||
{
|
||||
type: "response.failed",
|
||||
sequence_number: 1,
|
||||
response: {
|
||||
id: "resp_failed",
|
||||
object: "response",
|
||||
status: "failed",
|
||||
output: [],
|
||||
error: { code: "quota_exceeded", message: "provider quota exceeded" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(error?.exitCode).toBe(ExitCode.GENERAL);
|
||||
expect(error?.message).toBe("provider quota exceeded");
|
||||
});
|
||||
|
||||
test("streaming response.incomplete exits non-zero with the service reason", async () => {
|
||||
const error = await runResponsesStream([
|
||||
{
|
||||
type: "response.incomplete",
|
||||
sequence_number: 1,
|
||||
response: {
|
||||
id: "resp_incomplete",
|
||||
object: "response",
|
||||
status: "incomplete",
|
||||
output: [],
|
||||
incomplete_details: { reason: "max_output_tokens" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(error?.exitCode).toBe(ExitCode.GENERAL);
|
||||
expect(error?.message).toBe("Response incomplete: max_output_tokens");
|
||||
});
|
||||
|
||||
test("stream ending before response.completed exits non-zero", async () => {
|
||||
const error = await runResponsesStream([
|
||||
{ type: "response.output_text.delta", sequence_number: 1, delta: "partial" },
|
||||
]);
|
||||
|
||||
expect(error?.exitCode).toBe(ExitCode.GENERAL);
|
||||
expect(error?.message).toBe(
|
||||
"Stream disconnected before completion: stream closed before response.completed.",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, expect, test, vi } from "vite-plus/test";
|
||||
|
||||
const runtimeMocks = vi.hoisted(() => ({
|
||||
performBinaryUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
const childProcessMocks = vi.hoisted(() => ({
|
||||
execSync: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("bailian-cli-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("bailian-cli-runtime")>();
|
||||
return { ...actual, performBinaryUpdate: runtimeMocks.performBinaryUpdate };
|
||||
});
|
||||
|
||||
vi.mock("child_process", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("child_process")>();
|
||||
return { ...actual, execSync: childProcessMocks.execSync };
|
||||
});
|
||||
|
||||
import updateCommand from "../src/commands/update.ts";
|
||||
|
||||
let configDir: string;
|
||||
let previousConfigDir: string | undefined;
|
||||
let previousInstallMethod: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
configDir = mkdtempSync(join(tmpdir(), "bl-update-binary-"));
|
||||
previousConfigDir = process.env.BAILIAN_CONFIG_DIR;
|
||||
previousInstallMethod = process.env.BAILIAN_INSTALL_METHOD;
|
||||
process.env.BAILIAN_CONFIG_DIR = configDir;
|
||||
process.env.BAILIAN_INSTALL_METHOD = "binary";
|
||||
runtimeMocks.performBinaryUpdate.mockResolvedValue("1.15.0");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousConfigDir === undefined) delete process.env.BAILIAN_CONFIG_DIR;
|
||||
else process.env.BAILIAN_CONFIG_DIR = previousConfigDir;
|
||||
if (previousInstallMethod === undefined) delete process.env.BAILIAN_INSTALL_METHOD;
|
||||
else process.env.BAILIAN_INSTALL_METHOD = previousInstallMethod;
|
||||
rmSync(configDir, { recursive: true, force: true });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test("binary bl update syncs bailian skills after the CLI update succeeds", async () => {
|
||||
await updateCommand.run({
|
||||
identity: {
|
||||
binName: "bl",
|
||||
clientName: "bailian-cli",
|
||||
npmPackage: "bailian-cli",
|
||||
version: "1.14.3",
|
||||
},
|
||||
flags: { to: "1.15.0" },
|
||||
settings: {},
|
||||
} as never);
|
||||
|
||||
expect(runtimeMocks.performBinaryUpdate).toHaveBeenCalledWith("1.15.0");
|
||||
expect(childProcessMocks.execSync).toHaveBeenCalledWith("bl skill init", { stdio: "inherit" });
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bailian-cli-core",
|
||||
"version": "1.14.3",
|
||||
"version": "1.15.0",
|
||||
"description": "Core SDK for bailian-cli. See https://www.npmjs.com/package/bailian-cli for usage.",
|
||||
"homepage": "https://bailian.console.aliyun.com/cli",
|
||||
"bugs": {
|
||||
|
||||
@@ -6,6 +6,11 @@ export function chatPath(): string {
|
||||
return "/compatible-mode/v1/chat/completions";
|
||||
}
|
||||
|
||||
// ---- Responses (OpenAI Compatible) ----
|
||||
export function responsesPath(): string {
|
||||
return "/compatible-mode/v1/responses";
|
||||
}
|
||||
|
||||
// ---- Image Generation (DashScope) ----
|
||||
/** Async image API used by wan2.6-t2i / wan2.6-image (T2I) and similar message-format models. */
|
||||
export function imagePath(): string {
|
||||
|
||||
@@ -14,6 +14,7 @@ export {
|
||||
memorySearchPath,
|
||||
mcpWebSearchPath,
|
||||
profileSchemaPath,
|
||||
responsesPath,
|
||||
speechRecognizePath,
|
||||
speechSynthesizePath,
|
||||
taskPath,
|
||||
|
||||
@@ -108,6 +108,44 @@ export interface StreamChunk {
|
||||
};
|
||||
}
|
||||
|
||||
// ---- Responses (OpenAI Compatible) ----
|
||||
|
||||
export interface ResponsesRequest {
|
||||
model: string;
|
||||
input: ChatMessage[];
|
||||
max_output_tokens?: number;
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
stream?: boolean;
|
||||
tools?: Array<Record<string, unknown>>;
|
||||
enable_thinking?: boolean;
|
||||
}
|
||||
|
||||
export interface ResponsesOutputContent {
|
||||
type: string;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export interface ResponsesOutputItem {
|
||||
type: string;
|
||||
content?: ResponsesOutputContent[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface ResponsesResponse {
|
||||
id: string;
|
||||
object: "response";
|
||||
status: string;
|
||||
output: ResponsesOutputItem[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface ResponsesStreamEvent {
|
||||
type: string;
|
||||
delta?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
// ---- Image (DashScope) ----
|
||||
|
||||
export interface DashScopeImageRequest {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { responsesPath } from "../src/index.ts";
|
||||
|
||||
describe("Responses API", () => {
|
||||
test("uses the OpenAI-compatible Responses endpoint", () => {
|
||||
expect(responsesPath()).toBe("/compatible-mode/v1/responses");
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "knowledge-studio-cli",
|
||||
"version": "1.14.3",
|
||||
"version": "1.15.0",
|
||||
"description": "Lightweight RAG CLI for Aliyun Model Studio — focused on knowledge-base retrieval.",
|
||||
"keywords": [
|
||||
"alibaba-cloud",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bailian-cli-runtime",
|
||||
"version": "1.14.3",
|
||||
"version": "1.15.0",
|
||||
"description": "Runtime framework for bailian-cli (createCli, registry, args, output, pipeline). See https://www.npmjs.com/package/bailian-cli for usage.",
|
||||
"homepage": "https://bailian.console.aliyun.com/cli",
|
||||
"bugs": {
|
||||
|
||||
@@ -209,6 +209,25 @@ function errorMessage(err: unknown): string {
|
||||
return String(err);
|
||||
}
|
||||
|
||||
async function syncAgentSkillsAfterUpdate(
|
||||
dim: string,
|
||||
green: string,
|
||||
yellow: string,
|
||||
reset: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
process.stderr.write(` ${dim}Syncing agent skill...${reset}\n`);
|
||||
const { execSync } = await import("child_process");
|
||||
execSync("bl skill init", { stdio: "inherit" });
|
||||
process.stderr.write(` ${green}\u2713 Agent skill updated.${reset}\n\n`);
|
||||
} catch (error) {
|
||||
process.stderr.write(
|
||||
` ${yellow}\u26a0 Agent skill sync failed: ${errorMessage(error)}${reset}\n`,
|
||||
);
|
||||
process.stderr.write(` ${yellow} Run manually: bl skill init${reset}\n\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform auto-update for npm or binary installs.
|
||||
* Returns true if update succeeded, false otherwise.
|
||||
@@ -256,6 +275,7 @@ export async function performAutoUpdate(
|
||||
writeState({ lastChecked: Date.now(), latestVersion: newVer });
|
||||
process.stderr.write(` ${green}✓ Update complete: ${currentVersion} → ${newVer}${reset}\n`);
|
||||
process.stderr.write(` ${dim}Run ${cyan}bl --version${reset}${dim} to verify.${reset}\n\n`);
|
||||
await syncAgentSkillsAfterUpdate(dim, green, yellow, reset);
|
||||
pendingNotification = null;
|
||||
return true;
|
||||
} catch (err) {
|
||||
@@ -297,16 +317,7 @@ export async function performAutoUpdate(
|
||||
);
|
||||
process.stderr.write(` ${dim}Run ${cyan}bl --version${reset}${dim} to verify.${reset}\n\n`);
|
||||
|
||||
try {
|
||||
process.stderr.write(` ${dim}Syncing agent skill...${reset}\n`);
|
||||
execSync(`npx skills add modelstudioai/cli --all -g -y`, { stdio: "inherit" });
|
||||
process.stderr.write(` ${green}✓ Agent skill updated.${reset}\n\n`);
|
||||
} catch (err) {
|
||||
process.stderr.write(` ${yellow}⚠ Agent skill sync failed: ${errorMessage(err)}${reset}\n`);
|
||||
process.stderr.write(
|
||||
` ${yellow} Run manually: npx skills add modelstudioai/cli --all -g -y${reset}\n\n`,
|
||||
);
|
||||
}
|
||||
await syncAgentSkillsAfterUpdate(dim, green, yellow, reset);
|
||||
|
||||
pendingNotification = null;
|
||||
return true;
|
||||
|
||||
@@ -1,13 +1,58 @@
|
||||
import { expect, test } from "vite-plus/test";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, expect, test, vi } from "vite-plus/test";
|
||||
|
||||
const binaryUpdateMocks = vi.hoisted(() => ({
|
||||
performBinaryUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
const childProcessMocks = vi.hoisted(() => ({
|
||||
execSync: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../src/utils/binary-update.ts", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../src/utils/binary-update.ts")>();
|
||||
return { ...actual, performBinaryUpdate: binaryUpdateMocks.performBinaryUpdate };
|
||||
});
|
||||
|
||||
vi.mock("child_process", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("child_process")>();
|
||||
return { ...actual, execSync: childProcessMocks.execSync };
|
||||
});
|
||||
|
||||
import {
|
||||
compareVersion,
|
||||
isMajorUpgrade,
|
||||
isNewerVersion,
|
||||
isPrerelease,
|
||||
parseVersion,
|
||||
performAutoUpdate,
|
||||
shouldAutoUpdate,
|
||||
} from "../src/utils/update-checker.ts";
|
||||
|
||||
let configDir: string;
|
||||
let previousConfigDir: string | undefined;
|
||||
let previousInstallMethod: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
configDir = mkdtempSync(join(tmpdir(), "bl-auto-update-binary-"));
|
||||
previousConfigDir = process.env.BAILIAN_CONFIG_DIR;
|
||||
previousInstallMethod = process.env.BAILIAN_INSTALL_METHOD;
|
||||
process.env.BAILIAN_CONFIG_DIR = configDir;
|
||||
process.env.BAILIAN_INSTALL_METHOD = "binary";
|
||||
binaryUpdateMocks.performBinaryUpdate.mockResolvedValue("2.0.0");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousConfigDir === undefined) delete process.env.BAILIAN_CONFIG_DIR;
|
||||
else process.env.BAILIAN_CONFIG_DIR = previousConfigDir;
|
||||
if (previousInstallMethod === undefined) delete process.env.BAILIAN_INSTALL_METHOD;
|
||||
else process.env.BAILIAN_INSTALL_METHOD = previousInstallMethod;
|
||||
rmSync(configDir, { recursive: true, force: true });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test("parseVersion strips pre-release and build metadata", () => {
|
||||
expect(parseVersion("1.4.2")).toEqual([1, 4, 2]);
|
||||
expect(parseVersion("2.0.0-beta.1")).toEqual([2, 0, 0]);
|
||||
@@ -124,3 +169,11 @@ test("shouldAutoUpdate only targets stable releases with a significant gap", ()
|
||||
// Same core, release over its pre-release: notify only (no major gap).
|
||||
expect(shouldAutoUpdate("1.4.2", "1.4.2-beta.1")).toBe(false);
|
||||
});
|
||||
|
||||
test("binary auto-update syncs bailian skills after the CLI update succeeds", async () => {
|
||||
const updated = await performAutoUpdate("1.14.3", "2.0.0");
|
||||
|
||||
expect(updated).toBe(true);
|
||||
expect(binaryUpdateMocks.performBinaryUpdate).toHaveBeenCalledWith("2.0.0");
|
||||
expect(childProcessMocks.execSync).toHaveBeenCalledWith("bl skill init", { stdio: "inherit" });
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
Agent skill for **Alibaba Cloud Model Studio CLI** (`bl`) resource hub — apps, memory, RAG, usage/quota, MCP, and hub `reference/`.
|
||||
|
||||
- Shared protocol: `bailian-protocol` (install via `--all -g`)
|
||||
- Shared protocol: `bailian-protocol` (install via `bl skill init`)
|
||||
- Soft hand-offs (optional skills): `bailian-gen` · `bailian-finetune` · `bailian-managed-agent`
|
||||
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
For CLI installation, authentication, and examples, see the [main README](../../README.md).
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
**阿里云百炼 CLI**(`bl`)的资源管理 Agent 技能 — 应用、记忆、RAG、用量/额度、MCP,以及 hub `reference/`。
|
||||
|
||||
- 共享协议:`bailian-protocol`(通过 `--all -g` 与整家族同装)
|
||||
- 共享协议:`bailian-protocol`(通过 `bl skill init` 与整家族同装)
|
||||
- 软 hand-off(可选):`bailian-gen` · `bailian-finetune` · `bailian-managed-agent`
|
||||
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
CLI 的安装、认证和使用示例请查看[主 README](../../README.zh.md)。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: bailian-cli
|
||||
metadata:
|
||||
version: "1.14.3"
|
||||
version: "1.15.0"
|
||||
requires:
|
||||
bins: ["bl"]
|
||||
description: >-
|
||||
@@ -10,7 +10,7 @@ description: >-
|
||||
工作空间、MCP 市场、pipeline、文件上传、console API、登录鉴权与配置、
|
||||
Agent skill 安装/列表/更新/卸载(bl skill add|list|update|remove,百炼 skill registry)。
|
||||
用户点名百炼 / DashScope / `bl`,或继续既有 `bl` 工作流时直接使用。
|
||||
共享协议(consent / 版本预检 / 鉴权 / 错误上报)在 bailian-protocol;官方安装 `npx skills add modelstudioai/cli --all -g`。
|
||||
共享协议(consent / 版本预检 / 鉴权 / 错误上报)在 bailian-protocol;官方安装 `bl skill init`。
|
||||
家族路由:生图/生视频/配音/语音合成/转写 → bailian-gen;精调/微调/训练/数据集 → bailian-finetune;
|
||||
agents.yaml 托管 Agent → bailian-managed-agent。
|
||||
不要用于普通问答、编程、写作、翻译、摘要、泛搜索,或图片理解等宿主自己能做的任务(普通问答、编程、写作、翻译、摘要、泛搜索不触发)。
|
||||
@@ -19,14 +19,14 @@ description: >-
|
||||
|
||||
# Aliyun Model Studio CLI (`bl`)
|
||||
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Provider selection and consent, Version & updates (pre-flight checklist), Setup & auth, and CLI errors: report an issue. If that protocol file is missing, stop and run `npx skills add modelstudioai/cli --all -g`; do not guess auth/consent.**
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Provider selection and consent, Version & updates (pre-flight checklist), Setup & auth, and CLI errors: report an issue. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
|
||||
|
||||
> **Family hub** — This skill owns Bailian resource commands and the hub `reference/` (apps, knowledge, usage, auth, config, …).
|
||||
> Shared protocol → [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md) (install the full family with `--all -g`).
|
||||
> Soft hand-offs by skill name (Read if installed; else `bl … --help` / prompt `npx skills add modelstudioai/cli --all -g`): `bailian-gen` (media) · `bailian-finetune` (training) · `bailian-managed-agent` (agents.yaml IaC).
|
||||
> Shared protocol → [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md) (install the full family with `bl skill init`).
|
||||
> Soft hand-offs by skill name (Read if installed; else `bl … --help` / prompt `bl skill init`): `bailian-gen` (media) · `bailian-finetune` (training) · `bailian-managed-agent` (agents.yaml IaC).
|
||||
> Do not invoke it for ordinary reasoning, coding, writing, translation, summarization, generic research, or image understanding the host agent can complete directly.
|
||||
>
|
||||
> **Install (supported):** `npx skills add modelstudioai/cli --all -g`
|
||||
> **Install (supported):** `bl skill init`
|
||||
|
||||
## Command reference (authoritative)
|
||||
|
||||
@@ -115,7 +115,7 @@ schema-export commands.
|
||||
|
||||
## Routing reminders
|
||||
|
||||
- Image/video/audio generation or editing → skill `bailian-gen` (class 3 consent from `bailian-protocol`). Fine-tuning / datasets / deployments → `bailian-finetune`. agents.yaml IaC → `bailian-managed-agent`. Soft hand-off: Read sibling skill if installed; else `bl … --help` or prompt `npx skills add modelstudioai/cli --all -g`. Image understanding the host agent can do → host-first; use `bl vision` / `bl omni` only when the user names a Bailian model or the media (video/audio files) exceeds host capability.
|
||||
- Image/video/audio generation or editing → skill `bailian-gen` (class 3 consent from `bailian-protocol`). Fine-tuning / datasets / deployments → `bailian-finetune`. agents.yaml IaC → `bailian-managed-agent`. Soft hand-off: Read sibling skill if installed; else `bl … --help` or prompt `bl skill init`. Image understanding the host agent can do → host-first; use `bl vision` / `bl omni` only when the user names a Bailian model or the media (video/audio files) exceeds host capability.
|
||||
- Answer ordinary reasoning, coding, writing, translation, summarization, and generic research with the host agent's native capabilities; do not bounce them through `bl text chat` or `bl search web`.
|
||||
- Usage / quota / credits questions that do not name a product → ask which product (Bailian or another AI service) first; run `bl usage` / `bl quota` only after the user picks Bailian or Bailian context is already established.
|
||||
- "Remember this" and memory requests default to the host agent's own memory; `bl memory *` is only for Bailian app memory resources.
|
||||
|
||||
@@ -56,7 +56,7 @@ Use this index for the skill-scoped quick index and global flags.
|
||||
| `bl skill list` | No Auth | List registry skills and diff against local installs | [skill.md](skill.md) |
|
||||
| `bl skill remove` | No Auth | Remove locally installed skills (registry is untouched) | [skill.md](skill.md) |
|
||||
| `bl skill update` | No Auth | Update installed skills to the latest registry versions | [skill.md](skill.md) |
|
||||
| `bl text chat` | API Key | Send a chat completion (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl text chat` | API Key | Send a text model request (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl token-plan add-member` | AK/SK | Add a member to a Token Plan organization | [token-plan.md](token-plan.md) |
|
||||
| `bl token-plan assign-seats` | AK/SK | Batch assign Token Plan seats to members | [token-plan.md](token-plan.md) |
|
||||
| `bl token-plan create-key` | AK/SK | Create a Token Plan API key for a seat | [token-plan.md](token-plan.md) |
|
||||
|
||||
@@ -7,38 +7,39 @@ Index: [index.md](index.md)
|
||||
|
||||
## Commands in this group
|
||||
|
||||
| Command | Authentication | Description |
|
||||
| -------------- | -------------- | ----------------------------------------------------- |
|
||||
| `bl text chat` | API Key | Send a chat completion (OpenAI compatible, DashScope) |
|
||||
| Command | Authentication | Description |
|
||||
| -------------- | -------------- | -------------------------------------------------------- |
|
||||
| `bl text chat` | API Key | Send a text model request (OpenAI compatible, DashScope) |
|
||||
|
||||
## Command details
|
||||
|
||||
### `bl text chat`
|
||||
|
||||
| Field | Value |
|
||||
| ------------------ | ----------------------------------------------------- |
|
||||
| **Name** | `text chat` |
|
||||
| **Description** | Send a chat completion (OpenAI compatible, DashScope) |
|
||||
| **Authentication** | API Key |
|
||||
| **Usage** | `bl text chat --message <text> [flags]` |
|
||||
| Field | Value |
|
||||
| ------------------ | -------------------------------------------------------- |
|
||||
| **Name** | `text chat` |
|
||||
| **Description** | Send a text model request (OpenAI compatible, DashScope) |
|
||||
| **Authentication** | API Key |
|
||||
| **Usage** | `bl text chat --message <text> [flags]` |
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------ | ------ | -------- | --------------------------------------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model ID (default: qwen3.8-max) |
|
||||
| `--message <text>` | array | no | Message text (repeatable, prefix role: to set role); or use --messages-file |
|
||||
| `--messages-file <path>` | string | no | JSON file with messages array (use - for stdin) |
|
||||
| `--system <text>` | string | no | System prompt |
|
||||
| `--max-tokens <n>` | number | no | Maximum tokens to generate (default: 4096) |
|
||||
| `--temperature <n>` | number | no | Sampling temperature (0.0, 2.0] |
|
||||
| `--top-p <n>` | number | no | Nucleus sampling threshold |
|
||||
| `--stream` | switch | no | Stream response tokens (default: on in TTY) |
|
||||
| `--tool <json-or-path>` | array | no | Tool definition as JSON or file path (repeatable) |
|
||||
| `--enable-thinking` | switch | no | Enable thinking/reasoning mode (for qwen3/qwq models) |
|
||||
| `--thinking-budget <n>` | number | no | Max tokens for thinking (default: 4096) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------- | ------ | -------- | --------------------------------------------------------------------------- |
|
||||
| `--api <chat\|responses>` | string | no | API to call (default: chat) |
|
||||
| `--model <model>` | string | no | Model ID (default: qwen3.8-max) |
|
||||
| `--message <text>` | array | no | Message text (repeatable, prefix role: to set role); or use --messages-file |
|
||||
| `--messages-file <path>` | string | no | JSON file with messages array (use - for stdin) |
|
||||
| `--system <text>` | string | no | System prompt |
|
||||
| `--max-tokens <n>` | number | no | Maximum tokens to generate (default: 4096) |
|
||||
| `--temperature <n>` | number | no | Sampling temperature (0.0, 2.0] |
|
||||
| `--top-p <n>` | number | no | Nucleus sampling threshold |
|
||||
| `--stream` | switch | no | Stream response tokens (default: on in TTY) |
|
||||
| `--tool <json-or-path>` | array | no | Tool definition as JSON or file path (repeatable) |
|
||||
| `--enable-thinking` | switch | no | Enable thinking/reasoning mode (for qwen3/qwq models) |
|
||||
| `--thinking-budget <n>` | number | no | Max tokens for thinking (default: 4096) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -46,6 +47,10 @@ Index: [index.md](index.md)
|
||||
bl text chat --message "What is Qwen?"
|
||||
```
|
||||
|
||||
```bash
|
||||
bl text chat --api responses --model qwen3.8-max --tool '{"type":"web_search"}' --message "Search for recent Alibaba Cloud news"
|
||||
```
|
||||
|
||||
```bash
|
||||
bl text chat --model qwen-max --system "You are a coding assistant." --message "Write fizzbuzz in Python"
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: bailian-finetune
|
||||
metadata:
|
||||
version: "1.14.3"
|
||||
version: "1.15.0"
|
||||
requires:
|
||||
bins: ["bl"]
|
||||
description: >-
|
||||
@@ -11,12 +11,12 @@ description: >-
|
||||
upload 拿 file-id → finetune create 建任务 → watch 看进度 → export 导出 → deploy 上线,需要 API key;
|
||||
写操作先用 `--dry-run` 预览。反触发:用户点名火山方舟/ark 的精调不走本 skill;只是要选哪个模型走
|
||||
bailian-model-recommend;用现成模型生图生视频走 bailian-gen;百炼其他资源管理走 bailian-cli。
|
||||
官方安装:`npx skills add modelstudioai/cli --all -g`(与共享协议 bailian-protocol 同装)。
|
||||
官方安装:`bl skill init`(与共享协议 bailian-protocol 同装)。
|
||||
---
|
||||
|
||||
# Bailian fine-tuning pipeline (`bl dataset` / `bl finetune` / `bl deploy`)
|
||||
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Version & updates (pre-flight checklist), Setup & auth, and CLI errors: report an issue. Command details are authoritative in [`reference/`](reference/index.md) (dataset / finetune / deploy) and `bl <command> --help` — do not guess flags. The whole pipeline requires an API key. If that protocol file is missing, stop and run `npx skills add modelstudioai/cli --all -g`; do not guess auth/consent.**
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Version & updates (pre-flight checklist), Setup & auth, and CLI errors: report an issue. Command details are authoritative in [`reference/`](reference/index.md) (dataset / finetune / deploy) and `bl <command> --help` — do not guess flags. The whole pipeline requires an API key. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
|
||||
|
||||
## End-to-end workflow (follow in order)
|
||||
|
||||
@@ -63,7 +63,7 @@ bl deploy text create --model my-qwen-sft --name my-svc
|
||||
|
||||
## Common hand-offs
|
||||
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `npx skills add modelstudioai/cli --all -g`):
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `bl skill init`):
|
||||
|
||||
- After deployment, try the model or generate content → skill `bailian-gen` (media) or `bl text chat` (fallback: `bl image\|video\|text --help`).
|
||||
- Unsure which base model to pick → `bailian-model-recommend` / `bl advisor recommend`.
|
||||
@@ -71,5 +71,5 @@ bl deploy text create --model my-qwen-sft --name my-svc
|
||||
|
||||
## references
|
||||
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `--all -g`)
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `bl skill init`)
|
||||
- [reference/](reference/index.md) — command details
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: bailian-gen
|
||||
metadata:
|
||||
version: "1.14.3"
|
||||
version: "1.15.0"
|
||||
requires:
|
||||
bins: ["bl"]
|
||||
description: >-
|
||||
@@ -13,12 +13,12 @@ description: >-
|
||||
图片和语音同步返回并落地本地文件,视频是异步任务、用 `--download` 或轮询取回;本地文件直接传路径,CLI 自动上传。
|
||||
反触发:宿主自己能做的图片理解、普通问答、编程、写作、翻译不走本技能;百炼应用/知识库/用量/额度走 bailian-cli;
|
||||
精调训练走 bailian-finetune。
|
||||
官方安装:`npx skills add modelstudioai/cli --all -g`(与共享协议 bailian-protocol 同装)。
|
||||
官方安装:`bl skill init`(与共享协议 bailian-protocol 同装)。
|
||||
---
|
||||
|
||||
# Bailian media generation (`bl image` / `bl video` / `bl speech` / `bl omni`)
|
||||
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Provider selection and consent (one-time ask templates), Version & updates (pre-flight checklist), and CLI errors: report an issue. Command details are authoritative in [`reference/`](reference/index.md) and `bl <command> --help` — do not guess flags. If that protocol file is missing, stop and run `npx skills add modelstudioai/cli --all -g`; do not guess auth/consent.**
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Provider selection and consent (one-time ask templates), Version & updates (pre-flight checklist), and CLI errors: report an issue. Command details are authoritative in [`reference/`](reference/index.md) and `bl <command> --help` — do not guess flags. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
|
||||
|
||||
## Consent (short version; full rules in bailian-protocol)
|
||||
|
||||
@@ -78,7 +78,7 @@ If one or more `bl` commands actually ran, proactively add a one-line summary in
|
||||
|
||||
## Common hand-offs
|
||||
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `npx skills add modelstudioai/cli --all -g`):
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `bl skill init`):
|
||||
|
||||
- Generation failed and it is not a usage/auth/content-filter issue → follow the issue-reporting flow in `bailian-protocol` ([`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md#cli-errors-report-an-issue)) and ask once whether to report.
|
||||
- Managing Bailian apps / knowledge bases / usage → skill `bailian-cli` (fallback: `bl app\|knowledge\|usage --help`).
|
||||
@@ -86,5 +86,5 @@ If one or more `bl` commands actually ran, proactively add a one-line summary in
|
||||
|
||||
## references
|
||||
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `--all -g`)
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `bl skill init`)
|
||||
- [reference/](reference/index.md) — command details
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: bailian-managed-agent
|
||||
metadata:
|
||||
version: "1.14.3"
|
||||
version: "1.15.0"
|
||||
requires:
|
||||
bins: ["bl"]
|
||||
description: >-
|
||||
@@ -11,12 +11,12 @@ description: >-
|
||||
apply / destroy 变更远端资源且必须带 `--yes`,务必先 plan 给用户看 diff 再让其确认。
|
||||
反触发:调用已上线的百炼应用/智能体走 bailian-app-call 或 `bl app`;宿主 agent 自身的记忆、技能、
|
||||
子代理不走本 skill;生图生视频走 bailian-gen。
|
||||
官方安装:`npx skills add modelstudioai/cli --all -g`(与共享协议 bailian-protocol 同装)。
|
||||
官方安装:`bl skill init`(与共享协议 bailian-protocol 同装)。
|
||||
---
|
||||
|
||||
# Bailian managed agent IaC (`bl managed-agent`)
|
||||
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Version & updates (pre-flight checklist) and CLI errors: report an issue. Command details are authoritative in [`reference/managed-agent.md`](reference/managed-agent.md) and `bl managed-agent --help` — do not guess flags. If that protocol file is missing, stop and run `npx skills add modelstudioai/cli --all -g`; do not guess auth/consent.**
|
||||
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Version & updates (pre-flight checklist) and CLI errors: report an issue. Command details are authoritative in [`reference/managed-agent.md`](reference/managed-agent.md) and `bl managed-agent --help` — do not guess flags. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
|
||||
|
||||
## Safety guardrail (the most important rule)
|
||||
|
||||
@@ -60,7 +60,7 @@ Flags, usage, and examples: see [`reference/`](reference/index.md) or `bl <comma
|
||||
|
||||
## Common hand-offs
|
||||
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `npx skills add modelstudioai/cli --all -g`):
|
||||
软 hand-off(按 skill **名**;已安装则 Read,否则 `--help` / 提示 `bl skill init`):
|
||||
|
||||
- Call an already published Bailian app/assistant → `bailian-app-call`, or skill `bailian-cli` (`bl app list` / `call`; fallback: `bl app --help`).
|
||||
- Choosing the model referenced in agents.yaml → `bailian-model-recommend`.
|
||||
@@ -68,5 +68,5 @@ Flags, usage, and examples: see [`reference/`](reference/index.md) or `bl <comma
|
||||
|
||||
## references
|
||||
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `--all -g`)
|
||||
- [bailian-protocol](../bailian-protocol/SKILL.md) — shared protocol (install via `bl skill init`)
|
||||
- [reference/](reference/index.md) — command details
|
||||
|
||||
@@ -5,10 +5,10 @@ Shared execution protocol for the **bailian-\*** Agent Skill family (consent, ve
|
||||
Business skills (`bailian-cli`, `bailian-gen`, `bailian-finetune`, `bailian-managed-agent`) read this skill before running `bl`. **Supported install** is the full family:
|
||||
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
The Agent Skills / `npx skills` installer does **not** auto-resolve skill dependencies. Prefer `--all -g` over subset `-s` installs.
|
||||
Use `bl skill init`. Subset installs should explicitly include `bailian-protocol` when needed.
|
||||
|
||||
For CLI installation and command examples, see the [main README](../../README.md).
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
业务 skill(`bailian-cli` / `bailian-gen` / `bailian-finetune` / `bailian-managed-agent`)在跑 `bl` 前应读取本 skill。**官方安装**为整包:
|
||||
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
```
|
||||
|
||||
Agent Skills / `npx skills` **不会**自动解析 skill 依赖。请优先使用 `--all -g`,避免只装单个业务 skill。
|
||||
请使用 `bl skill init`。子集安装时如需要请显式带上 `bailian-protocol`。
|
||||
|
||||
CLI 安装与命令示例见[主 README](../../README.zh.md)。
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
name: bailian-protocol
|
||||
metadata:
|
||||
version: "1.14.3"
|
||||
version: "1.15.0"
|
||||
requires:
|
||||
bins: ["bl"]
|
||||
description: >-
|
||||
阿里云百炼 `bl` 家族共享执行协议(consent 确认、版本预检、鉴权/安装、错误上报、本地文件与输出约定)。
|
||||
不是面向用户意图的业务入口;当任一 bailian-* 业务 skill(bailian-cli / bailian-gen /
|
||||
bailian-finetune / bailian-managed-agent)执行前需要公共上下文,或用户首次安装/鉴权/`bl` 报错需上报时读取本 skill。
|
||||
官方安装为整包:`npx skills add modelstudioai/cli --all -g`(与业务 skill 同装);Agent Skills / `npx skills` 不会按 metadata 自动拉依赖。
|
||||
官方安装为整包:`bl skill init`(与业务 skill 同装)。
|
||||
---
|
||||
|
||||
# Bailian shared protocol (`bailian-protocol`)
|
||||
@@ -18,10 +18,10 @@ description: >-
|
||||
> **Install(supported):** 整包装齐,含本 skill 与全部业务 skill:
|
||||
>
|
||||
> ```bash
|
||||
> npx skills add modelstudioai/cli --all -g
|
||||
> bl skill init
|
||||
> ```
|
||||
>
|
||||
> Agent Skills / `npx skills` **不会**解析 frontmatter 依赖字段。子集 `-s` 为 advanced / 不推荐;若坚持子集,必须**手动**同时带上 `bailian-protocol`,否则业务 skill 的相对路径 Read 会失败。
|
||||
> 子集安装请显式带上 `bailian-protocol`(例如 `bl skill add --name bailian-protocol,bailian-gen`),否则业务 skill 的相对路径 Read 会失败。
|
||||
|
||||
## Provider selection and consent
|
||||
|
||||
@@ -44,7 +44,7 @@ After approval, treat Bailian as selected for the current task. Do not ask again
|
||||
## Family routing & hand-offs
|
||||
|
||||
业务路由(**软 hand-off**:按 skill **名**路由;已安装则 Read 其 `SKILL.md`,未安装则用 `bl <cmd> --help`,或提示整包安装
|
||||
`npx skills add modelstudioai/cli --all -g`):
|
||||
`bl skill init`):
|
||||
|
||||
| Intent | Skill | Fallback |
|
||||
| ------------------------------------- | ----------------------- | ----------------------------------------------- |
|
||||
@@ -55,7 +55,7 @@ After approval, treat Bailian as selected for the current task. Do not ask again
|
||||
|
||||
**共享协议** vs **软 hand-off**:
|
||||
|
||||
- `bailian-protocol`:靠 `--all -g` 与业务 skill 同装;CRITICAL 可用相对路径 `../bailian-protocol/…`。读不到则停止跑 `bl`,提示整包安装。
|
||||
- `bailian-protocol`:靠 `bl skill init` 与业务 skill 同装;CRITICAL 可用相对路径 `../bailian-protocol/…`。读不到则停止跑 `bl`,提示整包安装。
|
||||
- 其它 bailian-\* 业务 skill:只按名字提及,**不要**写死 `../bailian-*/SKILL.md` 当执行前提。
|
||||
|
||||
## Version & updates (after provider selection, before the first `bl` command)
|
||||
|
||||
@@ -114,7 +114,7 @@ Offer reporting when **none** of EXCLUDE applies **and** any of the following ho
|
||||
|
||||
### Before offering to report
|
||||
|
||||
1. Align versions: [SKILL.md → Version & updates](../SKILL.md#version--updates-after-provider-selection-before-the-first-bl-command) — run `bl update` and `npx skills add modelstudioai/cli --all -g -y` if mismatched.
|
||||
1. Align versions: [SKILL.md → Version & updates](../SKILL.md#version--updates-after-provider-selection-before-the-first-bl-command) — run `bl update` and `bl skill init` if mismatched.
|
||||
2. Confirm `bl auth status` is healthy (for commands that need auth).
|
||||
3. Retry once with `--verbose` if stderr was thin.
|
||||
|
||||
|
||||
@@ -11,16 +11,37 @@ inspect config keys. Day-to-day command routing lives in the business skills
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install -g bailian-cli
|
||||
# Recommended: install the full bailian-* skill family (includes bailian-protocol)
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
**prefer npm** (Node.js **≥ 18.17.0**); use the binary installer only when Node/npm is unavailable.
|
||||
|
||||
# Advanced / not recommended: skills CLI does not auto-pull bailian-protocol
|
||||
# npx skills add modelstudioai/cli -g -s bailian-protocol -s bailian-gen
|
||||
# npx skills add modelstudioai/cli -g -s bailian-protocol -s bailian-finetune
|
||||
# npx skills add modelstudioai/cli -g -s bailian-protocol -s bailian-managed-agent
|
||||
# npx skills add modelstudioai/cli -g -s bailian-protocol -s bailian-cli
|
||||
### 1. Recommended: npm
|
||||
|
||||
```bash
|
||||
# node -v ≥ 18.17.0; global install via npm only (do not use pnpm/yarn)
|
||||
npm install -g bailian-cli
|
||||
bl skill init
|
||||
```
|
||||
|
||||
### 2. Fallback: binary (no Node)
|
||||
|
||||
When there is no usable Node/npm, or Node is too old for the npm path:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
# The script runs bl skill init after installing the CLI; if that fails, run it manually
|
||||
```
|
||||
|
||||
Windows PowerShell: `irm https://bailian.aliyun.com/cli/install.ps1 | iex`
|
||||
|
||||
### Skills
|
||||
|
||||
- **Supported:** `bl skill init` (installs every `bailian-*`, including `bailian-protocol`)
|
||||
- **Advanced / subset** (include protocol when needed):
|
||||
|
||||
```bash
|
||||
# bl skill add --name bailian-protocol,bailian-gen
|
||||
# bl skill add --name bailian-protocol,bailian-finetune
|
||||
# bl skill add --name bailian-protocol,bailian-managed-agent
|
||||
# bl skill add --name bailian-protocol,bailian-cli
|
||||
```
|
||||
|
||||
Verify: `bl --version` (prints `bl X.Y.Z`).
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
3. Compare the two versions (ignore the `bl` prefix; compare only `X.Y.Z`):
|
||||
- If `metadata.version` ≠ `bl --version`, refresh skills before doing anything else:
|
||||
```bash
|
||||
npx skills add modelstudioai/cli --all -g -y
|
||||
bl skill init
|
||||
```
|
||||
- Do not trust a stale `reference/` when versions mismatch — flags may be wrong.
|
||||
4. Check the latest published CLI version:
|
||||
@@ -26,7 +26,7 @@
|
||||
5. If the installed `bl` is **older** than the latest npm version, **STOP** the current task and **ask the user** (report skill version, installed CLI version, and npm latest):
|
||||
> A newer version of bl is available (current: X.Y.Z, latest: A.B.C). Upgrade before continuing?
|
||||
- **Do NOT auto-upgrade silently** — the user decides.
|
||||
- If the user agrees: run `bl update`, then continue. (`bl update` upgrades `bailian-cli` via npm and, on success, also runs `npx skills add modelstudioai/cli --all -g -y` to keep skills in lockstep across all agent apps.)
|
||||
- If the user agrees: run `bl update`, then continue. (`bl update` uses the detected install channel and, on success, also runs `bl skill init` to keep skills in lockstep across all agent apps.)
|
||||
- If the user declines: continue with the current version and note it in the summary.
|
||||
- If `npm view` / `bl update` fails (offline, registry blocked, permission): continue with the current `bl` and tell the user it could not be updated.
|
||||
6. Only proceed with the user's actual task after the above is resolved.
|
||||
@@ -35,14 +35,18 @@
|
||||
|
||||
## Missing `bl`
|
||||
|
||||
If `bl --version` fails, install the CLI and skills:
|
||||
If `bl --version` fails, install the CLI and skills (same order as [setup.md → Install](setup.md#install) / root `INSTALL.md`: **npm first**):
|
||||
|
||||
```bash
|
||||
# Recommended — Node.js ≥ 18.17.0; npm only (do not use pnpm/yarn)
|
||||
npm install -g bailian-cli
|
||||
npx skills add modelstudioai/cli --all -g
|
||||
bl skill init
|
||||
|
||||
# Fallback — no usable Node/npm:
|
||||
# curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
|
||||
```
|
||||
|
||||
Do not install a single business skill alone — use `--all -g` so `bailian-protocol` is present.
|
||||
Do not install a single business skill alone — use `bl skill init` so `bailian-protocol` is present.
|
||||
|
||||
## Mention it in the task summary
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Ownership of each top-level command group is declared in `GROUP_OWNER_SKILL` below.
|
||||
* Unmapped groups fall back to `bailian-cli` (hub) so new commands never block generation.
|
||||
*
|
||||
* Committed to git; consumed by bailian-* Agent Skills (`npx skills add modelstudioai/cli`).
|
||||
* Committed to git; consumed by bailian-* Agent Skills (`bl skill init`).
|
||||
*
|
||||
* Run: pnpm --filter bailian-cli run generate:reference
|
||||
* Also run via `pnpm run sync:skill-assets` or the repo pre-commit hook.
|
||||
|
||||
Reference in New Issue
Block a user