bots-garden/mini-mepublic Fork
⑂ feature/mini-me-as-a-sdk
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. a8d612a · on feature/mini-me-as-a-sdk · k33g · 13d ago
README.fr.md · 86 lines · 5.5 KBmarkdown
Blame HistoryOpen raw

mini-me depuis Node.js : minime.js

English version

Un client Node.js qui utilise mini-me comme bibliothèque en pilotant mm -acp par ACP (ticket 167). Un fichier, minime.js, aucune dépendance (Node ≥ 20 : child_process et readline). Voir ../README.fr.md pour les messages ACP utilisés.

import { Agent } from "./minime.js";

const agent = await Agent.start({ config: "agent.yaml" });

const { text } = await agent.complete("Explain this repository");      // sans stream

for await (const ev of agent.stream("And the tests?")) {               // en stream
  if (ev.kind === "text") process.stdout.write(ev.text);
}

const ac = new AbortController();
setTimeout(() => ac.abort(), 3000);
await agent.complete("A long task", { signal: ac.signal });           // annulé

await agent.close();

Lancer les exemples

llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
llmman serve

cd demo.acp.sdk/nodejs
node examples/complete.js      # sans stream
node examples/stream.js        # en stream, avec les appels d'outils
node examples/cancel.js        # annulé au bout de 3 secondes
node examples/permission.js    # une commande refusée, puis autorisée

mm doit être dans le PATH, ou désigné par MM_BIN. Les exemples utilisent agent.yaml (Qwen3.5 4B sur llmman, bash seulement, yolo: false) ; tout fichier d'agent convient.

L'API

await Agent.start({ config, cwd?, mm?, onPermission?, onStderr? }) lance mm -acp -config <config> (rendu absolu), puis initialize et session/new {cwd}. mm vaut par défaut $MM_BIN, puis mm.
await agent.complete(prompt, { signal?, onEvent? }) un tour ; renvoie { text, stopReason, usage } une fois terminé. onEvent voit chaque événement au fil de l'eau.
agent.stream(prompt, { signal? }) un tour sous forme d'itérateur asynchrone d'événements ; le dernier est done. Sortir de la boucle avant la fin annule le tour.
signal (un AbortSignal) l'annuler envoie session/cancel ; le tour se termine avec stopReason: "cancelled" et le texte déjà reçu.
onPermission(call) appelé quand l'agent veut lancer un outil qui demande une confirmation (yolo: false). Renvoyer true (autoriser une fois), false (refuser une fois) ou un optionId ACP ("allow_always", "never"). Sans lui, tous ces appels sont refusés.
onStderr(line) la sortie d'erreur de mm (bannière, avertissements, lignes [acp]). Sinon elle est lue et ignorée ; sa dernière ligne est ajoutée à l'erreur quand mm s'arrête.
await agent.reset() une nouvelle session sur le même processus : la conversation repart de zéro.
await agent.close() ferme l'entrée standard de mm et attend sa fin.
agent.sessionId l'identifiant de session ACP.

Les événements : {kind: "text", text}, {kind: "thinking", text}, {kind: "tool_call", id, title, toolKind, input}, {kind: "tool_result", id, status, output}, {kind: "done", stopReason, usage, text}.

À savoir :

  • Un Agent = un processus mm = une conversation. Les appels la poursuivent, comme dans un éditeur. Un seul tour à la fois par Agent (un second lève already running) ; lancez plusieurs Agents pour travailler en parallèle.
  • Un tour que mm termine en erreur est rejeté avec les mots de mm, par exemple minime: Internal error (-32603): {"error":"the model repeated the same bash call 6 times…"}.
  • Une question annulée est retirée de la conversation par mm : la question suivante n'en sait rien.
  • Le client n'annonce aucune capacité fichiers, terminal ni formulaire : mm n'en a pas besoin, et son outil ask_user n'est pas proposé.

Tests

npm test        # node --test test/minime.test.js — 11 tests, sans modèle, sans mm

