Skip to content

Commit 2285dc1

Browse files
authored
Merge pull request #307 from modelstudioai/feat/web-search
Feat/web search
2 parents 2c29049 + cce66d4 commit 2285dc1

32 files changed

Lines changed: 766 additions & 304 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
66

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

9+
## [2.8.3] - 2026-11-06
10+
11+
### Added
12+
13+
- **Model-based web search**: `bl search web` adds a model search mode and now uses it as the default implementation.
14+
- **Web search in chat**: `bl text chat` supports built-in web search via the `enable_search` parameter.
15+
16+
### Changed
17+
18+
- **Profile credentials**: Profiles can now declare credentials per search mode (`model` / `mcp`), and the CLI picks the matching profile credential when switching search modes.
19+
920
## [2.8.2] - 2026-11-04
1021

1122
### Internal

‎CHANGELOG.zh.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66

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

9+
## [2.8.3] - 2026-11-06
10+
11+
### 新增
12+
13+
- **模型联网搜索**:`bl search web` 新增模型搜索模式(`--mode model`),并改为默认实现。
14+
- **对话内置联网搜索**:`bl text chat` 新增 `enable_search` 参数,支持内置联网搜索。
15+
16+
### 变更
17+
18+
- **Profile 凭证**:Profile 可按搜索模式(`model` / `mcp`)声明凭证,切换搜索模式时自动选择对应 Profile 凭证。
19+
920
## [2.8.2] - 2026-11-04
1021

1122
### 内部维护

