Une requête HTTP met un de nos agents au travail : Sinda, Omar, Farah, Dali, SoloBro ou Control. Le service ne fait pas un appel d’API — il lance le CLI claudedéjà installé et connecté sur la machine, avec les outils du dépôt. Aucune clé API n’est utilisée : ANTHROPIC_API_KEY est retirée de l’environnement avant le lancement.
Le service écoute sur 127.0.0.1:3060. Publié aussi sur https://ai.offer.brimind.pro, derrière mot de passe.
Le plus court chemin — poser une question et lire la réponse :
curl -X POST http://127.0.0.1:3060/api/ask \
-H 'content-type: application/json' \
-d '{"prompt":"Résume ce dépôt en 3 lignes","agent":"control"}'| Méthode | Route | Pour |
|---|---|---|
| GET | /api/health | l’état réel : CLI présent + version, roster, file, limites. Un ok:false vient toujours avec un why. |
| GET | /api/agents | le roster, relu dans agents/registry.json à chaque appel |
| POST | /api/ask | la demande — voir le corps ci-dessous |
| — | /chat | la page de chat : on écrit, on joint, on choisit l’agent, on lit |
/api/ask{
"prompt": "obligatoire — la demande",
"agent": "web-agent (défaut) | control | solobro | … voir /api/agents",
"sessionId": "s_ab12cd34ef56 — reprend cette conversation (voir plus bas)",
"timeoutMs": 600000,
"attachments": [
{ "name": "fiche.txt", "contentType": "text/plain", "text": "…" },
{ "name": "photo.jpg", "contentType": "image/jpeg", "data": "<base64>" }
]
}agent omis → web-agent (Web, l’agent de ce service : il existe pour lui seul, donc un agent d’équipe éteint ne fait pas tomber le point d’entrée). Une pièce jointe porte soit text, soit data en base64. Le nom est ramené à un basename assaini : ../../.ssh/id_rsa devient id_rsa.
| Code | Quand |
|---|---|
| 200 | {ok:true, answer, agent, durationMs, sessionId} |
| 400 | demande invalide : pas de prompt, agent inconnu, pièce jointe hors limites |
| 429 | la file est pleine — refusé tout de suite, avec le chiffre |
| 502 | l’agent a échoué, a dépassé le délai, ou n’a rien rendu |
Une réponse vide sort en 502, jamais en 200 : un échec doit rester une donnée, jamais un brouillon blanc qui part chez un client.
Chaque conversation est une session. La première réponse rend unsessionId ; renvoyez-le au tour suivant et l’agent reprend là où il s’était arrêté — il ne relit pas votre historique, c’est sa session qui reprend.
# tour 1 — la session s'ouvre
curl -s -X POST http://127.0.0.1:3060/api/ask \
-H 'content-type: application/json' \
-d '{"prompt":"On travaille sur le garage Hurley Bros.","agent":"control"}'
# → { "sessionId": "s_ab12cd34ef56", "session": { "was": "new", "turns": 1 } }
# tour 2 — la même conversation, demain si besoin
curl -s -X POST http://127.0.0.1:3060/api/ask \
-H 'content-type: application/json' \
-d '{"prompt":"Rappelle-moi son prix.","sessionId":"s_ab12cd34ef56"}'
# → { "session": { "was": "resumed" | "woken", "turns": 2 } }| État | Ce que ça veut dire |
|---|---|
open | utilisée récemment — le prochain tour enchaîne |
closed | inactive depuis plus de 60 min : fermée, pas supprimée. Redemander avec son id la réveille (was: "woken"). |
supprimée | le magasin était plein : les plus vieilles partent en premier. Son id revient alors en 400 unknown session, jamais en silence. |
| Route | Pour |
|---|---|
| GET /api/sessions | les conversations en cours, la plus récente d’abord, + l’état du magasin |
GET /api/sessions/<id> | une conversation avec tous ses tours |
DELETE /api/sessions/<id> | l’effacer maintenant |
| — | /chat?session=<id> rouvre la conversation à l’écran |
Trois garde-fous : on ne reprend qu’une session créée ici (l’id d’une autre machine est refusé, jamais passé à --resume) ; un tour à la fois par session (sinon 409) ; et si le transcript du CLI a disparu, l’agent repart à neuf en le disant (session.warning) plutôt que d’oublier en silence. Un appel purement ponctuel peut passer "session": false et ne rien laisser.
chargement…
Jamais un fetch maison : le client partagé scripts/agent.js porte l’URL, le délai et la forme d’un échec.
const agent = require('../scripts/agent');
const r = await agent.ask('Rédige la relance…', { agent: 'followup-agent' });
if (!r.ok) monFilet(r.error); // un échec est une donnée, jamais un blanc
else utiliser(r.answer);node scripts/agent.js health
node scripts/agent.js agents
node scripts/agent.js ask "décris cette image" --agent control --file ./shot.png| Limite | Valeur | Pourquoi |
|---|---|---|
| Requêtes simultanées | 1 | chaque tour est un Claude Code complet — ce chiffre est une affirmation sur la RAM de cette machine, pas sur le service |
| File d’attente | 20 | une file sans porte transforme une rafale en sockets tenues des heures ; au-delà, 429 immédiat avec le chiffre |
| Délai d’une demande | 10 min | couvre l’exécution, pas l’attente en file |
| Pièces jointes | 10 · 10 Mo · 25 Mo | vérifié avant tout décodage |
| Prompt sur stdin | pas d’argv | Linux plafonne un argument à 128 Ko : passé en argument, un prompt plus long ne démarre pas du tout (Argument list too long). Il part donc sur l’entrée standard du CLI |
| Magasin de sessions | 1 Go | plein, les sessions les plus anciennes sont effacées en premier — un dossier qui grandit sans fin est un disque qui se remplit à 3 h du matin |
| Session inactive | 60 min | fermée, pas supprimée : son id la réveille |
| Prompt | 100 000 caractères | — |