test/fake-mm.js joue le rôle de mm dans ACP, avec les formes de messages capturées sur mm v1.0.1 : des réponses, un appel d'outil avec sa permission, un tour lent à annuler, un plantage. Pas de node --test tout court : il lancerait aussi fake-mm.js comme un test, qui attendrait sans fin.

Mesuré (2026-10-26, llmman sur la machine de l'auteur, mm v1.0.1 compilé depuis l'arbre de travail)

Exemple Résultat
complete.js réponse en une phrase, end_turn, 663 tokens, 2,9 s
stream.js find examples -name "*.js" | wc -l autorisé par le callback (lecture seule), sortie 4, réponse affichée morceau par morceau, end_turn
cancel.js histoire coupée au bout de 3,0 s (cancelled, 383 caractères gardés) ; la question suivante sur le même Agent a répondu tout de suite — sans connaître l'histoire, que mm a retirée
permission.js pwd refusé : le modèle a inventé une réponse (/root) ; autorisé : le vrai dossier. Un refus n'empêche pas un petit modèle de deviner.

Vu sur trois passages, avant que le callback n'autorise find : le modèle a relancé la même commande refusée jusqu'à ce que le détecteur de boucle de mm arrête le tour (6 appels identiques) ; stream() a été rejeté avec ce message — d'où le try/catch de stream.js.

Pas fait

  • La bibliothèque ACP TypeScript officielle n'a pas été essayée (pas de réseau dans le bac à sable où ceci a été écrit) : du JSON-RPC brut garde le client sans dépendance.
  • Pas de paquet npm publié : il faudrait livrer le binaire mm avec, par plateforme.
  • session/load / session/resume (sessions enregistrées), images et fichiers joints dans les prompts, formulaires ask_user : non exposés.
 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
# mini-me depuis Node.js : `minime.js`

*[English version](README.en.md)*

Un client Node.js qui utilise mini-me comme bibliothèque en pilotant `mm -acp` par ACP (ticket 167). Un fichier, `minime.js`, aucune dépendance (Node ≥ 20 : `child_process` et `readline`). Voir [`../README.fr.md`](../README.fr.md) pour les messages ACP utilisés.

```js
import { Agent } from "./minime.js";

const agent = await Agent.start({ config: "agent.yaml" });

const { text } = await agent.complete("Explain this repository");      // sans stream

for await (const ev of agent.stream("And the tests?")) {               // en stream
  if (ev.kind === "text") process.stdout.write(ev.text);
}

const ac = new AbortController();
setTimeout(() => ac.abort(), 3000);
await agent.complete("A long task", { signal: ac.signal });           // annulé

await agent.close();
```

## Lancer les exemples

```bash
llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
llmman serve

cd demo.acp.sdk/nodejs
node examples/complete.js      # sans stream
node examples/stream.js        # en stream, avec les appels d'outils
node examples/cancel.js        # annulé au bout de 3 secondes
node examples/permission.js    # une commande refusée, puis autorisée
```

`mm` doit être dans le PATH, ou désigné par `MM_BIN`. Les exemples utilisent `agent.yaml` (Qwen3.5 4B sur llmman, bash seulement, `yolo: false`) ; tout fichier d'agent convient.

## L'API

