工具接口设计
概述
每个工具都遵循 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 | 原因 |
|---|---|---|
| GrepTool | true | 只读搜索 |
| GlobTool | true | 只读文件匹配 |
| FileReadTool | true | 只读 |
| BashTool | 取决于命令 | 只读命令安全 |
| FileEditTool | false | 修改文件 |
| FileWriteTool | false | 创建文件 |
| AgentTool | false | 复杂副作用 |