Interroger un autre agent — explication
De quoi s'agit-il ?
/ask-bob <prompt> permet à l'agent avec qui vous parlez de consulter un autre agent mm : un autre modèle, un autre prompt système, d'autres outils et skills. La réponse de bob est affichée, puis gardée dans votre conversation pour que votre propre modèle s'en serve à votre question suivante. Cette page explique comment c'est construit et pourquoi.
Pourquoi c'est conçu ainsi
Un autre agent est un autre processus. Bob tourne comme un enfant mm -acp -config <fichier de bob>, le même binaire que l'agent qui l'interroge. Le faire tourner dans le même processus était l'alternative évidente, et la mauvaise : la configuration de mm est une variable globale, lue par le moteur, les outils, la compaction et les sessions, et celle de bob diffère sur tous ces points. Un second moteur dans le même processus aurait d'abord demandé de démanteler cette variable globale partout. Un enfant garde chaque agent entier, avec ses propres outils, skills et serveurs MCP.
Les deux parlent ACP. mm parle déjà l'Agent Client Protocol comme serveur, pour les éditeurs. Interroger bob fait de l'agent qui pose la question un client ACP de son enfant. Le protocole apporte gratuitement ce que lire un terminal n'aurait jamais donné : la réponse de bob sous forme de texte, ses appels d'outils comme des événements structurés, ses demandes de permission comme des requêtes auxquelles on peut répondre, et une façon standard d'annuler. Le serveur ACP de mm n'appelle que deux méthodes du client — les mises à jour de session et les demandes de permission — donc le côté client est petit ; les requêtes de fichiers et de terminal sont refusées comme absentes.
Les permissions de bob, c'est vous qui les donnez. Bob est lancé avec AGENT_YOLO=false : chaque appel qu'il filtrerait devient une demande de permission adressée à votre agent, et c'est VOTRE yolo qui décide : activé, l'appel s'exécute ; désactivé, la question va à la façade que vous utilisez — le dialogue de l'éditeur, la zone de la fenêtre, l'invite 🔐 du mode ligne — exactement comme pour les outils de votre propre agent à cet endroit. Le yolo du fichier de bob ne compte pas tant qu'il vous répond. Les outils de bob s'appellent bob/<outil>, donc autoriser le bash de votre agent « pour cette session » n'autorise pas celui de bob. Voir Le mode yolo et les permissions.
La réponse est une paire de messages. Elle entre dans votre historique comme un message utilisateur ([asked bob (fournisseur/modèle): …]) suivi d'un message de l'assistant ([bob's answer] et le texte). Un seul message aurait été plus simple, mais votre question suivante est aussi un message utilisateur, et plusieurs templates de chat (ceux de Gemma, de Mistral) refusent deux messages utilisateur à la suite. Les marques disent qui a dit quoi, pour que votre modèle ne prenne pas la réponse de bob pour la sienne. La réponse est plafonnée comme la sortie d'un outil, à maxOutput caractères : elle atterrit dans la fenêtre de votre modèle.
Chaque demande est une conversation neuve pour bob. Bob ne garde aucune mémoire entre deux demandes. Quand il doit savoir ce que vous faisiez, /ask-with-context-bob envoie une transcription : questions, réponses, une ligne par appel d'outil — jamais les sorties d'outils, qui coûteraient à sa fenêtre ce qu'elles ont déjà coûté à la vôtre, jamais votre prompt système ni le raisonnement. La continuité est explicite, choisie à chaque question, plutôt qu'une seconde conversation qui dérive de son côté.
Un enfant par agent, démarré une fois. Démarrer mm coûte la mise en place de son moteur, la sonde du serveur et ses serveurs MCP. La première demande démarre bob ; les suivantes le réutilisent, chacune avec une nouvelle session. Il s'arrête quand votre agent se termine.
L'enfant est protégé de ce qui est destiné à son parent. Des variables comme AGENT_MODEL, AGENT_PROVIDER ou AGENT_BASE_URL surchargent une configuration ; héritées par bob, elles en feraient silencieusement une copie de vous. Elles sont retirées de son environnement. Bob tourne aussi avec AGENT_SESSIONS=off : il travaille dans votre projet, et ses fichiers de session apparaîtraient sinon dans vos /sessions et /resume.
Les chaînes s'arrêtent. /ask est une commande tapée par une personne ; aucun modèle ne peut l'appeler, donc aucun agent ne boucle tout seul. Une personne pourrait quand même taper /ask dans un agent lui-même interrogé, alors chaque enfant connaît sa profondeur (MM_ASK_DEPTH) : votre agent peut interroger bob, bob peut interroger riker, riker ne peut interroger personne.
La même mécanique répond aux scripts. mm --ask <agent> et mm --ask-with-context <agent> sont les commandes slash de ce qui ne sait que lancer une commande — une skill, un script. Ils démarrent le même enfant en ACP, avec la même protection de l'environnement et la même limite de profondeur, mais la réponse va sur stdout et tout le reste sur stderr, pour que l'appelant récupère la réponse seule. mm exporte MM_BIN et MM_CONFIG vers les commandes de son outil bash, donc une skill appelle « ce mm, avec cette configuration » sans connaître aucun des deux chemins. Deux choses diffèrent des commandes slash, parce que l'appelant est une commande et non une personne. Les appels d'outils de l'agent suivent le yolo de la configuration appelante : autorisés quand il est activé — la personne a déjà validé la commande mm --ask elle-même —, refusés quand il est désactivé, puisque stdin portait la question et que personne n'est là pour répondre. Et mm --ask surveille son processus parent : l'outil bash tue bash quand son budget est écoulé, pas les enfants de bash, et une demande orpheline laissait son agent tourner — et écrire des fichiers — alors que plus personne n'attendait.
Le temps est le point faible. Un modèle local peut mettre une minute à répondre, et une commande bash disposait de 30 secondes ; bashTimeout règle désormais ce budget. Le watchdog de l'agent qui pose la question continue aussi de compter pendant qu'une commande tourne (ticket 57), il faut donc le relever aussi tant que ce ticket n'est pas corrigé.
Alternatives écartées
mm -p "<prompt>"en sous-processus. Un processus par question et rien à garder en vie — mais sa sortie est un écran de terminal (réponse, raisonnement, échos d'outils, couleurs, récapitulatif des commandes) qu'il faudrait analyser ; il ne demande jamais de permission, donc bob lancerait des commandes sans contrôle ; on ne peut l'annuler qu'en le tuant.- Un second moteur dans le même processus. Rapide, sans processus — au prix de transformer la configuration globale en configuration par agent dans tout le code.
- Faire répondre le modèle courant tout de suite avec l'apport de bob. L'utilisateur a choisi autrement : la réponse de bob est affichée et gardée, et vous décidez de la question suivante.
- Garder la conversation de bob d'une demande à l'autre. Deux conversations qui évoluent en parallèle, dont une invisible, sont plus difficiles à suivre qu'une transcription explicite envoyée quand on la demande.
- Seulement un
/ask <nom>générique, y compris dans les éditeurs. Le menu/d'un éditeur complète un nom de commande, jamais son argument ; une commande par agent est la seule façon pour que le menu liste les agents.
Lien avec le reste
- L'enfant est un agent ACP ordinaire ; le parent réutilise le protocole de l'autre côté.
- Ses appels d'outils et ses permissions passent par la même interface d'événements que les trois façades implémentent pour les outils de votre propre agent.
- L'échange fait partie de l'historique comme n'importe quel tour : il est enregistré avec la session, rejoué par
/resume, et résumé par la compression du contexte quand il vieillit. - L'utiliser : comment interroger un autre agent. Toutes les commandes et messages : référence des commandes slash.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|