‎packages/bailian-kb-dsh/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bailian-kb-dsh",
3-
"version": "2.8.2",
3+
"version": "2.8.3",
44
"description": "Bailian knowledge-base tools for DeepSeek Harness: kb_search and kb_chat over the DashScope RAG API, plus the bl CLI management skill.",
55
"keywords": [
66
"alibaba-cloud",

‎packages/bailian-memo-dsh/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bailian-memo-dsh",
3-
"version": "2.8.2",
3+
"version": "2.8.3",
44
"description": "Bailian personal memory for DeepSeek Harness: automatic recall, silent curation, and user-controlled remember/forget.",
55
"keywords": [
66
"alibaba-cloud",

‎packages/cli/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bailian-cli",
3-
"version": "2.8.2",
3+
"version": "2.8.3",
44
"description": "CLI for Aliyun Model Studio (DashScope) AI Platform.",
55
"keywords": [
66
"agent",

‎packages/commands/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bailian-cli-commands",
3-
"version": "2.8.2",
3+
"version": "2.8.3",
44
"description": "Command library for bailian-cli products (knowledge, memory, media, …). See https://www.npmjs.com/package/bailian-cli for usage.",
55
"homepage": "https://bailian.console.aliyun.com/cli",
66
"bugs": {

‎packages/commands/src/commands/search/web.ts‎

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@ import {
22
defineCommand,
33
formatOutput,
44
BailianError,
5+
chatPath,
56
mcpWebSearchPath,
7+
type ChatRequest,
8+
type ChatResponse,
69
type FlagsDef,
710
type McpConnectedClient,
11+
type McpToolResult,
812
} from "bailian-cli-core";
913

1014
import { rethrowWithWebSearchActivateHint } from "./web-activate-hint.ts";
1115

16+
/** Fallback model for --mode model, mirroring the text-chat default chain. */
17+
const DEFAULT_SEARCH_MODEL = "qwen3.8-max";
18+
19+
type WebSearchMode = "mcp" | "model";
20+
21+
/**
22+
* Resolve the effective search mode. `--list-tools` is an MCP-only concept and
23+
* locks the mode to mcp; otherwise default to model (Chat Completions) unless
24+
* `--mode mcp` is given.
25+
*/
26+
function resolveSearchMode(flags: { mode?: string; listTools?: boolean }): WebSearchMode {
27+
if (flags.listTools) return "mcp";
28+
return flags.mode === "mcp" ? "mcp" : "model";
29+
}
30+
1231
const WEB_SEARCH_FLAGS = {
1332
query: {
1433
type: "string",
@@ -30,36 +49,119 @@ const WEB_SEARCH_FLAGS = {
3049
"zh-CN": "列出可用的 MCP 工具并退出",
3150
},
3251
},
52+
mode: {
53+
type: "string",
54+
valueHint: "<mcp|model>",
55+
choices: ["mcp", "model"] as const,
56+
description: {
57+
"en-US":
58+
"Search mode: model answers via Chat Completions with enable_search, mcp calls the WebSearch MCP service (default: model)",
59+
"zh-CN":
60+
"搜索模式:model 通过 Chat Completions(enable_search)由模型联网作答,mcp 调用 WebSearch MCP 服务(默认:model)",
61+
},
62+
},
63+
model: {
64+
type: "string",
65+
valueHint: "<model>",
66+
description: {
67+
"en-US": "Model ID for --mode model (default: qwen3.8-max)",
68+
"zh-CN": "--mode model 使用的模型 ID(默认:qwen3.8-max)",
69+
},
70+
},
3371
} satisfies FlagsDef;
3472

3573
export default defineCommand({
3674
description: {
37-
"en-US": "Search the web using DashScope MCP WebSearch service",
38-
"zh-CN": "使用 DashScope MCP WebSearch 服务搜索互联网",
75+
"en-US":
76+
"Search the web via a chat model with built-in web search (default) or the DashScope MCP WebSearch service",
77+
"zh-CN": "搜索互联网:默认走模型内置联网搜索,也可切换为 DashScope MCP WebSearch 服务",
3978
},
4079
auth: "apiKey",
80+
// Model mode talks Chat Completions (the `text.chat` capability domain), so
81+
// Profile API-key selection must follow the mode; MCP mode keeps the
82+
// `search.web` capability, which Token Plan profiles deliberately do not
83+
// list — plan keys cannot authorize Bailian MCP search.
84+
authCapability: (flags) => (resolveSearchMode(flags) === "model" ? "text.chat" : "search.web"),
4185
usageArgs: "--query <text> [flags]",
4286
flags: WEB_SEARCH_FLAGS,
4387
exampleArgs: [
4488
{
4589
"en-US": '--query "Alibaba Cloud Bailian latest features"',
4690
"zh-CN": '--query "阿里云百炼最新功能"',
4791
},
48-
{
49-
"en-US": '--query "TypeScript 5.9 new features" --count 5',
50-
"zh-CN": '--query "TypeScript 5.9 新功能" --count 5',
51-
},
5292
{
5393
"en-US": '--query "Today\'s news"',
5494
"zh-CN": '--query "今日新闻"',
5595
},
96+
{
97+
"en-US": '--mode mcp --query "TypeScript 5.9 new features" --count 5',
98+
"zh-CN": '--mode mcp --query "TypeScript 5.9 新功能" --count 5',
99+
},
100+
{
101+
"en-US": '--mode mcp --query "Alibaba Cloud Bailian latest features"',
102+
"zh-CN": '--mode mcp --query "阿里云百炼最新功能"',
103+
},
56104
"--list-tools",
57105
],
58-
validate: (f) => (!f.listTools && !f.query ? "Missing required flag: --query" : undefined),
106+
notes: [
107+
{
108+
"en-US":
109+
"Defaults to --mode model: one non-streaming Chat Completions request with enable_search: true, returning the model answer as a single content[].text block (no pages list). Use --mode mcp for the WebSearch MCP service (pages list); --count and --list-tools are MCP-mode only. The model resolves from --model, default_text_model, then qwen3.8-max.",
110+
"zh-CN":
111+
"默认 --mode model:发送单次非流式 Chat Completions 请求(enable_search: true),模型回答以单个 content[].text 块返回(无 pages 列表)。--mode mcp 走 WebSearch MCP 服务(返回 pages);--count 与 --list-tools 仅限 MCP 模式。模型按 --model、default_text_model、qwen3.8-max 依次解析。",
112+
},
113+
],
114+
validate: (flags) => {
115+
if (flags.mode === "model" && flags.listTools) {
116+
return "--list-tools is only available in MCP mode (--mode mcp). / --list-tools 仅支持 MCP 模式(--mode mcp)。";
117+
}
118+
if (resolveSearchMode(flags) === "model" && flags.count !== undefined) {
119+
return "--count is only available in MCP mode (--mode mcp). / --count 仅支持 MCP 模式(--mode mcp)。";
120+
}
121+
if (!flags.listTools && !flags.query) return "Missing required flag: --query";
122+
return undefined;
123+
},
59124
async run(ctx) {
60125
const { settings, flags } = ctx;
61126
const format = settings.output;
62127

128+
// --- Model mode (default): Chat Completions with enable_search ---
129+
if (resolveSearchMode(flags) === "model") {
130+
const model = flags.model || settings.defaultTextModel || DEFAULT_SEARCH_MODEL;
131+
const request: ChatRequest = {
132+
model,
133+
messages: [{ role: "user", content: flags.query! }],
134+
enable_search: true,
135+
stream: false,
136+
};
137+
138+
if (settings.dryRun) {
139+
ctx.output.result({ endpoint: ctx.client.url(chatPath()), request });
140+
return;
141+
}
142+
143+
ctx.output.progress({ "en-US": "Searching...", "zh-CN": "正在搜索……" });
144+
try {
145+
const response = await ctx.client.requestJson<ChatResponse>({
146+
path: chatPath(),
147+
method: "POST",
148+
body: request,
149+
});
150+
const answer = response.choices?.[0]?.message?.content ?? "";
151+
ctx.output.progress({ "en-US": "Done.", "zh-CN": "已完成。" });
152+
// Keep the MCP result envelope so downstream parsers work for both modes.
153+
const result: McpToolResult = {
154+
content: [{ type: "text", text: answer }],
155+
isError: false,
156+
};
157+
ctx.output.result(result, format === "text" ? { text: answer } : undefined);
158+
} catch (error) {
159+
ctx.output.progress({ "en-US": "Failed.", "zh-CN": "失败。" });
160+
throw error;
161+
}
162+
return;
163+
}
164+
63165
// --- List tools mode ---
64166
if (flags.listTools) {
65167
if (settings.dryRun) {

‎packages/commands/src/commands/text/chat.ts‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import {
2525
} from "./responses.ts";
2626
import { PRIME_FLAGS, resolvePrimeEndpoint, validatePrimeFlags } from "../shared/prime.ts";
2727

28+
/** Models that enable built-in web search by default on the Chat Completions API. */
29+
const SEARCH_BY_DEFAULT_MODELS = new Set(["qwen3.8-max"]);
30+
2831
const CHAT_FLAGS = {
2932
api: {
3033
type: "string",
@@ -79,6 +82,15 @@ const CHAT_FLAGS = {
7982
valueHint: "<n>",
8083
description: { "en-US": "Nucleus sampling threshold", "zh-CN": "核采样阈值" },
8184
},
85+
enableSearch: {
86+
type: "boolean",
87+
valueHint: "<true|false>",
88+
description: {
89+
"en-US":
90+
"Enable built-in web search (Chat Completions API only; default: true for qwen3.8-max)",
91+
"zh-CN": "启用模型内置联网搜索(仅 Chat Completions API;qwen3.8-max 默认开启)",
92+
},
93+
},
8294
stream: {
8395
type: "switch",
8496
description: {
@@ -202,6 +214,10 @@ export default defineCommand({
202214
"en-US": '--model qwq-plus --message "Solve 1+1" --enable-thinking',
203215
"zh-CN": '--model qwq-plus --message "计算 1+1" --enable-thinking',
204216
},
217+
{
218+
"en-US": '--enable-search true --message "Latest news about Alibaba Cloud"',
219+
"zh-CN": '--enable-search true --message "阿里云最新新闻"',
220+
},
205221
{
206222
"en-US": '--prime --workspace-id <id> --model glm-5.3-prime --message "Explain this code"',
207223
"zh-CN": '--prime --workspace-id <id> --model glm-5.3-prime --message "解释这段代码"',
@@ -229,6 +245,12 @@ export default defineCommand({
229245
"zh-CN":
230246
"Prime Endpoint:已配置的 --base-url、DASHSCOPE_BASE_URL 或 Profile base_url 优先;否则按 --workspace-id、BAILIAN_WORKSPACE_ID、配置项 workspace_id 解析工作空间。",
231247
},
248+
{
249+
"en-US":
250+
'--enable-search maps to the Chat Completions enable_search parameter and requires a model with built-in web search support; whitelisted models (qwen3.8-max) enable it by default unless --enable-search false is passed; for the Responses API use --tool \'{"type":"web_search"}\' instead.',
251+
"zh-CN":
252+
'--enable-search 映射为 Chat Completions 的 enable_search 参数,需要模型支持内置联网搜索;白名单模型(qwen3.8-max)默认开启,可传 --enable-search false 显式关闭;Responses API 请改用 --tool \'{"type":"web_search"}\'。',
253+
},
232254
],
233255
validate: (flags) => {
234256
if (!flags.message && !flags.messagesFile) return "Provide --message or --messages-file.";
@@ -243,6 +265,9 @@ export default defineCommand({
243265
if (flags.api === "responses" && flags.thinkingBudget !== undefined) {
244266
return "--thinking-budget is not supported by the Responses API.";
245267
}
268+
if (flags.api === "responses" && flags.enableSearch !== undefined) {
269+
return '--enable-search is not supported by the Responses API; use --tool \'{"type":"web_search"}\' instead. / --enable-search 不支持 Responses API,请改用 --tool \'{"type":"web_search"}\'。';
270+
}
246271
return undefined;
247272
},
248273
async run(ctx) {
@@ -295,6 +320,15 @@ export default defineCommand({
295320
}
296321
}
297322

323+
if (api === "chat" && "messages" in body) {
324+
if (flags.enableSearch !== undefined) {
325+
body.enable_search = flags.enableSearch;
326+
} else if (SEARCH_BY_DEFAULT_MODELS.has(model)) {
327+
// Whitelisted models get built-in web search unless explicitly opted out.
328+
body.enable_search = true;
329+
}
330+
}
331+
298332
const requestPath = flags.batch
299333
? resolveBatchChatEndpoint(ctx.client)
300334
: flags.prime

0 commit comments

Comments
 (0)