File size: 13,316 Bytes
eeeb2b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96f34e3
eeeb2b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96f34e3
eeeb2b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5b13359
eeeb2b6
 
 
 
96f34e3
 
 
 
eeeb2b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
762b1c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eeeb2b6
 
96f34e3
 
 
 
5b13359
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1f1f955
 
5b13359
 
 
96f34e3
 
 
5b13359
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# AI 工具系统

## Tool 抽象

所有 AI 可调用的工具(Tool)都通过 **`buildTool()`** 框架构建。每个工具定义以下核心属性:

```
Tool<Input, Output, Progress>
```

### 核心字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `name` | `string` | 工具名称,用于 API 调用标识 |
| `aliases` | `string[]` | 可选的别名,用于向后兼容 |
| `searchHint` | `string` | 3-10 词的关键词提示,辅助 ToolSearch 匹配 |
| `inputSchema` | `Zod Schema` | 输入参数的 Zod 校验 schema |
| `inputJSONSchema` | `object` | 可选的 JSON Schema 直接输出(MCP 工具使用) |
| `outputSchema` | `Zod Schema` | 输出参数的 Zod schema |
| `call()` | 函数 | 工具的核心执行逻辑 |
| `description()` | 函数 | 工具的描述字符串 |
| `prompt()` | 函数 | 返回工具在系统提示词中的内容 |
| `isEnabled()` | 函数 | 工具是否启用(默认 true) |
| `isConcurrencySafe()` | 函数 | 是否支持并发执行(默认 false) |
| `isReadOnly()` | 函数 | 是否为只读操作(默认 false) |
| `isDestructive()` | 函数 | 是否为破坏性操作(删除、覆盖、发送;默认 false) |
| `shouldDefer` | `boolean` | 是否延迟加载(配合 ToolSearch 使用) |
| `alwaysLoad` | `boolean` | 是否始终加载(即使在 ToolSearch 模式下) |
| `maxResultSizeChars` | `number` | 结果超过此大小时持久化到磁盘 |
| `strict` | `boolean` | 是否启用工具调用严格模式 |
| `checkPermissions()` | 函数 | 检查用户权限 |
| `validateInput()` | 函数 | 输入值校验逻辑 |
| `renderToolUseMessage()` | 函数 | 渲染工具调用 UI |
| `renderToolResultMessage()` | 函数 | 渲染工具结果 UI |
| `renderToolUseProgressMessage()` | 函数 | 渲染执行进度 UI |
| `userFacingName()` | 函数 | 面向用户显示的名称 |
| `getActivityDescription()` | 函数 | 进度提示文本 |
| `mapToolResultToToolResultBlockParam()` | 函数 | 将结果映射为 API 格式 |

### buildTool() 默认值

`buildTool()` 提供以下安全默认值:

| 方法 | 默认值 |
|------|--------|
| `isEnabled()` | `true` |
| `isConcurrencySafe()` | `false`(默认不支持并发) |
| `isReadOnly()` | `false`(默认可能写入) |
| `isDestructive()` | `false` |
| `checkPermissions()` | `{ behavior: 'allow', updatedInput: input }`(放行) |
| `toAutoClassifierInput()` | `''`(跳过分类器) |
| `userFacingName()` | `name` |

相关文件:`/home/yuki/Code/Agent/Codev/src/Tool.ts`

---

## 注册机制

### getTools() 流程

`src/tools.ts`**`getTools()`** 函数是工具注册的核心入口:

```
getTools(permissionContext) → Tool[]
```

执行流程:

