数据截至 (上游 commit afe54827dd65)
02 · 工具体系与权限闸门
本章讲什么: 模型的「手脚」长什么样,以及 Crush 用什么手段保证这双手不乱动。
1. 工具清单:模型能干哪些事
工具在 buildTools 里一次性装配(internal/agent/coordinator.go:679),
然后按 agent 配置里的 AllowedTools 过滤(:763)、按名字排序(:791)。
| 类别 | 工具 | 要权限吗 |
|---|---|---|
| 文件读 | view、ls、glob、grep | view/ls 只在路径落到工作目录之外时才问(view 另放行 skill 文件);glob/grep 从不问 |
| 文件写 | edit、multiedit、write | 是 |
| 执行 | bash、job_output、job_kill | bash 分级(见 §3);两个 job 工具不问 |
| 网络 | fetch、download、agentic_fetch | 是 |
| 代码搜索 | sourcegraph | 否 |
| LSP | lsp_diagnostics、lsp_references、lsp_definition、lsp_symbols、lsp_call_hierarchy、lsp_rename、lsp_replace_symbol、lsp_restart | 只有改代码的 lsp_rename/lsp_replace_symbol 要 |
| MCP | list_mcp_resources、read_mcp_resource、以及每个 MCP 服务器暴露的工具 | 是(Docker MCP 有白名单例外) |
| 元 | crush_info、crush_logs、todos、question、agent(子代理) | 否 |
工具名就是模型看到的字面标识符,所 以 LSP 这一排全都带 lsp_ 前缀,一个不能省。
逐个对得上的常量定义:internal/agent/tools/diagnostics.go:22、references.go:25、
lsp_definition.go:22、lsp_symbols.go:18、lsp_call_hierarchy.go:20、lsp_rename.go:27、
lsp_replace_symbol.go:26、lsp_restart.go:16。
四条装配规则值得注意:
- LSP 工具是有条件加入的:只要用户配了 LSP,或
auto_lsp没被显式关掉,就全套加上 (internal/agent/coordinator.go:739)。 - MCP 资源工具也是有条件的:只有配置里真有 MCP 服务器时才装
(
internal/agent/coordinator.go:753)。 question工具只在交互模式、且非子代理时存在(internal/agent/coordinator.go:735)—— 非交互跑批时问用户是没意义的。web_fetch/web_search不在主 agent 的工具表里。它们只发给agentic_fetch内部那个 子代理用,且那个子代理的工作目录是一个临时目录 (internal/agent/agentic_fetch_tool.go:165-174)。主模型想上网只能走agentic_fetch, 而agentic_fetch自己在入口处就要过一次权限(internal/agent/agentic_fetch_tool.go:83,Action: "fetch")。
每个工具的描述文本是单独的 .md 文件(如 internal/agent/tools/edit.md),
部分还是模板(.md.tpl),会按环境注入变量:比如 bash 的描述里会写清当前禁用了哪些命令、
本机有没有 gh 和 rg(internal/agent/tools/bash.go:148 bashDescription)。
工具描述随环境 变化,这是个容易忽略的细节。
2. 权限闸门:一道门,五道短路 + 一次弹窗
它要解决的小问题
模型要写文件、跑命令。你既不想每次都点同意(烦),也不想它偷偷 rm -rf(危险)。
思路
所有副作用工具调用同一个函数 permissions.Request,它按从便宜到昂贵的顺序依次短路,
五道都没命中,才真的去打扰用户(internal/permission/permission.go:181)。
怎么读这张图:从上往下,命中前五层中任意一层就立即返回、不再往下走; 第 ⑥ 步不是短路,是兜底——只有走到那里才会弹窗。
工具调用 permissions.Request(...)
│
① 全局 skip(--yolo)? ────────────► 放行
│否
② 在 allowed_tools 白名单? ───────► 放行
("tool" 或 "tool:action" 两种写法)
│否
③ PreToolUse hook 已判 allow? ────► 放行(仍广播一条 granted 通知)
│否
④ 该会话已整体自动批准? ──────────► 放行
│否
⑤ 同会话+同工具+同动作+同路径 已授权过? ─► 放行
│否
⑥ 广播请求事件,阻塞等 UI 回答 ────► 用户点了才放行