Skip to content

ツール集 read/bash/edit/write/grep/find/ls

源码版本v0.73.1

tools/ ディレクトリは pi の内蔵ツール集だ。各ツールは ToolDefinition (schema、説明、prompt snippet、guidelines を持つ) と AgentTool (実行関数) の二層構造で、wrapToolDefinition で変換される。index.ts はすべてのツールファクトリを re-export し、createCodingTools / createReadOnlyTools / createAllTools の 3 種のプリセット組み合わせを提供する。ファイル書き込み系ツール (edit、write) は withFileMutationQueue で直列化され、同じファイルへの並列変更による競合を避ける。

責務

  1. read:テキスト/画像ファイルを読む。画像は自動 resize (autoResizeImages)、テキストは DEFAULT_MAX_LINES / DEFAULT_MAX_BYTES で打ち切る。packages/coding-agent/src/core/tools/read.ts:205-236 参照。
  2. bash:shell コマンドを実行。detached 子プロセスを追跡し、abort とタイムアウトを提供する。packages/coding-agent/src/core/tools/bash.ts:264-280 参照。
  3. edit / write:ファイル編集と新規作成。両者とも withFileMutationQueue で直列化する。packages/coding-agent/src/core/tools/edit.ts:288-316packages/coding-agent/src/core/tools/write.ts:181-210 参照。
  4. grep / find / ls:ファイル検索と列挙。fdrg に基づき、.gitignore を尊重する。packages/coding-agent/src/core/tools/grep.ts:122-135packages/coding-agent/src/core/tools/find.ts:112-125packages/coding-agent/src/core/tools/ls.ts:99-112 参照。
  5. 組み合わせファクトリ:createToolDefinition / createToolToolName でディスパッチする。createCodingTools はデフォルト 4 件 (read/bash/edit/write)、createReadOnlyTools は 4 件 (read/grep/find/ls)。packages/coding-agent/src/core/tools/index.ts:96-136packages/coding-agent/src/core/tools/index.ts:138-184 参照。
  6. 直列化書き込み:withFileMutationQueue はファイル realpath ごとに Promise チェーンを維持し、同じファイルへの複数回書き込みを呼び出し順に並べる。異なるファイルは並行する。packages/coding-agent/src/core/tools/file-mutation-queue.ts:19-39 参照。

設計動機

なぜツールを二層に分けるのか? ToolDefinition は LLM 向け:schema、description、prompt snippet、guidelines はシステムプロンプトに注入される。AgentTool は実行体で runtime にしか意味がない。分ける利点は、同じ定義で複数の実行体を駆動できること——例えば read ツールの定義は RPC モードで異なる operations 実装に差し替えられる (read の単体テストは mock ファイルシステムを注入できる)。

なぜ書き込みを直列化するのか? LLM は一ターンの中で同じファイルに edit/write を並行で複数回呼ぶかもしれず、直列化しないと後の書き込みが先の書き込みを上書きして内容が壊れる。withFileMutationQueuerealpathSync.native をキーに使うので、シンボリックリンクと実パスが同じキューに対応する。異なるファイルは並行のままで、スループットを落とさない。

なぜ read にデフォルトで promptGuidelines: ["Use read to examine files instead of cat or sed."] が付くのか? システムプロンプト構築時にツールの guidelines が拼まれ、LLM が「bash で cat より read を優先」を見ると非効率なパスを減らせるからだ。

主要ファイル

withFileMutationQueue の実装は promise チェーンで、新呼び出しは古い promise の .then の後にぶら下がる:

typescript
// packages/coding-agent/src/core/tools/file-mutation-queue.ts:19-39
export async function withFileMutationQueue<T>(filePath: string, fn: () => Promise<T>): Promise<T> {
	const key = getMutationQueueKey(filePath);
	const currentQueue = fileMutationQueues.get(key) ?? Promise.resolve();

	let releaseNext!: () => void;
	const nextQueue = new Promise<void>((resolveQueue) => {
		releaseNext = resolveQueue;
	});
	const chainedQueue = currentQueue.then(() => nextQueue);
	fileMutationQueues.set(key, chainedQueue);

	await currentQueue;
	try {
		return await fn();
	} finally {
		releaseNext();
		if (fileMutationQueues.get(key) === chainedQueue) {
			fileMutationQueues.delete(key);
		}
	}
}

read ツールの executesignal: AbortSignal を受け取り、ユーザーが Ctrl+C した時に即座に reject する:

typescript
// packages/coding-agent/src/core/tools/read.ts:225-237
const absolutePath = resolveReadPath(path, cwd);
return new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(
	(resolve, reject) => {
		if (signal?.aborted) {
			reject(new Error("Operation aborted"));
			return;
		}
		let aborted = false;
		const onAbort = () => {
			aborted = true;
			reject(new Error("Operation aborted"));
		};
		signal?.addEventListener("abort", onAbort, { once: true });

データフロー

ツール選択と実行:

境界と失敗

  • abort シグナル:read は signal.aborted の時に即座に reject し、非同期タスク内でも aborted フラグをチェックして race condition を避ける。packages/coding-agent/src/core/tools/read.ts:228-237 参照。
  • realpath 失敗:getMutationQueueKeyrealpathSync.native が throw する時に resolve(filePath) にフォールバックし、削除済みファイルでもキューに入れるようにする。packages/coding-agent/src/core/tools/file-mutation-queue.ts:6-13 参照。
  • 画像 resize 失敗:resized が null を返す時、テキストプレースホルダー「Image omitted: could not be resized below the inline image size limit」に置き換え、直接エラーにしない。packages/coding-agent/src/core/tools/read.ts:255-258 参照。
  • 非視覚モデル:read は ctx?.model が視覚をサポートするかを検出し、サポートしない時は getNonVisionImageNote をテキストとして付け、LLM に画像が実際には見えないことを知らせる。
  • 未知のツール名:createToolDefinition の switch default は Unknown tool name を throw し、黙って undefined を返さない。packages/coding-agent/src/core/tools/index.ts:112-114 参照。

小ねた

tools/ は pi の内蔵ツールボックスで、二層構造 (ToolDefinition は LLM、AgentTool は runtime 向け) を持ち、書き込み系ツールは withFileMutationQueue で直列化して並列競合を避ける。3 種のプリセット組み合わせがコーディング、読み取り専用、フルセットの 3 シナリオを覆う。これらのツールを session に組み立てるのは createAgentSession 装配、ツール呼び出し前後のフックは AgentSession オーケストレーション層 参照。