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
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,38 @@

## Unreleased

## 2.0.6 - 2026-09-05

This is a small reliability release on the 2.0 TypeScript runtime.
`web_search` now queries Wikipedia's open MediaWiki API, then Bing HTML, then
DuckDuckGo HTML. Wikipedia is encyclopedia-only; Bing is the no-key web
fallback when Wikipedia is unreachable. Bundled ripgrep is used for `rg_*`
tools so Windows no longer depends on a system `rg`. Array tool results such as
`skill_list` keep their payloads in the model-facing short view. Permission
mode ids are unchanged.

### Fixed

- `web_search` merges Wikipedia, Bing HTML, and DuckDuckGo HTML (optional
SearXNG still works). Wikipedia requests are capped at about eight seconds.
- `rg_search`, `rg_files`, and `rg_count` prefer the bundled ripgrep binary.
- `skill_list`, `todo_read`, `mcp_list`, and `rg_count` short views no longer
collapse arrays to `{}`.

### Upgrade

```sh
git pull
npm ci
npm run verify:install
npm link
ant-code --version
```

`ant-code --version` should print `2.0.6`. Restart a running Dashboard so it
loads this runtime. Gateway config and `.lab-agent` sessions do not need to
be recreated.

## 2.0.5 - 2026-09-04

This is a small reliability release on the 2.0 TypeScript runtime. Tool
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ ant-code doctor
ant-code
```

`ant-code --version` should print `2.0.5`. If you previously linked a
`ant-code --version` should print `2.0.6`. If you previously linked a
JavaScript install, run `npm link` again so the global command points at
`src/cli/index.ts`.

Expand Down
2 changes: 1 addition & 1 deletion config/skills/web-research/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ argument_hint: 简述要调查的问题、时间范围、可信来源偏好和
## 工作流

1. 明确用户要查什么、是否需要最新信息、是否有指定来源。
2. 优先使用 `web_search` 搜索 3-5 个候选来源(内置 DuckDuckGo HTML)。只有配置了自建 SearXNG 时才走搜索 MCP。
2. 优先使用 `web_search` 搜索 3-5 个候选来源(维基开放接口、Bing HTML、DuckDuckGo HTML)。只有配置了自建 SearXNG 时才走搜索 MCP。
3. 对关键来源使用 `web_fetch` 抓取正文,优先 `markdown`。当前 Ant Code 默认让 `web_fetch` 先走 `fetch` MCP;如果 MCP 不可用,再回退到内置抓取器。
- 如果抓取被权限策略、反爬或 HTML 噪声阻断,先改用搜索摘要、官方 API/raw 文件。
- 若配置允许,可尝试 reader mirror:`https://r.jina.ai/http://r.jina.ai/http://<原始URL>`,并在 caveats 中说明使用了镜像读取。
Expand Down
40 changes: 40 additions & 0 deletions docs/releases/2.0.6-web-search-rg-tool-views_zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Ant Code v2.0.6:无 key 搜索渠道与随包代码搜索

发布日期:2026-09-05

这是 2.0 TypeScript 运行时上的小版本。`web_search` 增加维基百科开放接口,并在维基不可达时继续抓取 Bing HTML,再与 DuckDuckGo HTML 去重合并。Windows 上的 `rg_*` 改为使用随包 ripgrep,不再依赖系统 PATH 是否安装了 `rg`。技能列表、待办和 MCP 列表发给模型时保留实际条目,不再显示成空的 `{}`。权限模式 id 不变。本说明处于公开发布候选阶段,不表示 CI、tag 或 GitHub Release 已经完成。

## 对用户工作流的直接变化

- `web_search` 先查 Wikipedia/Wikimedia 只读 API(查询含汉字则用中文维基,最多约 8 秒),再抓 Bing HTML,最后才是 DuckDuckGo HTML/lite。可选自建 SearXNG 仍可用。维基覆盖百科词条,不是 Google 式全网检索。
- 国内直连维基常会超时;Ant Code 会读取 Windows 系统代理做 HTTPS CONNECT。不必在配置里再填代理端口。Bing 在直连可达时可作为无 key 的全网补充。
- `rg_search` / `rg_files` / `rg_count` 优先使用随包 `rg.exe`,避免 `ENOENT: spawn rg`。
- `skill_list`、`todo_read`、`mcp_list`、`rg_count` 的模型短视图会写出条数和名称,不再把数组结果收成 `{}`。

## 配置、数据与安全边界

- 配置格式、session / transcript、凭据存储和网关协议没有迁移。现有配置和 `.lab-agent` 会话可继续使用。
- 默认允许主机增加 `en.wikipedia.org`、`zh.wikipedia.org`、`bing.com`、`www.bing.com`。`approved-web` 下若允许列表里缺其中任何一个,整次 `web_search` 可能被询问或拦住。
- 这次没有改权限模式 id。搜索结果必须引用,不能当成最终事实。
- 自动化测试不能代表所有私有研究数据、外部模型供应商或现场网络环境都已得到验证。

## 升级与产物位置

需要 Node.js 22.18+。从源码更新:

```sh
git pull
npm ci
npm run verify:install
npm link
ant-code --version
```

`ant-code --version` 应显示 `2.0.6`。若以前 link 过旧安装,需要重新 `npm link`。正在跑的 Dashboard 需要重启。现有网关配置和会话不必重建。本次没有新的安装包要求。

## 验证、限制与待完成门禁

