Files
Loki/docs/superpowers/specs/2026-10-15-rust-migration-lot7-outils-design.md
T
Claude f11f667a4c Lot 7 : outils git exécutés par la façade
git_status, git_diff et git_clone (rust/loki-rs/src/tools/git.rs) quand la
façade tient la conversation : dépôt deviné comme le Go (sous-dossier
demandé, racine, unique sous-dossier dépôt), sorties mêlées et bornées,
jamais d'invite, clone limité à https:// et git@hôte: et rangé dans le
dossier de la discussion. Toujours sur cette machine, cible distante ou
non, comme le Go.

Parité : TestPariteOutilsGit (deux dépôts, l'un modifié, l'autre sans
commit ; aucun appel réseau) range tests/parity_tools/git.json ;
tests/tools_git.rs le retrouve à l'identique. Le rejeu des journaux des
outils est partagé (tests/common/toolsfx.rs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
2026-10-15 12:19:07 +00:00

4.6 KiB

Lot 7 — outils de l'agent exécutés par la façade

Contexte

Lot 6 : quand la façade tient la conversation (LOKI_CHAT=rust), la boucle du tour est en Rust mais chaque appel d'outil repart au Go (/internal/v1/tool/exec). Lot 7 : porter les outils eux-mêmes, en retirant les appels au Go un par un. Rien ne change sans LOKI_CHAT=rust : la boucle Go exécute ses outils comme avant.

Étape 1 — fichiers et shell (fait)

Exécutés par la façade (rust/loki-rs/src/tools/) : read, grep, glob, write, edit, bash, ask, avec les mêmes garde-fous dans le même ordre (commande catastrophique, & final en mode Code, bac à sable du mode Code, dossier mémoire interdit, « lu avant d'écrire »), le même diff pour l'UI et le même nettoyage de la sortie du shell (| tail -N, ANSI, fin bornée).

L'état partagé reste au Go, en un seul exemplaire, derrière trois routes internes (web_internal_toolstate.go) :

Route Rôle
POST /internal/v1/tool/context dossier de travail (agentCwd), dossier mémoire, cible distante
POST /internal/v1/tool/tracker read : lecture notée ; check : refus éventuel avant écriture
POST /internal/v1/tool/wrote après une écriture : note du suivi, bloc des diagnostics LSP

Le suivi reste au Go parce que les sous-agents et les tâches planifiées, qui y tournent, le lisent et l'écrivent aussi ; les serveurs LSP y vivent.

Repli sur le Go : outil non porté ; write/edit/bash quand l'agent vise un poste distant (une commande catastrophique est refusée avant, ici) ; contexte indisponible.

Le jeton de l'API interne est retiré de l'environnement du shell de l'agent.

Parité

internal/loki/parity_tools_test.go passe 58 appels à execTool sur une arborescence de test et range le journal (libellés, résultats, diffs, questions, arborescence finale) dans rust/loki-rs/tests/parity_tools/ ; rust/loki-rs/tests/tools.rs rejoue les mêmes appels dans exec_local et retrouve le même journal. Le test Go échoue si le comportement Go change (LOKI_PARITY_UPDATE=1 pour régénérer, puis le test Rust dit si le port suit).

Écarts assumés

  • Motif grep invalide : le message d'erreur est celui du moteur d'expressions de Rust (crate regex), pas celui de Go.
  • Classes \w, \b, \s, \d d'un motif grep : Unicode en Rust, ASCII en Go (un mot accentué y est un mot entier).
  • Octets hors UTF-8 dans un fichier lu ou cherché : remplacés par U+FFFD par séquence invalide (Go : par octet, à l'encodage JSON). edit travaille sur les octets et laisse intact ce qu'il ne remplace pas.
  • mkdir en échec : le chemin cité est le dossier parent visé, pas le composant qui a échoué.

Étape 2 — boucle du contrat du mode Code (fait)

codeVerifyLoop porté (rust/loki-rs/src/chat/verify.rs) : à la fin d'un tour de build en mode Code, relances du builder sur les critères encore ouverts, passe de vérification sur un contexte isolé (POST /internal/v1/turn/verifier : prompt du rôle et faits de la machine, outils fermés, rôle verifier qui seul peut marquer passed), corrections, abandon dit dans le fil après deux corrections. Mêmes deltas que le Go (role, verify_done, mesures ctx_isolated). Les critères sont lus en base (chat/crit:<id>) ; l'outil criteria reste au Go. Toute compaction en mode Code rend leur état au résumé, comme compactMessages.

Écart assumé : l'isolation du slot du moteur après la vérification (engineSideJob) reste au Go, qui ne voit pas passer les requêtes de la façade.

Étape 3 — git (fait)

git_status, git_diff, git_clone (rust/loki-rs/src/tools/git.rs) : dépôt deviné comme le Go (sous-dossier demandé, racine, unique sous-dossier dépôt), sorties mêlées et bornées, jamais d'invite, clone limité à https:// et git@hôte: et rangé dans le dossier de la discussion. Toujours sur cette machine, cible distante ou non (comme le Go). Journal de référence tests/parity_tools/git.json (TestPariteOutilsGit, deux dépôts, aucun appel réseau), rejoué par tests/tools_git.rs.

Étapes suivantes

  1. Web (web_search, web_open, web_read, web_grep, web_images) : le cache de pages et la conversion HTML → Markdown (bibliothèques Go) ne se reproduisent pas à l'octet ; à porter avec un journal de référence structurel plutôt qu'exact.
  2. Shell d'arrière-plan (bash_bg, bash_tail) : ses travaux sont lus par l'optimiseur et la suppression d'une discussion, au Go.
  3. Mémoire (mem_*, recall*, tracker) : avec le portage du chiffrement.
  4. Tâches, navigateur (CDP), MCP, sous-agents, critères.