bots-garden/mini-mepublic Fork
⑂ main
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. eca9ec1 · on main · k33g · 7d ago
README.fr.md · 98 lines · 7.1 KBmarkdown
Blame HistoryOpen raw

mini-me depuis Node.js, avec le SDK ACP officiel : lib/minime.js

English version

Un client Node.js qui utilise mini-me comme bibliothèque en pilotant mm -acp par ACP (ticket 188), construit sur le SDK ACP officiel pour TypeScript, @agentclientprotocol/sdk 2.2.0. Il a la même API que le client sans dépendance de ../nodejs/, qui parle JSON-RPC à la main : les exemples des deux dossiers sont les mêmes programmes. La bibliothèque est en JavaScript (ESM) avec des types JSDoc, donc sans étape de compilation. Voir ../README.fr.md pour les messages ACP qui se cachent derrière.

import { Agent } from "./lib/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-sdk
npm install           # le SDK, et zod qu'il demande
node complete.js      # sans stream
node stream.js        # en stream, avec les appels d'outils
node cancel.js        # annulé au bout de 3 secondes
node permission.js    # une commande refusée, puis autorisée

Node 20 ou plus récent. 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 fonctionne.

Pour utiliser la bibliothèque depuis un autre projet, tant qu'elle n'est pas publiée : npm install ../chemin/vers/demo.acp.sdk/nodejs-sdk, puis import { Agent } from "minime-sdk";.

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 ; se résout en { 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). Renvoyez true (autoriser une fois), false (refuser une fois) ou un optionId ACP ("allow_always", "never"). Sans lui, chacun de ces appels est refusé. Un callback qui lève une exception refuse.
onStderr(line) le stderr de mm (bannière, avertissements, lignes [acp]). Sinon il est lu puis jeté ; sa dernière ligne est ajoutée aux erreurs.
await agent.reset() une nouvelle session sur le même processus : la conversation repart de zéro.
await agent.close() ferme le stdin de mm et attend qu'il se termine (le tue au bout de 5 s). L'appeler deux fois est sans effet.
agent.sessionId l'identifiant de session ACP.
eventOf(update), pickOption(options, choice) les deux fonctions pures, exportées pour les tests et pour qui traite lui-même des messages 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}.

Les règles à connaître :

  • Un Agent = un processus mm = une conversation. Chaque appel la continue, 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 par une erreur est rejeté, avec les mots de mm et la dernière ligne de son stderr, par exemple minime: Internal error (-32603): the model repeated the same bash call 6 times…. Si mm a planté, le message dit mm exited: exit status N.
  • mm retire de la conversation une question annulée : la question suivante n'en sait rien.
  • Le callback de permission peut s'exécuter avant que l'événement tool_call soit lu. Le SDK répond aux requêtes de mm dès qu'elles arrivent, alors que les mises à jour de la session attendent dans une file que votre boucle les lise : stream.js affiche 🔐 avant 🛠️. Le client sans dépendance lit les deux dans l'ordre d'arrivée.
  • Le client n'annonce aucune capacité fichiers, terminal ou formulaire : mm n'en a pas besoin, et son outil ask_user n'est pas proposé. Le SDK répond « method not found » à toute requête de ce genre venant de mm.

Les différences avec ../nodejs/

nodejs/ nodejs-sdk/
Protocole JSON-RPC écrit à la main (~300 lignes) le SDK officiel : client(), ndJsonStream, buildSession(cwd).start(), ActiveSession.nextUpdate()
Dépendances aucune @agentclientprotocol/sdk 2.2.0 et zod (sa dépendance « peer »)
Validation des messages aucune le SDK vérifie les messages selon le schéma ACP
API Agent.start, complete, stream, reset, close la même

Tests

npm test        # node --test test/*.test.js — 16 tests, sans modèle ni mm, ~1 s

test/fake-mm.js joue le côté mm d'ACP, comme un vrai processus enfant. Il écrit et lit lui-même les lignes JSON, avec les formats de messages de mm v1.0.3 (quatre options de permission, rawOutput.output, usage dans la réponse au prompt, available_commands_update après session/new) : des réponses, une réflexion, un appel d'outil avec sa permission, un tour lent à annuler, une erreur, un plantage.

Mesures (2026-11-01, llmman sur la machine de l'auteur, mm v1.0.3 compilé depuis l'arbre de travail, Node 22)

Exemple Résultat
complete.js réponse en une phrase, end_turn, 663 tokens, 7,3 s
stream.js find test -name "*.js" | wc -l autorisé par le callback (lecture seule), résultat 2, réponse streamée morceau par morceau, end_turn
cancel.js histoire coupée au bout de 3,0 s (cancelled, 366 caractères gardés) ; la question suivante sur le même Agent a eu sa réponse aussitôt, sans connaître l'histoire, que mm a retirée
permission.js pwd refusé : l'exemple n'affiche rien (le modèle a inventé /root, 3 fois sur 3) ; autorisé : le vrai répertoire

Pas fait

  • Pas de paquet npm publié : il faudrait livrer le binaire mm avec, pour chaque plateforme.
  • session/load / session/resume (sessions enregistrées), images et fichiers joints dans les prompts, formulaires ask_user : non exposés.
  • Pas de délai maximum pour une annulation à laquelle mm ne répondrait jamais : le tour attend la réponse cancelled de mm, comme ACP l'exige.
 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