- 开发仓 `npm test`(`node:test` 口径):tests 1273,pass 1272,fail 1。失败项是 `MCP request timeout is a failed request, not a user interrupt`,与本次搜索/rg 改动无关。定向套件 `tests/unit/tools.test.ts` 与 `tests/unit/tool-result-view.test.ts` 105 项全部通过。完整 `npm run verify:release` 交给 GitHub CI。
- DuckDuckGo HTML 仍可能被反爬;维基在未走系统代理时可能超时;Bing HTML 刮取没有长期保证。
- 未把 TaxaMask 内嵌主题、`dashboard-embed` 或源码写入守卫带入独立版。
- 候选阶段最终结论以正式仓同一提交的 CI 和 Release 门禁为准。
9 changes: 8 additions & 1 deletion lab-agent.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@
],
"networkMode": "lab-only",
"allowedHosts": [
"gateway.example.com"
"gateway.example.com",
"en.wikipedia.org",
"zh.wikipedia.org",
"bing.com",
"www.bing.com",
"duckduckgo.com",
"html.duckduckgo.com",
"lite.duckduckgo.com"
],
"lab": {
"gatewayUrl": "https://gateway.example.com/v1/chat/completions",
Expand Down
4 changes: 2 additions & 2 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ant-code/cli",
"version": "2.0.5",
"version": "2.0.6",
"description": "AGPL-licensed local coding agent with a terminal UI, local dashboard, tool permissions, skills, MCP integration, and model gateway adapters.",
"type": "module",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ export const BUILT_IN_TOOLS = Object.freeze([
},
{
name: "web_search",
description: "Search the public web through a configured SearXNG endpoint or DuckDuckGo HTML fallback. Results are best-effort and must be cited.",
description: "Search the public web through Wikipedia, Bing HTML, and DuckDuckGo HTML, or a configured SearXNG endpoint. Results are best-effort and must be cited.",
risk: "network",
supportsAbort: true,
inputSchema: {
Expand Down
72 changes: 70 additions & 2 deletions src/tools/result-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ function bodyForTool(name: string, execution: ToolResultValue, result: Record<st
if (name === "read_file") {
return formatReadFile(result);
}
if (name === "grep" || name === "rg_search" || name === "rg_files_with_matches" || name === "rg_count") {
if (name === "grep" || name === "rg_search" || name === "rg_files_with_matches") {
return formatSearch(result);
}
if (name === "rg_count") {
return formatRgCount(result);
}
if (name === "glob" || name === "rg_files") {
return formatPathList(result, "matches", SEARCH_VIEW_MATCHES);
}
Expand All @@ -90,7 +93,13 @@ function bodyForTool(name: string, execution: ToolResultValue, result: Record<st
return formatAgent(execution, result);
}
if (name === "mcp_call" || name === "mcp_list") {
return formatMcp(result);
return formatMcpList(name, execution, result);
}
if (name === "skill_list") {
return formatSkillList(execution);
}
if (name === "todo_read") {
return formatTodoList(execution);
}
if (name === "document_intake" || name === "skill_read") {
return formatDocument(result);
Expand Down Expand Up @@ -192,6 +201,50 @@ function formatReadFile(result: Record<string, unknown>): ViewDraft {
};
}

function formatRgCount(result: Record<string, unknown>): ViewDraft {
const count = Number.isFinite(Number(result.count)) ? Number(result.count) : 0;
const mode = stringField(result.mode) || "matches";
return {
text: [
`count=${count}`,
`mode=${mode}`
].join("\n"),
truncated: result.truncated === true
};
}

function formatSkillList(execution: ToolResultValue): ViewDraft {
const skills = Array.isArray(execution.result) ? execution.result : asArray(asRecord(execution.result).skills);
const shown = skills.slice(0, SEARCH_VIEW_MATCHES);
const truncated = skills.length > shown.length;
const lines = [
`skills=${skills.length}${truncated ? " truncated=true" : ""}`,
...shown.map((item) => {
const skill = asRecord(item);
const name = stringField(skill.name) || "?";
const description = stringField(skill.description);
return `- ${name}${description ? `: ${truncateClean(description, SEARCH_LINE_CHARS)}` : ""}`;
})
];
return { text: lines.join("\n"), truncated };
}

function formatTodoList(execution: ToolResultValue): ViewDraft {
const todos = Array.isArray(execution.result) ? execution.result : asArray(asRecord(execution.result).todos);
const shown = todos.slice(0, SEARCH_VIEW_MATCHES);
const truncated = todos.length > shown.length;
const lines = [
`todos=${todos.length}${truncated ? " truncated=true" : ""}`,
...shown.map((item) => {
const todo = asRecord(item);
const status = stringField(todo.status) || "unknown";
const content = stringField(todo.content) || stringField(todo.id) || "?";
return `- [${status}] ${truncateClean(content, SEARCH_LINE_CHARS)}`;
})
];
return { text: lines.join("\n"), truncated };
}

function formatSearch(result: Record<string, unknown>): ViewDraft {
const matches = asArray(result.matches);
const shown = matches.slice(0, SEARCH_VIEW_MATCHES);
Expand Down Expand Up @@ -331,6 +384,21 @@ function formatAgent(execution: ToolResultValue, result: Record<string, unknown>
};
}

function formatMcpList(name: string, execution: ToolResultValue, result: Record<string, unknown>): ViewDraft {
if (name === "mcp_list" && Array.isArray(execution.result)) {
const servers = execution.result;
const shown = servers.slice(0, SEARCH_VIEW_MATCHES);
return {
text: [
`servers=${servers.length}`,
...shown.map((item) => `- ${typeof item === "string" ? item : stringifyCompact(item)}`)
].join("\n"),
truncated: servers.length > shown.length
};
}
return formatMcp(result);
}

function formatMcp(result: Record<string, unknown>): ViewDraft {
const payload = result.content ?? result.result ?? result;
const omitted = omitImagePayloads(payload);
Expand Down
Loading