Skip to content

工具接口设计

概述

每个工具都遵循 Tool<Input, Output, P> 接口。这个泛型接口定义了工具的执行、权限检查、渲染等标准契约。

Source: src/Tool.ts (792 行)

Tool 类型定义

typescript
// Source: src/Tool.ts:362-695
interface Tool<Input, Output, P> {
  // === 核心标识 ===
  name: string                    // 主名称
  aliases?: string[]              // 别名(向后兼容)
  searchHint?: string             // 3-10 词搜索提示
  
  // === 执行 ===
  call(args, context, canUseTool, parentMessage, onProgress?): Promise<ToolResult>
  description(): string | Promise<string>
  inputSchema: ZodSchema          // Zod JSON Schema
  
  // === 权限 ===
  checkPermissions(input, context): Promise<PermissionResult>
  validateInput?(input, context): Promise<ValidationResult>
  
  // === 行为标志 ===
  isConcurrencySafe(input): boolean   // 可并行执行?
  isReadOnly(input): boolean          // 只读操作?
  isDestructive?(input): boolean      // 不可逆操作?
  interruptBehavior?(): 'cancel' | 'block'
  
  // === 配置 ===
  maxResultSizeChars: number          // 结果大小阈值
  strict?: boolean                    // 严格模式
  shouldDefer?: boolean               // 延迟加载
  alwaysLoad?: boolean                // 始终加载
  isMcp?: boolean                     // MCP 工具标志
  
  // === 渲染 ===
  renderToolUseMessage()              // 渲染工具调用
  renderToolResultMessage?()          // 渲染执行结果
  renderToolUseProgressMessage?()     // 渲染进度
  renderToolUseRejectedMessage?()     // 渲染拒绝
  renderToolUseErrorMessage?()        // 渲染错误
  renderGroupedToolUse?()             // 批量渲染
}

buildTool() 构建器

Source: src/Tool.ts:721-792

所有工具使用 buildTool() 工厂函数创建,填充安全默认值:

typescript
const TOOL_DEFAULTS = {
  isEnabled: () => true,
  isConcurrencySafe: () => false,  // 保守默认:不安全
  isReadOnly: () => false,
  isDestructive: () => false,
  checkPermissions: () => ({ behavior: 'allow', updatedInput: input }),
  userFacingName: () => def.name,
};

export function buildTool(def: ToolDef): Tool {
  return { ...TOOL_DEFAULTS, ...def };
}

工具实现模式

每个工具遵循统一的实现模式:

typescript
export const MyTool = buildTool({
  name: 'MyTool',
  maxResultSizeChars: 100_000,
  strict: true,
  
  // Schema 定义
  get inputSchema() {
    return z.object({
      path: z.string(),
      content: z.string().optional(),
    });
  },
  
  // 描述
  async description() {
    return 'Description shown to Claude for tool selection.';
  },
  
  // 系统提示词补充
  async prompt() {
    return 'Guidelines for using this tool...';
  },
  
  // 行为标志
  isConcurrencySafe(input) {
    return true;  // 只读操作可并行
  },
  isReadOnly(input) {
    return true;
  },
  
  // 权限检查
  async checkPermissions(input, context) {
    return checkReadPermissionForTool(MyTool, input, context.toolPermissionContext);
  },
  
  // 执行
  async call(input, context, canUseTool, parentMessage, onProgress) {
    // 1. 验证输入
    // 2. 执行操作
    // 3. 返回结果
    return { data: result };
  },
  
  // UI 渲染
  renderToolUseMessage(input, { verbose }) {
    return <Box>...</Box>;
  },
  renderToolResultMessage(output, progress, options) {
    return <Box>...</Box>;
  },
});

ToolUseContext — 执行上下文

Source: src/Tool.ts:158-300

每次工具执行都携带丰富的上下文:

typescript
type ToolUseContext = {
  // 工具和模型配置
  options: {
    tools: Tool[]
    model: string
    mcpClients: MCPServerConnection[]
    thinkingConfig: ThinkingConfig
    agentDefinitions: AgentDefinition[]
    // ...
  }
  
  // 控制信号
  abortController: AbortController
  
  // 状态访问
  getAppState(): AppState
  setAppState(updater): void
  
  // 文件缓存
  readFileState: FileStateCache  // LRU 缓存
  
  // 消息历史
  messages: Message[]
  
  // 权限上下文
  toolPermissionContext: ToolPermissionContext
  
  // 限流
  fileReadingLimits: RateLimits
  globLimits: RateLimits
}

工具辅助函数

typescript
// Source: src/Tool.ts:348-360

// 按名称或别名查找工具
export function findToolByName(tools: Tool[], name: string): Tool | undefined {
  return tools.find(t => toolMatchesName(t, name));
}

// 检查工具是否匹配名称(含别名)
export function toolMatchesName(tool: Tool, name: string): boolean {
  return tool.name === name || (tool.aliases?.includes(name) ?? false);
}

并发安全标志

isConcurrencySafe 决定工具是否可以与其他工具并行执行:

工具isConcurrencySafe原因
GrepTooltrue只读搜索
GlobTooltrue只读文件匹配
FileReadTooltrue只读
BashTool取决于命令只读命令安全
FileEditToolfalse修改文件
FileWriteToolfalse创建文件
AgentToolfalse复杂副作用

下一步