Releases: chenbhao/codev
Releases · chenbhao/codev
Release list
v2.1.0
auto create subagent & autodream and auto-compact
Full Changelog: v2.0.0...v2.0.1
auto create subagent & autodream and auto-compact
WebSearchTool via SearXNG
🚀 WebSearchTool v2.0.0
✨ Highlights
WebSearchTool v2.0.0 is officially released — now powered by SearXNG.
🔍 Local-first web search
🛡️ Privacy-friendly (no tracking)
🌐 Multi-engine aggregation (Google / Bing / DuckDuckGo...)
🧹 Cleaned & normalized outputs
🧠 Structured for LLM tool-calling
Turn your LLM into a real web agent.
📊 WebSearchTool 执行流程图
执行步骤:
1. 开始性能计时
2. 验证查询参数
3. 发送进度更新(如果有)
4. 调用 searchSearXNG()
5. 清洗搜索结果
6. 格式化输出
7. 返回结果
🔍 searchSearXNG(query)
文件位置: src/tools/WebSearchTool/WebSearchTool.ts:51-92
步骤:
1. 构建请求 URL
http://localhost:8080/search?q={query}&format=json
2. 设置超时控制 (10 秒)
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 10000)
3. 发送 HTTP 请求
const res = await fetch(url, {
signal: controller.signal,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; WebSearchTool/1.0)',
'Accept': 'application/json'
}
})
4. 清除超时
clearTimeout(timeout)
5. 检查 HTTP 状态码
if (!res.ok) { throw Error(`HTTP ${res.status}`) }
6. 解析 JSON 响应
const data = await res.json()
7. 提取前 10 个结果
return (data.results || []).slice(0, 10).map(r => ({
title: r.title,
url: r.url,
snippet: r.content
}))
🌐 SearXNG 服务
地址: localhost:8080
返回结构:
{
query: "search term",
number_of_results: 0,
results: [
{ title: "...", url: "...", content: "..." },
...
]
}
🧹 数据清洗 Pipeline
文件位置: src/tools/WebSearchTool/WebSearchTool.ts:95-117
1. stripTags(text)
-
移除
<script>/<style> -
移除所有 HTML 标签
-
转换 HTML 实体:
&→&<→<>→>"→"'→' → 空格
2. normalizeText(text)
- 压缩多个空格 → 单个空格
- 压缩换行 → 最多两个换行
- 去除首尾空白
3. cleanSearchResult(result)
title -> stripTags + normalizeText
snippet -> stripTags + normalizeText
✅ 清洗结果示例
{
"title": "Clean Title",
"url": "https://example.com",
"snippet": "Clean snippet without HTML tags"
}📦 格式化输出
文件位置: src/tools/WebSearchTool/WebSearchTool.ts:219-242
{
"query": "search term",
"results": [
{
"tool_use_id": "search-1",
"content": [
{ "title": "...", "url": "...", "snippet": "..." }
]
}
],
"durationSeconds": 0.5
}🔄 结果映射 (Tool → Claude)
文件位置: src/tools/WebSearchTool/WebSearchTool.ts:244-266
Results for "search term"
1. Title 1
https://url1.com
Snippet 1
2. Title 2
https://url2.com
Snippet 2
返回格式:
{
"tool_use_id": "toolu_xxx",
"type": "tool_result",
"content": "Results for \"search term\"..."
}🤖 返回给 Claude API
{
"type": "content",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_xxx",
"content": "Results..."
}
]
}🏗️ WebSearchTool 架构图
分层结构
用户层
├── CLI (Ink.js)
├── IDE 插件 (VS Code)
└── Web UI (React)
↓
Claude API 层
├── @anthropic-ai/sdk
│ ├── 消息处理
│ ├── 工具调用
│ └── 流式响应
↓
Query Engine
├── 查询解析
├── 工具调度
└── 响应格式化
↓
Tool Execution Pipeline
├── 工具查找
├── 输入验证 (Zod)
├── 权限检查
├── Hooks
├── tool.call()
└── 结果映射
↓
WebSearchTool 核心
├── 工具定义
├── Schema
├── 核心方法
└── 辅助函数
↓
外部服务
├── SearXNG (localhost:8080)
└── HTTP Fetch
🔄 数据流转换图
阶段 7: stripTags()
输入
{
"title": "<b>TypeScript</b> Tutorial",
"snippet": "Learn <a href='#'>TypeScript</a>..."
}输出
{
"title": "TypeScript Tutorial",
"snippet": "Learn TypeScript..."
}阶段 8: normalizeText()
"with examples" → "with examples"
"\n\n\n" → "\n\n"
阶段 9: 结果格式化
{
"query": "typescript tutorial",
"results": [...],
"durationSeconds": 0.5
}阶段 10: 文本转换
Results for "typescript tutorial"
1. Title
URL
Snippet
⚠️ 错误处理流程
❌ HTTP 错误
if (!res.ok) {
throw new Error(`HTTP ${res.status}`)
}示例:
HTTP 403: ForbiddenHTTP 500: Internal Server Error
⏱️ 请求超时
setTimeout(() => controller.abort(), 10000)错误:
AbortError: The operation was aborted
🧩 JSON 解析失败
SyntaxError: Unexpected token < in JSON
🔍 无搜索结果
if (cleaned.length === 0) {
output = [`No results for: ${input.query}`]
}✅ 总结
WebSearchTool 核心流程:
Query
→ SearXNG 请求
→ 数据清洗
→ 结构化输出
→ 文本映射
→ 返回 Claude
Research and Auto Evolve
v1.0.0 auto research and evolve