Skip to content

Werkzeugset read/bash/edit/write/grep/find/ls

源码版本v0.73.1

Das tools/-Verzeichnis ist pi's eingebautes Werkzeugset. Jedes Werkzeug ist eine Doppelschicht aus ToolDefinition (mit schema, Beschreibung, prompt snippet, guidelines) und AgentTool (Ausführungsfunktion), umgewandelt über wrapToolDefinition. index.ts re-exportiert alle Werkzeugfabriken und bietet mit createCodingTools / createReadOnlyTools / createAllTools drei Preset-Kombinationen. Datei-schreibende Werkzeuge (edit, write) werden über withFileMutationQueue serialisiert, um Race Conditions bei paralleler Modifikation derselben Datei zu vermeiden.

Verantwortung

  1. read: Liest Text-/Bilddateien, Bilder unterstützen auto-resize (autoResizeImages), Text wird nach DEFAULT_MAX_LINES / DEFAULT_MAX_BYTES abgeschnitten. Siehe packages/coding-agent/src/core/tools/read.ts:205-236.
  2. bash: Führt Shell-Befehle aus, verfolgt detached-Kindprozesse, bietet abort und Timeout. Siehe packages/coding-agent/src/core/tools/bash.ts:264-280.
  3. edit / write: Dateien editieren und neu anlegen, beide gehen über withFileMutationQueue-Serialisierung. Siehe packages/coding-agent/src/core/tools/edit.ts:288-316, packages/coding-agent/src/core/tools/write.ts:181-210.
  4. grep / find / ls: Dateisuche und Auflistung, basierend auf fd und rg, respektiert .gitignore. Siehe packages/coding-agent/src/core/tools/grep.ts:122-135, packages/coding-agent/src/core/tools/find.ts:112-125, packages/coding-agent/src/core/tools/ls.ts:99-112.
  5. Kombinationsfabriken: createToolDefinition / createTool verteilen nach ToolName, createCodingTools ist das default-4er-Set (read/bash/edit/write), createReadOnlyTools das 4er-Set (read/grep/find/ls). Siehe packages/coding-agent/src/core/tools/index.ts:96-136, packages/coding-agent/src/core/tools/index.ts:138-184.
  6. Serialisiertes Schreiben: withFileMutationQueue pflegt pro Realpath einer Datei eine Promise-Kette, mehrfache Schreibvorgänge an derselben Datei werden nach Aufrufreihenfolge gereiht, verschiedene Dateien parallel. Siehe packages/coding-agent/src/core/tools/file-mutation-queue.ts:19-39.

Entwurfsmotivation

Warum zweischichtig? ToolDefinition ist für den LLM: schema, description, prompt snippet, guidelines werden in den Systemprompt injiziert. AgentTool ist der Ausführungskörper, nur für die Runtime relevant. Die Trennung erlaubt es, dieselbe Definition für mehrere Ausführungskörper zu treiben - so kann die Definition des read-Werkzeugs im RPC-Modus durch eine andere operations-Implementierung ersetzt werden (read-Einheitentests können ein mock-Dateisystem injizieren).

Warum Schreiben serialisieren? Ein LLM kann in einer Runde mehrfach edit/write parallel aufrufen und dieselbe Datei modifizieren, ohne Serialisierung überschreibt das spätere Schreiben das frühere und der Inhalt wird chaotisch. withFileMutationQueue nutzt realpathSync.native als Key, sodass symbolische Links und echte Pfade auf dieselbe Warteschlange zeigen. Verschiedene Dateien bleiben parallel, kein Durchsatzverlust.

Warum hat read default promptGuidelines: ["Use read to examine files instead of cat or sed."]? Weil beim Systemprompt-Aufbau die guidelines des Werkzeugs eingefügt werden und der LLM bei "bevorzuge read statt bash für cat" weniger ineffiziente Pfade geht.

Wichtige Dateien

Die Implementierung von withFileMutationQueue ist eine Promise-Kette, ein neuer Aufruf hängt sich an .then des alten Promise an:

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);
		}
	}
}

Das execute des read-Werkzeugs nimmt signal: AbortSignal und rejectet bei Ctrl+C sofort:

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 });

Datenfluss

Werkzeugauswahl und Ausführung:

Grenzen und Fehler

Zusammenfassung

tools/ ist pi's eingebautes Werkzeugset, zweischichtig (ToolDefinition für den LLM, AgentTool für die Runtime), schreibende Werkzeuge über withFileMutationQueue serialisiert, um Race Conditions zu vermeiden. Drei Preset-Kombinationen decken Coding, read-only und Vollset ab. Wie diese Werkzeuge in eine Session eingebaut werden, siehe createAgentSession Zusammenbau; die Hooks vor und nach Werkzeugaufrufen siehe AgentSession Orchestrierungsschicht.