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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and

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

## [2.8.3] - 2026-11-06

### Added

- **Model-based web search**: `bl search web` adds a model search mode and now uses it as the default implementation.
- **Web search in chat**: `bl text chat` supports built-in web search via the `enable_search` parameter.

### Changed

- **Profile credentials**: Profiles can now declare credentials per search mode (`model` / `mcp`), and the CLI picks the matching profile credential when switching search modes.

## [2.8.2] - 2026-11-04

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

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

## [2.8.3] - 2026-11-06

### 新增

- **模型联网搜索**:`bl search web` 新增模型搜索模式(`--mode model`),并改为默认实现。
- **对话内置联网搜索**:`bl text chat` 新增 `enable_search` 参数,支持内置联网搜索。

### 变更

- **Profile 凭证**:Profile 可按搜索模式(`model` / `mcp`)声明凭证,切换搜索模式时自动选择对应 Profile 凭证。

## [2.8.2] - 2026-11-04

### 内部维护
Expand Down
2 changes: 1 addition & 1 deletion packages/bailian-kb-dsh/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-kb-dsh",
"version": "2.8.2",
"version": "2.8.3",
"description": "Bailian knowledge-base tools for DeepSeek Harness: kb_search and kb_chat over the DashScope RAG API, plus the bl CLI management skill.",
"keywords": [
"alibaba-cloud",
Expand Down
2 changes: 1 addition & 1 deletion packages/bailian-memo-dsh/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-memo-dsh",
"version": "2.8.2",
"version": "2.8.3",
"description": "Bailian personal memory for DeepSeek Harness: automatic recall, silent curation, and user-controlled remember/forget.",
"keywords": [
"alibaba-cloud",
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": "2.8.2",
"version": "2.8.3",
"description": "CLI for Aliyun Model Studio (DashScope) AI Platform.",
"keywords": [
"agent",
Expand Down
2 changes: 1 addition & 1 deletion packages/commands/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli-commands",
"version": "2.8.2",
"version": "2.8.3",
"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": {
Expand Down
116 changes: 109 additions & 7 deletions packages/commands/src/commands/search/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,32 @@ import {
defineCommand,
formatOutput,
BailianError,
chatPath,
mcpWebSearchPath,
type ChatRequest,
type ChatResponse,
type FlagsDef,
type McpConnectedClient,
type McpToolResult,
} from "bailian-cli-core";

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

/** Fallback model for --mode model, mirroring the text-chat default chain. */
const DEFAULT_SEARCH_MODEL = "qwen3.8-max";

type WebSearchMode = "mcp" | "model";

/**
* Resolve the effective search mode. `--list-tools` is an MCP-only concept and
* locks the mode to mcp; otherwise default to model (Chat Completions) unless
* `--mode mcp` is given.
*/
function resolveSearchMode(flags: { mode?: string; listTools?: boolean }): WebSearchMode {
if (flags.listTools) return "mcp";
return flags.mode === "mcp" ? "mcp" : "model";
}

const WEB_SEARCH_FLAGS = {
query: {
type: "string",
Expand All @@ -30,36 +49,119 @@ const WEB_SEARCH_FLAGS = {
"zh-CN": "列出可用的 MCP 工具并退出",
},
},
mode: {
type: "string",
valueHint: "<mcp|model>",
choices: ["mcp", "model"] as const,
description: {
"en-US":
"Search mode: model answers via Chat Completions with enable_search, mcp calls the WebSearch MCP service (default: model)",
"zh-CN":
"搜索模式:model 通过 Chat Completions(enable_search)由模型联网作答,mcp 调用 WebSearch MCP 服务(默认:model)",
},
},
model: {
type: "string",
valueHint: "<model>",
description: {
"en-US": "Model ID for --mode model (default: qwen3.8-max)",
"zh-CN": "--mode model 使用的模型 ID(默认:qwen3.8-max)",
},
},
} satisfies FlagsDef;

export default defineCommand({
description: {
"en-US": "Search the web using DashScope MCP WebSearch service",
"zh-CN": "使用 DashScope MCP WebSearch 服务搜索互联网",
"en-US":
"Search the web via a chat model with built-in web search (default) or the DashScope MCP WebSearch service",
"zh-CN": "搜索互联网:默认走模型内置联网搜索,也可切换为 DashScope MCP WebSearch 服务",
},
auth: "apiKey",
// Model mode talks Chat Completions (the `text.chat` capability domain), so
// Profile API-key selection must follow the mode; MCP mode keeps the
// `search.web` capability, which Token Plan profiles deliberately do not
// list — plan keys cannot authorize Bailian MCP search.
authCapability: (flags) => (resolveSearchMode(flags) === "model" ? "text.chat" : "search.web"),
usageArgs: "--query <text> [flags]",
flags: WEB_SEARCH_FLAGS,
exampleArgs: [
{
"en-US": '--query "Alibaba Cloud Bailian latest features"',
"zh-CN": '--query "阿里云百炼最新功能"',
},
{
"en-US": '--query "TypeScript 5.9 new features" --count 5',
"zh-CN": '--query "TypeScript 5.9 新功能" --count 5',
},
{
"en-US": '--query "Today\'s news"',
"zh-CN": '--query "今日新闻"',
},
{
"en-US": '--mode mcp --query "TypeScript 5.9 new features" --count 5',
"zh-CN": '--mode mcp --query "TypeScript 5.9 新功能" --count 5',
},
{
"en-US": '--mode mcp --query "Alibaba Cloud Bailian latest features"',
"zh-CN": '--mode mcp --query "阿里云百炼最新功能"',
},
"--list-tools",
],
validate: (f) => (!f.listTools && !f.query ? "Missing required flag: --query" : undefined),
notes: [
{
"en-US":
"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.",
"zh-CN":
"默认 --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 依次解析。",
},
],
validate: (flags) => {
if (flags.mode === "model" && flags.listTools) {
return "--list-tools is only available in MCP mode (--mode mcp). / --list-tools 仅支持 MCP 模式(--mode mcp)。";
}
if (resolveSearchMode(flags) === "model" && flags.count !== undefined) {
return "--count is only available in MCP mode (--mode mcp). / --count 仅支持 MCP 模式(--mode mcp)。";
}
if (!flags.listTools && !flags.query) return "Missing required flag: --query";
return undefined;
},
async run(ctx) {
const { settings, flags } = ctx;
const format = settings.output;

// --- Model mode (default): Chat Completions with enable_search ---
if (resolveSearchMode(flags) === "model") {
const model = flags.model || settings.defaultTextModel || DEFAULT_SEARCH_MODEL;
const request: ChatRequest = {
model,
messages: [{ role: "user", content: flags.query! }],
enable_search: true,
stream: false,
};

if (settings.dryRun) {
ctx.output.result({ endpoint: ctx.client.url(chatPath()), request });
return;
}

ctx.output.progress({ "en-US": "Searching...", "zh-CN": "正在搜索……" });
try {
const response = await ctx.client.requestJson<ChatResponse>({
path: chatPath(),
method: "POST",
body: request,
});
const answer = response.choices?.[0]?.message?.content ?? "";
ctx.output.progress({ "en-US": "Done.", "zh-CN": "已完成。" });
// Keep the MCP result envelope so downstream parsers work for both modes.
const result: McpToolResult = {
content: [{ type: "text", text: answer }],
isError: false,
};
ctx.output.result(result, format === "text" ? { text: answer } : undefined);
} catch (error) {
ctx.output.progress({ "en-US": "Failed.", "zh-CN": "失败。" });
throw error;
}
return;
}

// --- List tools mode ---
if (flags.listTools) {
if (settings.dryRun) {
Expand Down
34 changes: 34 additions & 0 deletions packages/commands/src/commands/text/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import {
} from "./responses.ts";
import { PRIME_FLAGS, resolvePrimeEndpoint, validatePrimeFlags } from "../shared/prime.ts";

/** Models that enable built-in web search by default on the Chat Completions API. */
const SEARCH_BY_DEFAULT_MODELS = new Set(["qwen3.8-max"]);

const CHAT_FLAGS = {
api: {
type: "string",
Expand Down Expand Up @@ -79,6 +82,15 @@ const CHAT_FLAGS = {
valueHint: "<n>",
description: { "en-US": "Nucleus sampling threshold", "zh-CN": "核采样阈值" },
},
enableSearch: {
type: "boolean",
valueHint: "<true|false>",
description: {
"en-US":
"Enable built-in web search (Chat Completions API only; default: true for qwen3.8-max)",
"zh-CN": "启用模型内置联网搜索(仅 Chat Completions API;qwen3.8-max 默认开启)",
},
},
stream: {
type: "switch",
description: {
Expand Down Expand Up @@ -202,6 +214,10 @@ export default defineCommand({
"en-US": '--model qwq-plus --message "Solve 1+1" --enable-thinking',
"zh-CN": '--model qwq-plus --message "计算 1+1" --enable-thinking',
},
{
"en-US": '--enable-search true --message "Latest news about Alibaba Cloud"',
"zh-CN": '--enable-search true --message "阿里云最新新闻"',
},
{
"en-US": '--prime --workspace-id <id> --model glm-5.3-prime --message "Explain this code"',
"zh-CN": '--prime --workspace-id <id> --model glm-5.3-prime --message "解释这段代码"',
Expand Down Expand Up @@ -229,6 +245,12 @@ export default defineCommand({
"zh-CN":
"Prime Endpoint:已配置的 --base-url、DASHSCOPE_BASE_URL 或 Profile base_url 优先;否则按 --workspace-id、BAILIAN_WORKSPACE_ID、配置项 workspace_id 解析工作空间。",
},
{
"en-US":
'--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.',
"zh-CN":
'--enable-search 映射为 Chat Completions 的 enable_search 参数,需要模型支持内置联网搜索;白名单模型(qwen3.8-max)默认开启,可传 --enable-search false 显式关闭;Responses API 请改用 --tool \'{"type":"web_search"}\'。',
},
],
validate: (flags) => {
if (!flags.message && !flags.messagesFile) return "Provide --message or --messages-file.";
Expand All @@ -243,6 +265,9 @@ export default defineCommand({
if (flags.api === "responses" && flags.thinkingBudget !== undefined) {
return "--thinking-budget is not supported by the Responses API.";
}
if (flags.api === "responses" && flags.enableSearch !== undefined) {
return '--enable-search is not supported by the Responses API; use --tool \'{"type":"web_search"}\' instead. / --enable-search 不支持 Responses API,请改用 --tool \'{"type":"web_search"}\'。';
}
return undefined;
},
async run(ctx) {
Expand Down Expand Up @@ -295,6 +320,15 @@ export default defineCommand({
}
}

if (api === "chat" && "messages" in body) {
if (flags.enableSearch !== undefined) {
body.enable_search = flags.enableSearch;
} else if (SEARCH_BY_DEFAULT_MODELS.has(model)) {
// Whitelisted models get built-in web search unless explicitly opted out.
body.enable_search = true;
}
}

const requestPath = flags.batch
? resolveBatchChatEndpoint(ctx.client)
: flags.prime
Expand Down
Loading
Loading