Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ca69316
feat(cli): 新增 knowledge search 和 knowledge chat 命令支持
clark-fc Jun 26, 2026
eaa6b07
build(kscli): 构建并发布 knowledge-studio-cli 包
clark-fc Jun 26, 2026
4745d70
feat(release): 支持 knowledge-studio-cli 的构建与发布流程
clark-fc Jun 26, 2026
ead1bc0
refactor(release): 重构发布流程并合并知识库发布逻辑
clark-fc Jun 26, 2026
d2aa8ca
docs(cli): 统一所有参考文档表格格式及添加全局参数说明
clark-fc Jun 26, 2026
2ec2f34
feat(cli): 支持多模态消息内容及图片URL数组
clark-fc Jun 29, 2026
7c9ad7d
feat(packages): 添加 runtime 和 commands 包配置
clark-fc Jun 29, 2026
9ff8c53
feat: merge
clark-fc Jul 2, 2026
6c4f31d
test(e2e): 删除kscli的chat和search端到端测试
clark-fc Jul 2, 2026
892ae30
feat(knowledge): 新增基于 workspace 的知识库语义检索与问答功能
clark-fc Jul 2, 2026
9bf6c6d
refactor(release): 移除未使用的导入以简化代码
clark-fc Jul 2, 2026
8fc2fc5
test(e2e): 添加全局设置调试日志,排查CI环境变量问题
clark-fc Jul 2, 2026
a078670
Merge remote-tracking branch 'origin/feat/composable-cli' into feat/k…
clark-fc Jul 2, 2026
e2efcfd
test(cli): 添加文件上传E2E测试的环境变量调试信息
clark-fc Jul 2, 2026
6dd206e
debug(cli): 增加文件上传测试对配置文件读取的调试日志
clark-fc Jul 2, 2026
03541b4
test(e2e): 移除多处测试调试信息并优化 runCli 调用参数
clark-fc Jul 2, 2026
c6426e9
test(cli): 更新测试用例以模拟空环境变量场景
clark-fc Jul 2, 2026
e6a8bf0
test(knowledge): 添加条件跳过无法执行的e2e错误场景测试
clark-fc Jul 2, 2026
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and

[中文版](CHANGELOG.zh.md) · [README](README.md) · [Contributing](CONTRIBUTING.md)

## [1.6.0] - 2026-07-02

### Added

- `bl knowledge search` — semantic search across knowledge bases using the new workspace-based RAG API. Supports `--query`, `--agent-id`, `--workspace-id`, `--image` (multimodal retrieval, repeatable), and `--query-history` (JSON conversation context for multi-turn query rewriting).
- `bl knowledge chat` — knowledge-base Q&A with SSE streaming. Supports `--message` (repeatable, with `role:content` prefix for multi-turn history), `--agent-id`, `--workspace-id`, and `--image` (multimodal). Displays real-time progress with step-change labels (retrieval, planning, generation) in interactive mode.
- `bailian-cli-core` gains new types and endpoints for the workspace-based knowledge API: `KnowledgeSearchRequest` / `KnowledgeSearchResponse`, `KnowledgeChatRequest` / `KnowledgeChatStreamChunk` / `KnowledgeChatMessage` / `KnowledgeChatContentPart`, and `knowledgeSearchEndpoint` / `knowledgeChatEndpoint`.
- `kscli` now ships `search` and `chat` commands alongside the existing `retrieve`.

### Changed

- `bl knowledge retrieve` is now marked as deprecated in its description; use `bl knowledge search` instead.
- `kscli` README (EN + ZH) updated to feature `search` and `chat` as the primary commands, with `retrieve` marked deprecated.

## [1.5.0] - 2026-07-01

### Added
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@

[English](CHANGELOG.md) · [README](README.zh.md) · [参与贡献](CONTRIBUTING.zh.md)

## [1.6.0] - 2026-07-02

### 新增

- `bl knowledge search` — 基于新版 workspace RAG API 的知识库语义检索。支持 `--query`、`--agent-id`、`--workspace-id`、`--image`(多模态检索,可重复)和 `--query-history`(多轮对话上下文 JSON,用于查询重写)。
- `bl knowledge chat` — 知识库 SSE 流式问答。支持 `--message`(可重复,支持 `角色:内容` 前缀传入多轮历史)、`--agent-id`、`--workspace-id` 和 `--image`(多模态)。交互模式下实时展示检索、规划、生成等步骤进度。
- `bailian-cli-core` 新增 workspace 级知识 API 类型与端点:`KnowledgeSearchRequest` / `KnowledgeSearchResponse`、`KnowledgeChatRequest` / `KnowledgeChatStreamChunk` / `KnowledgeChatMessage` / `KnowledgeChatContentPart`,以及 `knowledgeSearchEndpoint` / `knowledgeChatEndpoint`。
- `kscli` 现已包含 `search` 和 `chat` 命令。

### 变更

- `bl knowledge retrieve` 描述中已标记为废弃,请改用 `bl knowledge search`。
- `kscli` README(中英文)更新,以 `search` 和 `chat` 为主推命令,`retrieve` 标记为废弃。

## [1.5.0] - 2026-07-01