| | |
|---|---|
| `await Agent.start({ config, cwd?, mm?, onPermission?, onStderr? })` | lance `mm -acp -config <config>` (rendu absolu), puis `initialize` et `session/new {cwd}`. `mm` vaut par défaut `$MM_BIN`, puis `mm`. |
| `await agent.complete(prompt, { signal?, onEvent? })` | un tour ; renvoie `{ text, stopReason, usage }` une fois terminé. `onEvent` voit chaque événement au fil de l'eau. |
| `agent.stream(prompt, { signal? })` | un tour sous forme d'itérateur asynchrone d'événements ; le dernier est `done`. Sortir de la boucle avant la fin annule le tour. |
| `signal` (un `AbortSignal`) | l'annuler envoie `session/cancel` ; le tour se termine avec `stopReason: "cancelled"` et le texte déjà reçu. |
| `onPermission(call)` | appelé quand l'agent veut lancer un outil qui demande une confirmation (`yolo: false`). Renvoyer `true` (autoriser une fois), `false` (refuser une fois) ou un `optionId` ACP (`"allow_always"`, `"never"`). **Sans lui, tous ces appels sont refusés.** |
| `onStderr(line)` | la sortie d'erreur de mm (bannière, avertissements, lignes `[acp]`). Sinon elle est lue et ignorée ; sa dernière ligne est ajoutée à l'erreur quand mm s'arrête. |
| `await agent.reset()` | une nouvelle session sur le même processus : la conversation repart de zéro. |
| `await agent.close()` | ferme l'entrée standard de mm et attend sa fin. |
| `agent.sessionId` | l'identifiant de session ACP. |

Les événements : `{kind: "text", text}`, `{kind: "thinking", text}`, `{kind: "tool_call", id, title, toolKind, input}`, `{kind: "tool_result", id, status, output}`, `{kind: "done", stopReason, usage, text}`.

À savoir :

- **Un Agent = un processus mm = une conversation.** Les appels la poursuivent, comme dans un éditeur. Un seul tour à la fois par Agent (un second lève `already running`) ; lancez plusieurs Agents pour travailler en parallèle.
- **Un tour que mm termine en erreur est rejeté** avec les mots de mm, par exemple `minime: Internal error (-32603): {"error":"the model repeated the same bash call 6 times…"}`.
- **Une question annulée est retirée de la conversation par mm** : la question suivante n'en sait rien.
- Le client n'annonce aucune capacité fichiers, terminal ni formulaire : mm n'en a pas besoin, et son outil `ask_user` n'est pas proposé.

## Tests

```bash
npm test        # node --test test/minime.test.js — 11 tests, sans modèle, sans mm
```

`test/fake-mm.js` joue le rôle de mm dans ACP, avec les formes de messages capturées sur mm v1.0.1 : des réponses, un appel d'outil avec sa permission, un tour lent à annuler, un plantage. Pas de `node --test` tout court : il lancerait aussi `fake-mm.js` comme un test, qui attendrait sans fin.

## Mesuré (2026-10-26, llmman sur la machine de l'auteur, mm v1.0.1 compilé depuis l'arbre de travail)

| Exemple | Résultat |
|---|---|
| `complete.js` | réponse en une phrase, `end_turn`, 663 tokens, **2,9 s** |
| `stream.js` | `find examples -name "*.js" \| wc -l` autorisé par le callback (lecture seule), sortie `4`, réponse affichée morceau par morceau, `end_turn` |
| `cancel.js` | histoire coupée au bout de **3,0 s** (`cancelled`, 383 caractères gardés) ; la question suivante sur le même Agent a répondu tout de suite — sans connaître l'histoire, que mm a retirée |
| `permission.js` | `pwd` refusé : le modèle a **inventé** une réponse (`/root`) ; autorisé : le vrai dossier. Un refus n'empêche pas un petit modèle de deviner. |

Vu sur trois passages, avant que le callback n'autorise `find` : le modèle a relancé la même commande refusée jusqu'à ce que le détecteur de boucle de mm arrête le tour (6 appels identiques) ; `stream()` a été rejeté avec ce message — d'où le `try/catch` de `stream.js`.

## Pas fait

- La bibliothèque ACP TypeScript officielle n'a pas été essayée (pas de réseau dans le bac à sable où ceci a été écrit) : du JSON-RPC brut garde le client sans dépendance.
- Pas de paquet npm publié : il faudrait livrer le binaire `mm` avec, par plateforme.
- `session/load` / `session/resume` (sessions enregistrées), images et fichiers joints dans les prompts, formulaires `ask_user` : non exposés.