Claude Code 源码研究(四)工具系统:43 个内置工具与权限链路

Tool 接口契约(792 行)、ToolSearch 懒加载、maxResultSizeChars 落盘策略、AgentTool 子代理派生——能力层全揭秘。
claude-codesource-coderesearchtoolsagent

这是 Claude Code 源码研究系列的第 4 篇——能力层。Tool 是工程层挂载到模型的"手脚"。

Tool 接口契约

文件:src/Tool.ts(792 行,定义在 362-695 行)

export type Tool<Input, Output, P> = {
  // 元数据
  name: string
  aliases?: string[]
  searchHint?: string                    // ToolSearch 关键字匹配
  shouldDefer?: boolean                  // 是否走 ToolSearch 懒加载
  alwaysLoad?: boolean                   // MCP: _meta['anthropic/alwaysLoad']
  mcpInfo?: { serverName, toolName }     // MCP 元信息
  isMcp?: boolean
  isLsp?: boolean
  strict?: boolean                       // strict 模式(tengu_tool_pear flag)

  // Schema
  inputSchema: z.ZodType                 // zod v4
  inputJSONSchema?: ToolInputJSONSchema  // 直接 JSON Schema(MCP)
  outputSchema?: z.ZodType

  // 执行
  call(args, context, canUseTool, parentMessage, onProgress): Promise<ToolResult>

  // 描述(给模型看)
  description(input, opts): Promise<string>
  prompt(opts): Promise<string>

  // 能力判定
  isEnabled(): boolean
  isConcurrencySafe(input): boolean
  isReadOnly(input): boolean
  isDestructive?(input): boolean         // 不可逆操作
  isOpenWorld?(input): boolean
  isSearchOrReadCommand?(input): { isSearch, isRead, isList? }
  interruptBehavior?(): 'cancel' | 'block'
  requiresUserInteraction?(): boolean
  isTransparentWrapper?(): boolean       // 如 REPLTool 完全委托内部工具

  // 安全
  validateInput?(input, ctx): Promise<ValidationResult>
  checkPermissions(input, ctx): Promise<PermissionResult>
  toAutoClassifierInput(input): unknown  // Auto 模式安全分类器输入

  // 限制
  maxResultSizeChars: number             // 超出落盘,模型收到文件路径

  // 渲染(UI)
  userFacingName(input): string
  renderToolUseMessage(input, opts)
  renderToolResultMessage?(output, ...)
  renderToolUseProgressMessage?(...)
  renderToolUseRejectedMessage?(...)
  renderToolUseErrorMessage?(...)
  renderToolUseQueuedMessage?()
  renderToolUseTag?(input)
  renderGroupedToolUse?(toolUses[], opts) // 并行调用聚合
  getActivityDescription?(input)         // 状态条文本
  getToolUseSummary?(input)
  extractSearchText?(output)              // 转录搜索索引
  isResultTruncated?(output)

  // 副作用
  backfillObservableInput?(input)         // 观察者前回填字段
  mapToolResultToToolResultBlockParam(content, toolUseID)
  getPath?(input)                         // 文件路径工具
  preparePermissionMatcher?(input)
  inputsEquivalent?(a, b)
}

43 个内置工具

类别工具备注
文件FileReadTool / FileWriteTool / FileEditTool / NotebookEditTool / GlobTool / GrepTool / LSPTool6 + LSP
ShellBashTool / PowerShellTool / REPLTool跨平台
网络WebFetchTool / WebSearchTool
代理/任务AgentTool / TaskCreateTool / TaskGetTool / TaskListTool / TaskStopTool / TaskUpdateTool / TaskOutputTool / TeamCreateTool / TeamDeleteTool9
计划/思考EnterPlanModeTool / ExitPlanModeTool / TodoWriteTool / BriefTool / SyntheticOutputTool5
MCPMCPTool / McpAuthTool / ListMcpResourcesTool / ReadMcpResourceTool4
元工具ToolSearchTool / SkillTool / ConfigTool / SleepTool / AskUserQuestionTool / SendMessageTool6
WorktreeEnterWorktreeTool / ExitWorktreeTool2
远程RemoteTriggerTool / ScheduleCronTool2
共享shared/gitOperationTracking, spawnMultiAgent
测试testing/TestingPermissionTool.tsx

关键工具实现要点

AgentTool(最重)

目录:src/tools/AgentTool/(6072 行)

文件行数作用
AgentTool.tsx1397Tool 主体 + UI 渲染
runAgent.ts973子代理 query 循环
loadAgentsDir.ts755加载自定义 agent 定义
agentToolUtils.ts686工具结果处理
forkSubagent.ts210fork-style 派生
resumeAgent.ts265恢复中断的 agent
agentMemorySnapshot.ts197记忆隔离快照
prompt.ts287给主代理看的工具描述

TaskCreateTool(持久任务)

src/tools/TaskCreateTool/TaskCreateTool.ts:48

  • isTodoV2Enabled() 控制启用
  • 输入:subject / description / activeForm / metadata
  • 执行 executeTaskCreatedHooks — 钩子若返回 blockingError 则删除任务
  • 自动展开 UI 任务面板

EnterPlanModeTool(计划模式)

src/tools/EnterPlanModeTool/EnterPlanModeTool.ts:36

  • 修改 toolPermissionContext.mode = 'plan'
  • prepareContextForPlanMode 激活分类器
  • 返回 mapToolResultToToolResultBlockParam 内的指令文本告诉模型:「只探索 / 不写文件 / 用 ExitPlanMode 提交方案
  • KAIROS channels 模式下禁用(避免陷入无法退出)
  • agent 上下文中禁用

buildTool 工厂

src/Tool.ts 末尾的 buildTool(def: ToolDef) 为下列字段提供默认值:

  • isEnabled() => true
  • isConcurrencySafe() => false
  • 其他 Renderer 字段:根据有无回退

工具懒加载 — ToolSearch

部分工具 shouldDefer: true,初始 prompt 里只显示工具名,schema 通过 ToolSearchTool 用关键字搜索后注入:

模型看到: <function name="WebFetch" /> (仅名字)
模型调用: ToolSearch({ query: "fetch url" })
ToolSearch 返回: <function>{schema...}</function>
模型再调用: WebFetch({ url, prompt })

alwaysLoad: true 的工具(如 Bash、Read、Write)始终完整加载。

这个设计很巧:把不常用工具的 schema 推迟到「真正需要时」加载,省下大量首轮 system prompt token——尤其是 MCP 工具往往 schema 巨长。

工具结果落盘

maxResultSizeChars 超过时:

  • 结果保存到磁盘
  • 模型收到预览 + 文件路径
  • 防止单个工具结果撑爆上下文
  • Infinity 表示永不落盘(如 Read — 否则形成 Read→file→Read 死循环)

权限链路

模型 tool_use
  ↓
validateInput(input, ctx)         返回 false → 直接告诉模型失败原因
  ↓
checkPermissions(input, ctx)      返回 ASK → 弹用户对话框(hooks/useCanUseTool)
  ↓                                返回 ALLOW → 执行
  ↓                                返回 DENY → 拒绝
preparePermissionMatcher(input)   解析 hook `if` 条件(如 "Bash(git *)")
  ↓
hooks PreToolUse                   用户自定义脚本拦截
  ↓
call(args, ctx, canUseTool, ...)
  ↓
hooks PostToolUse

下一篇

下一篇拆 Task 系统——7 种任务类型、状态机、ID 防爆破、Token 计费陷阱。