工具系统

Pi 的工具系统有两层:pi-agent-core 定义通用 AgentToolpi-coding-agent 提供内置 coding 工具和扩展工具 registry。

本章涉及的工具接口、内置工具和扩展工具包装行号见源码索引

关键源码:

  • packages/agent/src/types.ts
  • packages/agent/src/agent-loop.ts
  • packages/coding-agent/src/core/tools/*
  • packages/coding-agent/src/core/extensions/wrapper.ts

AgentTool

低层工具接口:

interface AgentTool<TParameters, TDetails> {
  name: string;
  label: string;
  description: string;
  parameters: TParameters;
  prepareArguments?: (args: unknown) => Static<TParameters>;
  execute(
    toolCallId,
    params,
    signal,
    onUpdate
  ): Promise<AgentToolResult<TDetails>>;
  executionMode?: "parallel" | "sequential";
}

值得注意的字段:

  • parameters: TypeBox/JSON Schema,用于模型工具定义和运行时校验。
  • prepareArguments: 兼容模型输出的小修正点,例如把旧参数形态迁移到新 schema。
  • onUpdate: 工具执行中可以发 partial result,UI 能实时显示。
  • details: 结构化结果,不一定发给模型,但可给 UI、日志、HTML export 使用。
  • executionMode: 单工具可以强制顺序执行。

内置工具

packages/coding-agent/src/core/tools/index.ts 定义了内置工具集合:

  • read
  • bash
  • edit
  • write
  • grep
  • find
  • ls

默认 coding 模式启用 readbasheditwrite。只读工具组启用 readgrepfindls

SDK 可通过:

  • tools: allowlist。
  • excludeTools: denylist。
  • noTools: "all" | "builtin"
  • customTools

来控制暴露给模型的工具集合。

ToolDefinition 与 AgentTool

coding-agent 层有 ToolDefinition,它比低层 AgentTool 更面向扩展和产品:

  • 带 sourceInfo。
  • 可包含 prompt snippet 和 prompt guidelines。
  • 可由扩展注册。
  • 可包装成低层 AgentTool

AgentSession 维护:

  • _toolRegistry: name -> AgentTool。
  • _toolDefinitions: name -> ToolDefinition + sourceInfo。
  • _toolPromptSnippets: 用于系统提示的工具简述。
  • _toolPromptGuidelines: 根据启用工具动态追加提示规则。

因此“工具是否存在”和“工具是否当前激活”是分开的。

文件变更队列

withFileMutationQueue 用于文件写入/编辑这类 mutation 工具。核心思想是把可能互相冲突的文件修改串起来,避免多个工具并发写同一工作区时产生竞态。

这和 agent loop 的 executionMode 配合:低层支持批量并行,但具体工具仍能通过队列或 sequential 模式保护状态。

Bash 与上下文

用户通过 ! 执行 bash 时,coding-agent 会生成 BashExecutionMessage。它可以被转成 LLM user message:

Ran `command`

并包含输出、exit code、cancelled、truncated、fullOutputPath。若 excludeFromContext 为 true,则不会进入 LLM context。

这给了用户一个有用控制:某些命令只想自己看,不想污染模型上下文。

工具结果的双通道

AgentToolResult 有两类数据:

  • content: text/image,发给模型。
  • details: 任意结构化数据,给 UI、导出、扩展、诊断。

这是工具设计里很实用的分离。模型需要简洁、语义化的结果;UI 可能需要 diff、行号、截断状态、完整输出路径等细节。

设计启发

  • 工具 schema 校验应该在执行前统一完成。
  • 工具结果最好分成“给模型看的 content”和“给程序看的 details”。
  • 并行工具执行必须配合顺序 preflight、顺序写回和 per-tool sequential。
  • 用户命令输出要能选择是否进入模型上下文。