# mini-me depuis Node.js, avec le SDK ACP officiel : `lib/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 188), construit sur le SDK ACP officiel pour TypeScript, [`@agentclientprotocol/sdk`](https://www.npmjs.com/package/@agentclientprotocol/sdk) 2.2.0. Il a **la même API** que le client sans dépendance de [`../nodejs/`](../nodejs/README.fr.md), qui parle JSON-RPC à la main : les exemples des deux dossiers sont les mêmes programmes. La bibliothèque est en JavaScript (ESM) avec des types JSDoc, donc sans étape de compilation. Voir [`../README.fr.md`](../README.fr.md) pour les messages ACP qui se cachent derrière.

```js
import { Agent } from "./lib/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-sdk
npm install           # le SDK, et zod qu'il demande
node complete.js      # sans stream
node stream.js        # en stream, avec les appels d'outils
node cancel.js        # annulé au bout de 3 secondes
node permission.js    # une commande refusée, puis autorisée
```

Node 20 ou plus récent. `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 fonctionne.

Pour utiliser la bibliothèque depuis un autre projet, tant qu'elle n'est pas publiée : `npm install ../chemin/vers/demo.acp.sdk/nodejs-sdk`, puis `import { Agent } from "minime-sdk";`.

## 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 ; se résout en `{ 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`). Renvoyez `true` (autoriser une fois), `false` (refuser une fois) ou un `optionId` ACP (`"allow_always"`, `"never"`). **Sans lui, chacun de ces appels est refusé.** Un callback qui lève une exception refuse. |
| `onStderr(line)` | le stderr de mm (bannière, avertissements, lignes `[acp]`). Sinon il est lu puis jeté ; sa dernière ligne est ajoutée aux erreurs. |
| `await agent.reset()` | une nouvelle session sur le même processus : la conversation repart de zéro. |
| `await agent.close()` | ferme le stdin de mm et attend qu'il se termine (le tue au bout de 5 s). L'appeler deux fois est sans effet. |
| `agent.sessionId` | l'identifiant de session ACP. |
| `eventOf(update)`, `pickOption(options, choice)` | les deux fonctions pures, exportées pour les tests et pour qui traite lui-même des messages 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}`.

Les règles à connaître :

- **Un Agent = un processus mm = une conversation.** Chaque appel la continue, 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 par une erreur est rejeté**, avec les mots de mm et la dernière ligne de son stderr, par exemple `minime: Internal error (-32603): the model repeated the same bash call 6 times…`. Si mm a planté, le message dit `mm exited: exit status N`.
- **mm retire de la conversation une question annulée** : la question suivante n'en sait rien.
- **Le callback de permission peut s'exécuter avant que l'événement `tool_call` soit lu.** Le SDK répond aux requêtes de mm dès qu'elles arrivent, alors que les mises à jour de la session attendent dans une file que votre boucle les lise : `stream.js` affiche 🔐 avant 🛠️. Le client sans dépendance lit les deux dans l'ordre d'arrivée.
- Le client n'annonce aucune capacité fichiers, terminal ou formulaire : mm n'en a pas besoin, et son outil `ask_user` n'est pas proposé. Le SDK répond « method not found » à toute requête de ce genre venant de mm.

## Les différences avec `../nodejs/`

| | `nodejs/` | `nodejs-sdk/` |
|---|---|---|
| Protocole | JSON-RPC écrit à la main (~300 lignes) | le SDK officiel : `client()`, `ndJsonStream`, `buildSession(cwd).start()`, `ActiveSession.nextUpdate()` |
| Dépendances | aucune | `@agentclientprotocol/sdk` 2.2.0 et `zod` (sa dépendance « peer ») |
| Validation des messages | aucune | le SDK vérifie les messages selon le schéma ACP |
| API | `Agent.start`, `complete`, `stream`, `reset`, `close` | la même |

## Tests

```bash
npm test        # node --test test/*.test.js — 16 tests, sans modèle ni mm, ~1 s
```

`test/fake-mm.js` joue le côté mm d'ACP, comme un vrai processus enfant. Il écrit et lit lui-même les lignes JSON, avec les formats de messages de mm v1.0.3 (quatre options de permission, `rawOutput.output`, usage dans la réponse au prompt, `available_commands_update` après `session/new`) : des réponses, une réflexion, un appel d'outil avec sa permission, un tour lent à annuler, une erreur, un plantage.

## Mesures (2026-11-01, llmman sur la machine de l'auteur, mm v1.0.3 compilé depuis l'arbre de travail, Node 22)

| Exemple | Résultat |
|---|---|
| `complete.js` | réponse en une phrase, `end_turn`, 663 tokens, **7,3 s** |
| `stream.js` | `find test -name "*.js" \| wc -l` autorisé par le callback (lecture seule), résultat `2`, réponse streamée morceau par morceau, `end_turn` |
| `cancel.js` | histoire coupée au bout de **3,0 s** (`cancelled`, 366 caractères gardés) ; la question suivante sur le même Agent a eu sa réponse aussitôt, sans connaître l'histoire, que mm a retirée |
| `permission.js` | `pwd` refusé : l'exemple n'affiche rien (le modèle a **inventé** `/root`, 3 fois sur 3) ; autorisé : le vrai répertoire |

## Pas fait

- Pas de paquet npm publié : il faudrait livrer le binaire `mm` avec, pour chaque plateforme.
- `session/load` / `session/resume` (sessions enregistrées), images et fichiers joints dans les prompts, formulaires `ask_user` : non exposés.
- Pas de délai maximum pour une annulation à laquelle mm ne répondrait jamais : le tour attend la réponse `cancelled` de mm, comme ACP l'exige.