### 新增
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli",
"version": "1.5.0",
"version": "1.6.0",
"description": "CLI for Aliyun Model Studio (DashScope) AI Platform.",
"keywords": [
"agent",
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
memoryProfileCreate,
memoryProfileGet,
knowledgeRetrieve,
knowledgeSearch,
knowledgeChat,
mcpCall,
mcpList,
mcpTools,
Expand Down Expand Up @@ -105,6 +107,8 @@ export const commands: Record<string, Command> = {
"memory profile create": memoryProfileCreate,
"memory profile get": memoryProfileGet,
"knowledge retrieve": knowledgeRetrieve,
"knowledge search": knowledgeSearch,
"knowledge chat": knowledgeChat,
"mcp call": mcpCall,
"mcp list": mcpList,
"mcp tools": mcpTools,
Expand Down
194 changes: 194 additions & 0 deletions packages/cli/tests/e2e/knowledge-chat.e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import { describe, expect, test } from "vite-plus/test";
import { parseStdoutJson, runCli } from "./helpers.ts";

interface ContentPart {
type: string;
text?: string;
image_url?: { url: string };
}

interface DryRunBody {
endpoint?: string;
request?: {
input?: {
messages?: Array<{ role: string; content: string | ContentPart[] }>;
};
parameters?: {
agent_options?: {
agent_id?: string;
};
};
stream?: boolean;
};
}

describe("e2e: knowledge chat", () => {
test("knowledge chat --help 正常退出", async () => {
const { stderr, exitCode } = await runCli(["knowledge", "chat", "--help"]);
expect(exitCode, stderr).toBe(0);
expect(stderr).toMatch(/--message/i);
expect(stderr).toMatch(/--agent-id/i);
expect(stderr).toMatch(/--workspace-id/i);
});

test("缺少 --message 时打印帮助并退出 (0)", async () => {
const { stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--agent-id",
"aid_test",
"--non-interactive",
]);
expect(exitCode).toBe(0);
expect(stderr).toMatch(/--message|Usage:/i);
});

test("缺少 --agent-id 时打印帮助并退出 (0)", async () => {
const { stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--message",
"Hello",
"--non-interactive",
]);
expect(exitCode).toBe(0);
expect(stderr).toMatch(/--agent-id|Usage:/i);
});

test("缺少 --workspace-id 时非零退出并提示", async () => {
const { stderr, exitCode } = await runCli(
[
"knowledge",
"chat",
"--message",
"Hello",
"--agent-id",
"aid_test",
"--non-interactive",
"--output",
"json",
],
{ BAILIAN_WORKSPACE_ID: "" },
);
expect(exitCode).not.toBe(0);
expect(stderr).toMatch(/workspace.*required/i);
});

test("--dry-run 输出 endpoint 和 request body", async () => {
const { stdout, stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--dry-run",
"--message",
"什么是RAG",
"--agent-id",
"aid_test",
"--workspace-id",
"ws_test",
"--non-interactive",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<DryRunBody>(stdout);
expect(data.endpoint).toMatch(/ws_test\.cn-beijing\.maas\.aliyuncs\.com/);
expect(data.endpoint).toMatch(/api\/v2\/apps\/knowledge\/chat/);
expect(data.request?.input?.messages?.[0]?.role).toBe("user");
expect(data.request?.input?.messages?.[0]?.content).toBe("什么是RAG");
expect(data.request?.parameters?.agent_options?.agent_id).toBe("aid_test");
});

test("--dry-run 多轮消息解析 role:content 前缀", async () => {
const { stdout, stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--dry-run",
"--message",
"user:什么是RAG",
"--message",
"assistant:RAG是检索增强生成",
"--message",
"它怎么工作",
"--agent-id",
"aid_test",
"--workspace-id",
"ws_test",
"--non-interactive",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<DryRunBody>(stdout);
const msgs = data.request?.input?.messages ?? [];
expect(msgs).toHaveLength(3);
expect(msgs[0]?.role).toBe("user");
expect(msgs[0]?.content).toBe("什么是RAG");
expect(msgs[1]?.role).toBe("assistant");
expect(msgs[1]?.content).toBe("RAG是检索增强生成");
expect(msgs[2]?.role).toBe("user");
expect(msgs[2]?.content).toBe("它怎么工作");
});

test("--dry-run + --image 输出多模态 content 数组", async () => {
const { stdout, stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--dry-run",
"--message",
"描述这张图",
"--agent-id",
"aid_test",
"--workspace-id",
"ws_test",
"--image",
"https://example.com/img.jpg",
"--non-interactive",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<DryRunBody>(stdout);
const lastMsg = data.request?.input?.messages?.[0];
expect(lastMsg?.role).toBe("user");
expect(Array.isArray(lastMsg?.content)).toBe(true);
const parts = lastMsg?.content as ContentPart[];
expect(parts[0]).toEqual({ type: "text", text: "描述这张图" });
expect(parts[1]).toEqual({
type: "image_url",
image_url: { url: "https://example.com/img.jpg" },
});
});

test("--dry-run + --image 无 --message 自动创建空 user message", async () => {
const { stdout, stderr, exitCode } = await runCli([
"knowledge",
"chat",
"--dry-run",
"--agent-id",
"aid_test",
"--workspace-id",
"ws_test",
"--image",
"https://example.com/a.png",
"--image",
"https://example.com/b.png",
"--non-interactive",
"--output",
"json",
]);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<DryRunBody>(stdout);
const lastMsg = data.request?.input?.messages?.[0];
expect(lastMsg?.role).toBe("user");
const parts = lastMsg?.content as ContentPart[];
expect(parts[0]).toEqual({ type: "text", text: "" });
expect(parts[1]).toEqual({
type: "image_url",
image_url: { url: "https://example.com/a.png" },
});
expect(parts[2]).toEqual({
type: "image_url",
image_url: { url: "https://example.com/b.png" },
});
});
});
Loading