1. **`CLAUDE_CODE_SIMPLE` 模式**:仅返回 BashTool、FileReadTool、FileEditTool(极简模式)
2. **`getAllBaseTools()`**:收集所有内置工具,按 feature flag 和条件编译
3. **`filterToolsByDenyRules()`**:检查 deny rules,过滤被禁止的工具
4. **`REPL 模式过滤`**:当 REPL 启用时,隐藏原始工具(`REPL_ONLY_TOOLS`5. **`isEnabled()` 过滤**:逐个检查工具是否启用

### assembleToolPool()

`assembleToolPool()` 是内置工具与 MCP 工具的汇聚函数:

1. 调用 `getTools()` 获取内置工具
2. 通过 `filterToolsByDenyRules()` 过滤 MCP 工具
3. 按名称去重(内置工具优先)
4. 按名称排序(保持 prompt cache 稳定性)

### getMergedTools()

单纯合并内置工具与 MCP 工具(不去重、不排序),用于工具搜索阈值计算等场景。

相关文件:`/home/yuki/Code/Agent/Codev/src/tools.ts`

---

## 执行引擎

### runToolUse()

`src/services/tools/toolExecution.ts`**`runToolUse()`** 是工具调用的入口点,接收 `ToolUseBlock` 并返回异步生成器。

执行生命周期:

```
runToolUse(toolUse, assistantMessage, canUseTool, toolUseContext)
  → AsyncGenerator<MessageUpdateLazy>
```

### 完整生命周期

```
LLM 请求工具调用

    ├─ 1. 查找工具 ── findToolByName()
    │      ├─ 找到 → 继续
    │      └─ 未找到 → 尝试别名匹配 → 返回"工具不存在"错误

    ├─ 2. 输入校验 ── inputSchema.safeParse(input)
    │      ├─ 成功 → 继续
    │      └─ 失败 → 返回 Zod 校验错误(含 ToolSearch schema 未发送提示)

    ├─ 3. 自定义校验 ── validateInput()
    │      ├─ 通过 → 继续
    │      └─ 拒绝 → 返回自定义错误消息

    ├─ 4. PreToolUse Hooks ── runPreToolUseHooks()
    │      ├─ 产生消息(进度、附件)
    │      ├─ 产生 hookPermissionResult(提前决定权限)
    │      ├─ 产生 hookUpdatedInput(修改输入)
    │      └─ 产生 stop(钩子要求停止执行)

    ├─ 5. 权限检查 ── resolveHookPermissionDecision()
    │      ├─ permission mode 决定交互方式
    │      ├─ 权限缓存 / alwaysAllow / alwaysDeny / alwaysAsk
    │      ├─ 用户交互弹窗(default 模式)
    │      ├─ 自动分类器(auto 模式)
    │      └─ 结果: allow / reject / ask

    ├─ 6. 工具执行 ── tool.call()
    │      ├─ 执行核心逻辑
    │      ├─ 发送进度通知 (onProgress)
    │      └─ 返回 ToolResult

    ├─ 7. 结果处理 ── mapToolResultToToolResultBlockParam()
    │      ├─ 大结果持久化到磁盘
    │      └─ 生成预览

    ├─ 8. PostToolUse Hooks ── runPostToolUseHooks()
    │      ├─ MCP 工具: 可修改 toolOutput
    │      └─ 非 MCP 工具: 添加附件消息

    └─ 9. 返回结果 ── 生成 MessageUpdateLazy
           ├─ 成功: tool_result 消息
           ├─ 错误: tool_use_error 消息
           └─ 中断: tool_result_stop 消息
```

---

## 权限系统

权限系统基于 `permission mode` 决定工具调用是否需要用户确认:

### Permission Mode

| 模式 | 说明 |
|------|------|
| `default` | 默认模式,敏感操作需用户确认 |
| `acceptEdits` | 自动接受文件编辑类操作 |
| `bypassPermissions` | 绕过所有权限检查 |
| `plan` | 规划模式,限制工具使用 |
| `auto` | 自动模式,分类器决定权限 |

### 权限规则覆盖

根据 `ToolPermissionContext`,系统支持:

- **alwaysAllowRules**: 始终允许的规则(按工具名称、文件路径模式、shell 命令前缀)
- **alwaysDenyRules**: 始终拒绝的规则
- **alwaysAskRules**: 始终询问的规则
- **denyRules**: 在工具注册阶段过滤掉的工具

### 权限决定来源(OTel `source` 词汇)

| 来源 | 说明 |
|------|------|
| `user_temporary` | 用户会话级临时允许 |
| `user_permanent` | 用户永久允许(存盘) |
| `user_reject` | 用户拒绝 |
| `hook` | 钩子系统决定 |
| `config` | 配置/预设规则决定 |

---

## 进度通知系统

工具执行过程中通过 `onProgress` 回调发送进度通知,不同类型的工具有不同的进度类型:

| 进度类型 | 说明 | 对应工具 |
|----------|------|----------|
| `BashProgress` | Shell 命令执行进度 | BashTool |
| `AgentProgress` | 子代理执行进度 | AgentTool |
| `MCPProgress` | MCP 工具调用进度 | MCP 工具 |
| `SkillToolProgress` | 技能执行进度 | SkillTool |
| `TaskOutputProgress` | 后台任务输出进度 | TaskOutputTool |
| `WebSearchProgress` | 网络搜索进度 | WebSearchTool |
| `LocationToolProgress` | 地理位置搜索进度 | LocationTool |
| `REPLToolProgress` | REPL 工具进度 | REPLTool |
| `HookProgress` | 钩子执行进度 | Hooks |

相关文件:
- `/home/yuki/Code/Agent/Codev/src/services/tools/toolExecution.ts` — 执行引擎
- `/home/yuki/Code/Agent/Codev/src/types/tools.ts` — 进度类型定义
- `/home/yuki/Code/Agent/Codev/src/hooks/toolPermission/` — 权限钩子
- `/home/yuki/Code/Agent/Codev/src/utils/permissions/` — 权限工具函数

---

## 关键工具详述

### AgentTool

执行子代理任务的核心工具。

- **输入参数**: `description`, `prompt`, `subagent_type`, `model`, `run_in_background`, `name`, `team_name`, `mode`, `isolation`, `cwd`
- **行为**: 启动一个独立的子代理会话,可指定代理类型、模型、隔离方式
- **权限**: 可能需要用户确认
- **进度**: `AgentProgress` 类型

### BashTool

在本地 Shell 中执行命令。

- **输入参数**: `command`, `timeout`, `description`, `run_in_background`, `dangerouslyDisableSandbox`
- **行为**: 执行任意 shell 命令,支持超时控制、后台运行、沙箱模式
- **权限**: 按命令前缀匹配权限规则
- **进度**: 超过 2 秒显示 `BashProgress`
- **自动分类**: search/read/list 命令会折叠显示

### Read / Edit / Write

三大文件操作工具:

- **FileReadTool**: 读取文件内容,支持 PDF、图片、Jupyter Notebook
- **FileEditTool**: 精确替换文件中的字符串,支持 diff 显示和 git diff 跟踪
- **FileWriteTool**: 创建或覆盖写入文件内容,包含文件变更追踪

### WebSearch / WebFetch

#### 双后端架构

WebSearchTool 支持两个搜索后端:

| 后端 | 类型 | 配置 | 特点 |
|------|------|------|------|
| **Tavily** | 云 API | `TAVILY_API_KEY` 环境变量 | 稳定、无需自托管 |
| **SearXNG** | 自托管 | Docker 运行 `verspersearch` | 完全隐私、无 API 成本 |

后端自动选择:若配置了 `TAVILY_API_KEY` 则使用 Tavily,否则回退到本地 SearXNG。

#### WebFetch

抓取 URL 内容并应用 prompt 处理(提取、总结)。支持将结果渲染为 Markdown 格式,包含图片链接。

配置项:
- `JINA_API_KEY` — 可选的 Jina AI API 密钥,用于增强型内容提取

相关文件:
- `/home/yuki/Code/Agent/Codev/src/Tool.ts` — Tool 类型与 buildTool 框架
- `/home/yuki/Code/Agent/Codev/src/tools.ts` — 工具注册与过滤
- `/home/yuki/Code/Agent/Codev/src/services/tools/toolExecution.ts` — 执行引擎
- `/home/yuki/Code/Agent/Codev/src/services/tools/toolHooks.ts` — 工具钩子

---

### LocationTool

地理位置与地图搜索工具。根据地区自动选择地图服务商:

| 地区 | 服务商 | 环境变量 |
|------|--------|----------|
| 中国大陆 | 高德地图 (Amap) | `AMAP_API_KEY` |
| 海外 | Google Maps | `GOOGLE_MAPS_API_KEY` |

**支持的操作:**

| 动作 | 功能 | Amap API | Google API |
|------|------|----------|------------|
| `locate` | IP 地理定位 (无需 location 参数) | — | — |
| `geocode` | 地址→坐标 | 地理编码 | Geocoding |
| `search_places` | 周边/关键词搜索 POI | POI 周边搜索 | Places / Nearby Search |
| `get_directions` | 两点间路线规划 | 驾车/公交路径规划 | Directions |
| `plan_trip` | 多途经点行程规划 | 分段路径拼接 | 多航点 Directions |

**地区自动检测:** 含中文字符或已知中国城市名 → Amap,否则 → Google。支持 `region` 参数强制指定。

**配合搜索工具:** Prompt 层面指导模型在获取地点后,可调用 WebSearchTool 查攻略/评价,或用 WebFetchTool 获取详情页内容。

**搜索结果数量:** 高德搜索默认翻页至全部结果(每页 1000 条,最多 20 页 ≈ 10000 条);Google 搜索使用 `next_page_token` 翻页(最多 60 条,Google 上限)。`locate` 动作优先尝试 Amap/Google WiFi 指纹定位,最后回退到 IP 定位(3 个 IP 服务)。

**输入参数:** `action` (必填), `location` (必填), `destination`, `query`, `radius` (默认 5000m), `mode` (driving/walking/transit/bicycling), `waypoints`, `type` (Amap POI 类型过滤), `region` (强制指定), `language`

相关文件:
- `/home/yuki/Code/Agent/Codev/src/tools/LocationTool/LocationTool.ts` — 主工具逻辑
- `/home/yuki/Code/Agent/Codev/src/tools/LocationTool/prompt.ts` — 提示词
- `/home/yuki/Code/Agent/Codev/src/tools/LocationTool/UI.tsx` — 渲染组件

#### API Key 申请指南

**高德地图 API Key(中国大陆用)**

1. **注册账号** — 打开 [高德开放平台](https://lbs.amap.com/),点击右上角「注册」
2. **创建应用** — 登录后进入控制台 → 「应用管理」→ 「创建新应用」
3. **添加 Key** — 在创建的应用中点击「添加 Key」→ 服务平台选择 **「Web 服务」**
4. **获取 Key** — 创建成功后复制 Key,设为环境变量:
   ```bash
   export AMAP_API_KEY=你的高德Key
   ```

**Google Maps API Key(海外用)**

1. **创建项目** — 打开 [Google Cloud Console](https://console.cloud.google.com/),创建新项目
2. **启用 API** — 进入「API 和服务」→「库」,搜索并启用以下 API:
   - **Geocoding API**(地址 → 坐标)
   - **Places API**(地点搜索)
   - **Directions API**(路线规划)
3. **创建凭据** — 「API 和服务」→「凭据」→「创建凭据」→「API 密钥」
4. **限制密钥**(强烈建议)— 在凭据页面设置 API 限制,仅允许上面启用的三个 API,避免滥用
5. 设为环境变量:
   ```bash
   export GOOGLE_MAPS_API_KEY=你的GoogleKey
   ```