Ensemble d'outils read/bash/edit/write/grep/find/ls
Le répertoire tools/ est l'ensemble d'outils intégrés de pi. Chaque outil est une structure à deux couches — ToolDefinition (avec schema, description, prompt snippet, guidelines) et AgentTool (la fonction d'exécution) — reliées par wrapToolDefinition. index.ts re-export toutes les factories d'outils et fournit trois combinaisons préréglées : createCodingTools / createReadOnlyTools / createAllTools. Les outils d'écriture de fichiers (edit, write) sont sérialisés via withFileMutationQueue pour éviter les races liées à des modifications concurrentes du même fichier.
Responsabilités
- read : lit fichiers texte et images ; les images peuvent être auto-resize (
autoResizeImages) ; le texte est tronqué selonDEFAULT_MAX_LINES/DEFAULT_MAX_BYTES. Voirpackages/coding-agent/src/core/tools/read.ts:205-236. - bash : exécute des commandes shell, suit les sous-processus detached, gère abort et timeout. Voir
packages/coding-agent/src/core/tools/bash.ts:264-280. - edit / write : édition et création de fichiers, tous deux sérialisés via
withFileMutationQueue. Voirpackages/coding-agent/src/core/tools/edit.ts:288-316etpackages/coding-agent/src/core/tools/write.ts:181-210. - grep / find / ls : recherche et listing de fichiers, basés sur
fdetrg, respectent.gitignore. Voirpackages/coding-agent/src/core/tools/grep.ts:122-135,packages/coding-agent/src/core/tools/find.ts:112-125etpackages/coding-agent/src/core/tools/ls.ts:99-112. - Factories de combinaison :
createToolDefinition/createTooldispatchent parToolName;createCodingToolsdonne le quatuor par défaut (read/bash/edit/write),createReadOnlyToolsun quatuor read-only (read/grep/find/ls). Voirpackages/coding-agent/src/core/tools/index.ts:96-136etpackages/coding-agent/src/core/tools/index.ts:138-184. - Sérialisation des écritures :
withFileMutationQueuemaintient une chaîne de Promises par realpath de fichier ; les écritures sur un même fichier s'y mettent en file selon l'ordre d'appel, les fichiers distincts restent parallèles. Voirpackages/coding-agent/src/core/tools/file-mutation-queue.ts:19-39.
Motivation de design
Pourquoi deux couches d'outils ? ToolDefinition est destiné au LLM : schema, description, prompt snippet, guidelines — tout ça est injecté dans le system prompt. AgentTool est le corps d'exécution, qui n'a de sens que pour le runtime. L'intérêt de la séparation est qu'une même définition peut piloter plusieurs exécutions — par exemple, la définition de read peut, en mode RPC, être branchée à une implémentation alternative de operations (les tests unitaires de read peuvent injecter un filesystem mock).
Pourquoi sérialiser les écritures ? Le LLM peut, dans un même tour, lancer plusieurs edit/write en parallèle sur le même fichier. Sans sérialisation, le dernier écrit écrase le premier, et le contenu part en vrille. withFileMutationQueue utilise realpathSync.native comme clé, de sorte que les liens symboliques et les chemins réels tombent dans la même file. Les fichiers distincts restent parallèles, sans perte de throughput.
Pourquoi read a-t-il par défaut promptGuidelines: ["Use read to examine files instead of cat or sed."] ? Parce qu'à la construction du system prompt, les guidelines de l'outil y sont concaténées, et un LLM qui voit « préférez read à bash qui lance cat » évite quelques chemins inefficaces.
Fichiers clés
packages/coding-agent/src/core/tools/— répertoire des outils : bash.ts / edit.ts / find.ts / grep.ts / ls.ts / read.ts / write.ts / truncate.ts / file-mutation-queue.ts.packages/coding-agent/src/core/tools/index.ts:1-69— re-export de tous lescreate*Tool/create*ToolDefinition.packages/coding-agent/src/core/tools/index.ts:81-115— typeToolNameet dispatchcreateToolDefinition.packages/coding-agent/src/core/tools/index.ts:138-196— trois combinaisons préréglées :createCodingTools/createReadOnlyTools/createAllTools.packages/coding-agent/src/core/tools/file-mutation-queue.ts:4-13— MapfileMutationQueuesetgetMutationQueueKey, résolution par realpath.packages/coding-agent/src/core/tools/file-mutation-queue.ts:19-39—withFileMutationQueue, file d'attente par chaîne de Promises.packages/coding-agent/src/core/tools/read.ts:205-236—createReadToolDefinition: détection d'images, resize, gestion du signal d'abort.packages/coding-agent/src/core/tools/read.ts:360-362—createReadTool, wrapping viawrapToolDefinition.
L'implémentation de withFileMutationQueue est une chaîne de promises : chaque nouvel appel s'accroche au .then de la précédente :
// 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);
}
}
}L'execute de read reçoit un signal: AbortSignal et reject immédiatement quand l'utilisateur fait Ctrl+C :
// 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 });Flux de données
Sélection et exécution d'outil :
Limites et échecs
- Signal d'abort : read reject immédiatement si
signal.aborted, et la tâche asynchrone vérifie le flagabortedpour éviter une race condition. Voirpackages/coding-agent/src/core/tools/read.ts:228-237. - Échec de realpath :
getMutationQueueKeyretombe surresolve(filePath)quandrealpathSync.nativethrow, pour pouvoir quand même mettre en file un fichier déjà supprimé. Voirpackages/coding-agent/src/core/tools/file-mutation-queue.ts:6-13. - Échec de resize d'image : si
resizedrenvoie null, on remplace par un placeholder texte « Image omitted: could not be resized below the inline image size limit », sans erreur directe. Voirpackages/coding-agent/src/core/tools/read.ts:255-258. - Modèle non vision : read détecte si
ctx?.modelsupporte la vision ; sinon, on attache un texte d'avertissementgetNonVisionImageNotepour que le LLM sache que l'image n'est pas réellement visible. - Nom d'outil inconnu : le
switch defaultdecreateToolDefinitionthrowUnknown tool name, pas de retour silencieux undefined. Voirpackages/coding-agent/src/core/tools/index.ts:112-114.
Résumé
tools/ est la boîte à outils intégrée de pi : structure à deux couches (ToolDefinition pour le LLM, AgentTool pour le runtime) ; les outils d'écriture sont sérialisés via withFileMutationQueue pour éviter les races concurrentes. Trois combinaisons préréglées couvrent les cas codage, lecture seule, et full set. Pour l'assemblage de ces outils dans la session, voir Assemblage createAgentSession ; pour les hooks autour des appels d'outils, voir AgentSession : couche d'orchestration.