bots-garden/mini-mepublic Fork
⑂ feature/declared-tools
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 5b2f986 · on feature/declared-tools · k33g · 7d ago
control-agent-calls-with-hooks.md · 104 lines · 5.4 KBmarkdown
Blame HistoryOpen raw

Contrôler les relais vers d'autres agents avec des hooks

Ce guide montre comment un agent qui en appelle d'autres (ask_agent, /ask-<nom>, mm --ask) peut vérifier, réécrire ou refuser chaque question avant qu'elle parte, et vérifier ou remplacer chaque réponse quand elle revient. Il suppose un agent avec au moins une entrée dans mmConfigs (voir Laisser l'agent appeler d'autres agents), et que vous savez écrire un hook (voir Protéger l'agent avec des hooks). Les exemples sont en Node.js.

Les hooks vont dans le fichier de l'agent qui appelle. L'agent appelé n'a pas à changer, ni même à le savoir.

Étapes

1. Choisir l'événement

Vous voulez… Événement Réponse
refuser un relais (un budget, un agent qu'on ne doit pas appeler d'ici) preAsk {"action":"deny","reason":"…"}
masquer des secrets, ou couper la conversation envoyée avec with_context preAsk {"prompt":"…","transcript":"…"}
donner des consignes permanentes à l'agent appelé (langue, longueur, format) preAsk {"context":"…"}
transformer un échec en quelque chose que le modèle qui appelle sait traiter postAsk {"answer":"…"}
vérifier le format de la réponse, ajouter une note pour le modèle qui appelle postAsk {"context":"…"}
journaliser chaque relais postAsk rien

2. Écrire le hook

Ce hook preAsk ajoute des consignes permanentes à chaque question envoyée à l'agent expert :

// hooks/house-rules.js
const input = JSON.parse(require("fs").readFileSync(0, "utf8"));

const rules = ["Answer in the language of the question.", "At most 120 words."];
// Via ask_agent, la réponse est lue par le modèle qui appelle, pas par une personne.
if (input.ask.via === "tool") rules.push("No greetings, no questions back.");

console.log(JSON.stringify({ context: rules.join("\n") }));

Et ce hook postAsk journalise le relais et, quand l'agent appelé a échoué, remplace l'erreur par une consigne pour le modèle qui appelle :

// hooks/after-ask.js
const fs = require("fs");
const path = require("path");
const input = JSON.parse(fs.readFileSync(0, "utf8"));

const line = { agent: input.ask.agent, via: input.ask.via, prompt: input.ask.prompt, durationMs: input.durationMs, error: input.error };
fs.mkdirSync(path.join(input.cwd, ".mm"), { recursive: true });
fs.appendFileSync(path.join(input.cwd, ".mm", "ask-audit.jsonl"), JSON.stringify(line) + "\n");

if (input.error && !(input.answer || "").trim()) {
  console.log(JSON.stringify({ answer: `The ${input.ask.agent} agent is unavailable. Tell the user in one sentence; do not answer yourself.` }));
}

3. Les essayer sans mm

echo '{"event":"preAsk","cwd":"/tmp","ask":{"agent":"expert","via":"tool","prompt":"Qu'"'"'est-ce qu'"'"'un inode ?"}}' \
  | node hooks/house-rules.js

Vous devriez voir :

{"context":"Answer in the language of the question.\nAt most 120 words.\nNo greetings, no questions back."}

4. Les déclarer dans le fichier de l'agent qui appelle

mmConfigs:
  expert:
    path: agent.expert.yaml
    description: Technical expert. For every technical question.

hooks:
  preAsk:
    - matcher: ^expert$
      command: node "$MM_CONFIG_DIR/hooks/house-rules.js"
  postAsk:
    - command: node "$MM_CONFIG_DIR/hooks/after-ask.js"

matcher est une expression régulière sur le nom de l'agent appelé ; sans lui, le hook s'exécute pour tous les agents.

5. Démarrer l'agent et vérifier

mm agent.yaml

La bannière se termine par hooks: preAsk×1 postAsk×1. Posez une question que l'agent transmet, puis regardez .mm/ask-audit.jsonl : une ligne par relais, avec "via":"tool". Tapez /ask-expert <question> et la ligne indique "via":"command".

Variantes

  • Un budget par question. Déclarez le même script sur preGeneration (remise à zéro d'un fichier compteur) et sur preAsk (comptage, et deny au-delà de la limite). Ne comptez que "via":"tool" : un relais tapé par l'utilisateur, ou lancé par un script, n'est pas le fait du modèle.
  • Masquer des secrets. Sur preAsk, réécrivez input.ask.prompt et input.ask.transcript et renvoyez les deux. "transcript":"" n'envoie aucune conversation.
  • Un garde-fou. Mettez onError: fail sur un hook preAsk qui ne doit pas être sauté : quand il ne peut pas s'exécuter, le relais est refusé.
  • Avec yolo: false, l'utilisateur approuve d'abord l'appel ask_agent ; preAsk s'exécute après cette approbation, sur la question écrite par le modèle.
  • mm --ask depuis une skill. Les hooks du fichier qu'il lit s'exécutent aussi ("via":"cli"). Avec un hook postAsk, stdout porte la réponse une fois les hooks exécutés : le script appelant lit le remplacement.
  • Les hooks propres à l'agent appelé. Il exécute les hooks de son propre fichier, qui voient "asked":{"depth":1}. Servez-vous-en pour ce qui appartient à cet agent quel que soit l'appelant ; gardez preAsk/postAsk pour ce qui appartient à ce relais.

Voir aussi

  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
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
# Contrôler les relais vers d'autres agents avec des hooks

Ce guide montre comment un agent qui en appelle d'autres (`ask_agent`, `/ask-<nom>`, `mm --ask`) peut vérifier, réécrire ou refuser chaque question avant qu'elle parte, et vérifier ou remplacer chaque réponse quand elle revient. Il suppose un agent avec au moins une entrée dans `mmConfigs` (voir [Laisser l'agent appeler d'autres agents](let-the-agent-call-other-agents.md)), et que vous savez écrire un hook (voir [Protéger l'agent avec des hooks](guard-the-agent-with-hooks.md)). Les exemples sont en Node.js.

Les hooks vont dans le fichier de l'agent **qui appelle**. L'agent appelé n'a pas à changer, ni même à le savoir.

## Étapes

### 1. Choisir l'événement

| Vous voulez… | Événement | Réponse |
|--------------|-----------|---------|
| refuser un relais (un budget, un agent qu'on ne doit pas appeler d'ici) | `preAsk` | `{"action":"deny","reason":"…"}` |
| masquer des secrets, ou couper la conversation envoyée avec `with_context` | `preAsk` | `{"prompt":"…","transcript":"…"}` |
| donner des consignes permanentes à l'agent appelé (langue, longueur, format) | `preAsk` | `{"context":"…"}` |
| transformer un échec en quelque chose que le modèle qui appelle sait traiter | `postAsk` | `{"answer":"…"}` |
| vérifier le format de la réponse, ajouter une note pour le modèle qui appelle | `postAsk` | `{"context":"…"}` |
| journaliser chaque relais | `postAsk` | rien |

### 2. Écrire le hook

Ce hook `preAsk` ajoute des consignes permanentes à chaque question envoyée à l'agent `expert` :

```js
// hooks/house-rules.js
const input = JSON.parse(require("fs").readFileSync(0, "utf8"));

const rules = ["Answer in the language of the question.", "At most 120 words."];
// Via ask_agent, la réponse est lue par le modèle qui appelle, pas par une personne.
if (input.ask.via === "tool") rules.push("No greetings, no questions back.");

console.log(JSON.stringify({ context: rules.join("\n") }));
```

Et ce hook `postAsk` journalise le relais et, quand l'agent appelé a échoué, remplace l'erreur par une consigne pour le modèle qui appelle :

```js
// hooks/after-ask.js
const fs = require("fs");
const path = require("path");
const input = JSON.parse(fs.readFileSync(0, "utf8"));

const line = { agent: input.ask.agent, via: input.ask.via, prompt: input.ask.prompt, durationMs: input.durationMs, error: input.error };
fs.mkdirSync(path.join(input.cwd, ".mm"), { recursive: true });
fs.appendFileSync(path.join(input.cwd, ".mm", "ask-audit.jsonl"), JSON.stringify(line) + "\n");

if (input.error && !(input.answer || "").trim()) {
  console.log(JSON.stringify({ answer: `The ${input.ask.agent} agent is unavailable. Tell the user in one sentence; do not answer yourself.` }));
}
```

### 3. Les essayer sans mm

```bash
echo '{"event":"preAsk","cwd":"/tmp","ask":{"agent":"expert","via":"tool","prompt":"Qu'"'"'est-ce qu'"'"'un inode ?"}}' \
  | node hooks/house-rules.js
```

Vous devriez voir :

```
{"context":"Answer in the language of the question.\nAt most 120 words.\nNo greetings, no questions back."}
```

### 4. Les déclarer dans le fichier de l'agent qui appelle

```yaml
mmConfigs:
  expert:
    path: agent.expert.yaml
    description: Technical expert. For every technical question.

hooks:
  preAsk:
    - matcher: ^expert$
      command: node "$MM_CONFIG_DIR/hooks/house-rules.js"
  postAsk:
    - command: node "$MM_CONFIG_DIR/hooks/after-ask.js"
```

`matcher` est une expression régulière sur le nom de l'agent appelé ; sans lui, le hook s'exécute pour tous les agents.

### 5. Démarrer l'agent et vérifier

```bash
mm agent.yaml
```

La bannière se termine par `hooks: preAsk×1 postAsk×1`. Posez une question que l'agent transmet, puis regardez `.mm/ask-audit.jsonl` : une ligne par relais, avec `"via":"tool"`. Tapez `/ask-expert <question>` et la ligne indique `"via":"command"`.

## Variantes

- **Un budget par question.** Déclarez le même script sur `preGeneration` (remise à zéro d'un fichier compteur) et sur `preAsk` (comptage, et `deny` au-delà de la limite). Ne comptez que `"via":"tool"` : un relais tapé par l'utilisateur, ou lancé par un script, n'est pas le fait du modèle.
- **Masquer des secrets.** Sur `preAsk`, réécrivez `input.ask.prompt` et `input.ask.transcript` et renvoyez les deux. `"transcript":""` n'envoie aucune conversation.
- **Un garde-fou.** Mettez `onError: fail` sur un hook `preAsk` qui ne doit pas être sauté : quand il ne peut pas s'exécuter, le relais est refusé.
- **Avec `yolo: false`**, l'utilisateur approuve d'abord l'appel `ask_agent` ; `preAsk` s'exécute après cette approbation, sur la question écrite par le modèle.
- **`mm --ask` depuis une skill.** Les hooks du fichier qu'il lit s'exécutent aussi (`"via":"cli"`). Avec un hook `postAsk`, stdout porte la réponse une fois les hooks exécutés : le script appelant lit le remplacement.
- **Les hooks propres à l'agent appelé.** Il exécute les hooks de son propre fichier, qui voient `"asked":{"depth":1}`. Servez-vous-en pour ce qui appartient à cet agent quel que soit l'appelant ; gardez `preAsk`/`postAsk` pour ce qui appartient à ce relais.

## Voir aussi

- Tous les champs et leurs effets : [Référence des hooks](../reference/hooks.md#preask)
- Pourquoi ces hooks appartiennent à l'agent qui appelle : [Les hooks — explication](../explanation/hooks.md#des-hooks-autour-des-appels-dagents)
- Un exemple complet : `demos/hooks-ask/`