overmind-mcp 2.3.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/orchestration/dispatcher.d.ts +3 -3
- package/dist/lib/orchestration/dispatcher.d.ts.map +1 -1
- package/dist/lib/orchestration/dispatcher.js +1 -56
- package/dist/lib/orchestration/dispatcher.js.map +1 -1
- package/dist/lib/processRegistry.d.ts +2 -0
- package/dist/lib/processRegistry.d.ts.map +1 -1
- package/dist/lib/processRegistry.js +21 -2
- package/dist/lib/processRegistry.js.map +1 -1
- package/dist/lib/telemetry.d.ts +17 -5
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +20 -65
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/server.d.ts +16 -28
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +62 -69
- package/dist/server.js.map +1 -1
- package/dist/services/ClaudeRunner.d.ts.map +1 -1
- package/dist/services/ClaudeRunner.js.map +1 -1
- package/dist/services/GeminiRunner.d.ts.map +1 -1
- package/dist/services/GeminiRunner.js +4 -1
- package/dist/services/GeminiRunner.js.map +1 -1
- package/dist/services/KiloRunner.d.ts.map +1 -1
- package/dist/services/KiloRunner.js.map +1 -1
- package/dist/tools/agent_control.d.ts +101 -0
- package/dist/tools/agent_control.d.ts.map +1 -0
- package/dist/tools/agent_control.js +320 -0
- package/dist/tools/agent_control.js.map +1 -0
- package/dist/tools/run_agents_parallel.d.ts +3 -3
- package/docs/agent_control.md +656 -0
- package/package.json +1 -12
- package/scripts/auto-install.mjs +0 -5
- package/scripts/uninstall.mjs +2 -15
- package/dist/bin/rabbitmq-worker.d.ts +0 -2
- package/dist/bin/rabbitmq-worker.d.ts.map +0 -1
- package/dist/bin/rabbitmq-worker.js +0 -63
- package/dist/bin/rabbitmq-worker.js.map +0 -1
- package/dist/bin/temporal-worker.d.ts +0 -2
- package/dist/bin/temporal-worker.d.ts.map +0 -1
- package/dist/bin/temporal-worker.js +0 -24
- package/dist/bin/temporal-worker.js.map +0 -1
- package/dist/lib/broker/rabbitmq.d.ts +0 -28
- package/dist/lib/broker/rabbitmq.d.ts.map +0 -1
- package/dist/lib/broker/rabbitmq.js +0 -67
- package/dist/lib/broker/rabbitmq.js.map +0 -1
- package/dist/lib/broker/rabbitmqDispatch.d.ts +0 -23
- package/dist/lib/broker/rabbitmqDispatch.d.ts.map +0 -1
- package/dist/lib/broker/rabbitmqDispatch.js +0 -77
- package/dist/lib/broker/rabbitmqDispatch.js.map +0 -1
- package/dist/lib/workflow/temporal/activities.d.ts +0 -15
- package/dist/lib/workflow/temporal/activities.d.ts.map +0 -1
- package/dist/lib/workflow/temporal/activities.js +0 -18
- package/dist/lib/workflow/temporal/activities.js.map +0 -1
- package/dist/lib/workflow/temporal/client.d.ts +0 -8
- package/dist/lib/workflow/temporal/client.d.ts.map +0 -1
- package/dist/lib/workflow/temporal/client.js +0 -48
- package/dist/lib/workflow/temporal/client.js.map +0 -1
- package/dist/lib/workflow/temporal/dispatch.d.ts +0 -13
- package/dist/lib/workflow/temporal/dispatch.d.ts.map +0 -1
- package/dist/lib/workflow/temporal/dispatch.js +0 -19
- package/dist/lib/workflow/temporal/dispatch.js.map +0 -1
- package/dist/lib/workflow/temporal/workflows.d.ts +0 -31
- package/dist/lib/workflow/temporal/workflows.d.ts.map +0 -1
- package/dist/lib/workflow/temporal/workflows.js +0 -79
- package/dist/lib/workflow/temporal/workflows.js.map +0 -1
- package/dist/tools/get_agent_status.d.ts +0 -29
- package/dist/tools/get_agent_status.d.ts.map +0 -1
- package/dist/tools/get_agent_status.js +0 -45
- package/dist/tools/get_agent_status.js.map +0 -1
- package/dist/tools/kill_agent.d.ts +0 -22
- package/dist/tools/kill_agent.d.ts.map +0 -1
- package/dist/tools/kill_agent.js +0 -33
- package/dist/tools/kill_agent.js.map +0 -1
- package/dist/tools/stream_agent_output.d.ts +0 -30
- package/dist/tools/stream_agent_output.d.ts.map +0 -1
- package/dist/tools/stream_agent_output.js +0 -44
- package/dist/tools/stream_agent_output.js.map +0 -1
- package/dist/tools/wait_agent.d.ts +0 -30
- package/dist/tools/wait_agent.d.ts.map +0 -1
- package/dist/tools/wait_agent.js +0 -68
- package/dist/tools/wait_agent.js.map +0 -1
- package/docs/ASYNC_AGENT_INTEGRATION.md +0 -311
- package/docs/INDEX.md +0 -144
- package/docs/changelog/CHANGELOG.add.md +0 -106
- package/docs/changelog/CHANGELOG.md +0 -339
- package/docs/docs/OVERMIND_WORKFLOW_GUIDE.md +0 -595
- package/docs/docs/PROJECT_STRUCTURE.md +0 -101
- package/docs/docs/README_POSTGRES_INTEGRATION.md +0 -229
- package/docs/prompt/Claude_code.md +0 -74
- package/docs/prompt/Kilo.md +0 -74
- package/docs/prompt/Kilo_Hermes.md +0 -170
- package/docs/prompt/Minimax4.md +0 -96
- package/docs/tools.md +0 -794
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
# `agent_control` — Contrôle Unifié du Cycle de Vie des Agents
|
|
2
|
+
|
|
3
|
+
> **Outil unifié** qui remplace les 4 outils précédents : `get_agent_status`, `stream_agent_output`, `kill_agent`, `wait_agent`.
|
|
4
|
+
> Document technique complet : usage, patterns async, lookup par PID/timestamp, dashboard.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Table des Matières
|
|
9
|
+
|
|
10
|
+
1. [Vue d'Ensemble](#1-vue-densemble)
|
|
11
|
+
2. [Actions Disponibles](#2-actions-disponibles)
|
|
12
|
+
3. [Codes d'Erreur](#3-codes-derreur)
|
|
13
|
+
4. [Patterns Async avec OverMind](#4-patterns-async-avec-overmind)
|
|
14
|
+
5. [Tracker PID ↔ Session ↔ Agent](#5-tracker-pid--session--agent)
|
|
15
|
+
6. [Dashboard en Temps Réel](#6-dashboard-en-temps-réel)
|
|
16
|
+
7. [Flux Complet de Debug](#7-flux-complet-de-debug)
|
|
17
|
+
8. [Référence Rapide](#8-référence-rapide)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Vue d'Ensemble
|
|
22
|
+
|
|
23
|
+
### Problème Résolu
|
|
24
|
+
|
|
25
|
+
Quand un agent est lancé via `run_agent`, le processus fils (`claude`, `kilo`, etc.) tourne en arrière-plan. Le seul lien entre le processus parent (OverMind MCP) et le processus enfant est le `sessionId` — généré par le runner, opaque pour OverMind.
|
|
26
|
+
|
|
27
|
+
**Problème** : Si OverMind restart ou crash, le `sessionId` est perdu et le child process devient **orphelin**.
|
|
28
|
+
|
|
29
|
+
**Solution** : Le **Process Registry** (`sessions.json`) stocke le mapping complet :
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
pid ↔ sessionId ↔ agentName ↔ runner ↔ status ↔ outputBuffer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`agent_control` est l'unique interface pour interagir avec ce registry.
|
|
36
|
+
|
|
37
|
+
### Architecture
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Client OverMind MCP Process
|
|
41
|
+
│ │ │
|
|
42
|
+
│ run_agent() │ spawn(claude) │
|
|
43
|
+
│──────────────────────────────────►│ registerProcess(pid) │
|
|
44
|
+
│ │─────────────────────────────►│
|
|
45
|
+
│ │ │
|
|
46
|
+
│ agent_control(action: "status") │ │
|
|
47
|
+
│──────────────────────────────────►│ getProcessStatus(pid) │
|
|
48
|
+
│ { status, pid, outputBuffer } │ │
|
|
49
|
+
│◄─────────────────────────────────│ │
|
|
50
|
+
│ │ │
|
|
51
|
+
│ agent_control(action: "stream") │ │
|
|
52
|
+
│──────────────────────────────────►│ read outputBuffer │
|
|
53
|
+
│ { output, isComplete } │ │
|
|
54
|
+
│◄─────────────────────────────────│ │
|
|
55
|
+
│ │ │
|
|
56
|
+
│ agent_control(action: "wait") │ poll every 1s... │
|
|
57
|
+
│──────────────────────────────────►│ │
|
|
58
|
+
│ │ child.on('close') │
|
|
59
|
+
│ { result } │◄─────────────────────────────│
|
|
60
|
+
│◄─────────────────────────────────│ │
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. Actions Disponibles
|
|
66
|
+
|
|
67
|
+
### `status` — Lecture Pure, Zero Side-Effect
|
|
68
|
+
|
|
69
|
+
Retourne l'état courant du process **sans modifier le registry**.
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
agent_control({
|
|
73
|
+
agentName: 'sniper_analyst',
|
|
74
|
+
runner: 'kilo',
|
|
75
|
+
action: 'status',
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Réponse :**
|
|
80
|
+
|
|
81
|
+
```markdown
|
|
82
|
+
**Agent:** sniper_analyst
|
|
83
|
+
**Runner:** kilo
|
|
84
|
+
**Status:** running
|
|
85
|
+
**Started:** 2026-05-10T14:32:00.000Z
|
|
86
|
+
**PID:** 12345
|
|
87
|
+
**Session ID:** sess_abc123
|
|
88
|
+
|
|
89
|
+
**Output Buffer (2048 chars):**
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Thinking...
|
|
93
|
+
Fetching BTC data...
|
|
94
|
+
Analysis complete.
|
|
95
|
+
```
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**États possibles :**
|
|
99
|
+
|
|
100
|
+
| Status | Signification |
|
|
101
|
+
|--------|---------------|
|
|
102
|
+
| `running` | Process actif, PID valide |
|
|
103
|
+
| `done` | Terminé avec code 0 |
|
|
104
|
+
| `failed` | Terminé avec erreur (exit code != 0) |
|
|
105
|
+
| `orphaned` | Parent mort mais child tourne encore |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### `stream` — Lecture + Indicateur de Complétude
|
|
110
|
+
|
|
111
|
+
Retourne l'output accumulé + un flag `isComplete` pour savoir si le process est fini.
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
agent_control({
|
|
115
|
+
agentName: 'sniper_analyst',
|
|
116
|
+
runner: 'kilo',
|
|
117
|
+
action: 'stream',
|
|
118
|
+
sinceTimestamp: 1746892800000, // optionnel
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Réponse :**
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
**Agent:** sniper_analyst
|
|
126
|
+
**Status:** running
|
|
127
|
+
**isComplete:** false
|
|
128
|
+
**PID:** 12345
|
|
129
|
+
**Last Output At:** 2026-05-10T14:32:45.000Z
|
|
130
|
+
|
|
131
|
+
**Output (2048 chars):**
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
Thinking...
|
|
135
|
+
Fetching BTC data...
|
|
136
|
+
```
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Quand `isComplete: true` :
|
|
140
|
+
```markdown
|
|
141
|
+
**Agent:** sniper_analyst
|
|
142
|
+
**Status:** done
|
|
143
|
+
**isComplete:** true
|
|
144
|
+
**PID:** 12345
|
|
145
|
+
|
|
146
|
+
**Output (4096 chars):**
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Final analysis: BUY signal detected.
|
|
150
|
+
```
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### `kill` — Destruction Irréversible
|
|
156
|
+
|
|
157
|
+
Tue le process tree via `taskkill /F /T /PID` (Windows) ou `kill -9` (Unix).
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
agent_control({
|
|
161
|
+
agentName: 'sniper_analyst',
|
|
162
|
+
runner: 'kilo',
|
|
163
|
+
action: 'kill',
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Réponse (succès) :**
|
|
168
|
+
|
|
169
|
+
```markdown
|
|
170
|
+
Agent "sniper_analyst" tué avec succès (PID: 12345). Status mis à jour → 'failed' dans le registry.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Réponse (échec) :**
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
Agent "sniper_analyst" n'est pas en cours d'exécution (status: done). Impossible de tuer un agent déjà terminé.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> **⚠️ IRRÉVERSIBLE** : Une fois tué, le process ne peut pas être récupéré. Utiliser `kill` uniquement pour un abort d'urgence ou kill-switch.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### `wait` — Blocage Async avec Polling
|
|
184
|
+
|
|
185
|
+
Poll toutes les 1s jusqu'à ce que le status ne soit plus `running`, ou que le timeout soit atteint.
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
agent_control({
|
|
189
|
+
agentName: 'sniper_analyst',
|
|
190
|
+
runner: 'kilo',
|
|
191
|
+
action: 'wait',
|
|
192
|
+
timeoutMs: 300000, // 5 minutes (défaut: 900000 = 15 min)
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Réponse (terminé) :**
|
|
197
|
+
|
|
198
|
+
```markdown
|
|
199
|
+
Final analysis: BUY signal detected. Portfolio balanced.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Réponse (timeout) :**
|
|
203
|
+
|
|
204
|
+
```markdown
|
|
205
|
+
Timeout de 300000ms atteint. L'agent "sniper_analyst" est toujours en cours d'exécution (status: running). Utilisez action="kill" pour forcer l'arrêt ou augmentez timeoutMs.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Réponse (erreur) :**
|
|
209
|
+
|
|
210
|
+
```markdown
|
|
211
|
+
Agent terminé avec erreur (failed):
|
|
212
|
+
|
|
213
|
+
TypeError: Cannot read property 'price' of undefined
|
|
214
|
+
at analyzeBTC (/app/bot.js:42)
|
|
215
|
+
at processTicksAndCallbacks (internal/process/task_queues.js:95)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 3. Codes d'Erreur
|
|
221
|
+
|
|
222
|
+
Chaque erreur est structurée avec un **code** pour faciliter le debugging programatique.
|
|
223
|
+
|
|
224
|
+
| Code | Signification | Action recommandée |
|
|
225
|
+
|------|---------------|---------------------|
|
|
226
|
+
| `AGENT_NOT_FOUND` | Agent absent du registry | Vérifier le nom ou le runner |
|
|
227
|
+
| `AGENT_NOT_RUNNING` | Action `kill` sur un agent déjà terminé | Ne pas tuer un agent already done |
|
|
228
|
+
| `KILL_FAILED` | `taskkill`/`kill` a échoué | Vérifier permissions Windows/Unix |
|
|
229
|
+
| `WAIT_TIMEOUT` | Timeout atteint sans terminaison | Augmenter `timeoutMs` ou utiliser `kill` |
|
|
230
|
+
| `ORPHANED_PROCESS` | Process zombie détecté | `kill` puis relancer l'agent |
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 4. Patterns Async avec OverMind
|
|
235
|
+
|
|
236
|
+
### Pattern 1 : Lancer et Ne Pas Bloquer (Fire & Forget)
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
// 1. Lancer l'agent en arrière-plan
|
|
240
|
+
const runResult = await run_agent({
|
|
241
|
+
runner: 'kilo',
|
|
242
|
+
agentName: 'crypto_scanner',
|
|
243
|
+
prompt: 'Scan BTC/USDT for trading opportunities',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// 2. Récupérer le PID depuis le output (format: "PID: 12345")
|
|
247
|
+
// OU depuis le sessionId pour retrouver le process plus tard
|
|
248
|
+
const sessionId = runResult.sessionId; // "sess_abc123"
|
|
249
|
+
|
|
250
|
+
// 3. Polling non-bloquant pour vérifier l'état
|
|
251
|
+
const status = await agent_control({
|
|
252
|
+
agentName: 'crypto_scanner',
|
|
253
|
+
runner: 'kilo',
|
|
254
|
+
action: 'status',
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Pattern 2 : Lancer et Attendre (Blocking Wait)
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
// Une seule ligne pour lancer et attendre
|
|
262
|
+
const result = await agent_control({
|
|
263
|
+
agentName: 'long_task',
|
|
264
|
+
runner: 'claude',
|
|
265
|
+
action: 'wait',
|
|
266
|
+
timeoutMs: 600000, // 10 minutes
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
if (result.isError) {
|
|
270
|
+
console.error('Task failed:', result.content[0].text);
|
|
271
|
+
} else {
|
|
272
|
+
console.log('Result:', result.content[0].text);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Pattern 3 : Orchestration Séquentielle
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
async function runWorkflow(steps) {
|
|
280
|
+
const results = [];
|
|
281
|
+
|
|
282
|
+
for (const step of steps) {
|
|
283
|
+
console.log(`Starting step: ${step.name}`);
|
|
284
|
+
|
|
285
|
+
const result = await agent_control({
|
|
286
|
+
agentName: step.agentName,
|
|
287
|
+
runner: step.runner,
|
|
288
|
+
action: 'wait',
|
|
289
|
+
timeoutMs: step.timeoutMs || 300000,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
if (result.isError) {
|
|
293
|
+
return {
|
|
294
|
+
success: false,
|
|
295
|
+
failedStep: step.name,
|
|
296
|
+
error: result.content[0].text,
|
|
297
|
+
partialResults: results,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
results.push({ step: step.name, output: result.content[0].text });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return { success: true, results };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Usage
|
|
308
|
+
const workflow = await runWorkflow([
|
|
309
|
+
{ name: 'fetch_data', agentName: 'data_fetcher', runner: 'kilo', timeoutMs: 60000 },
|
|
310
|
+
{ name: 'analyze', agentName: 'analyzer', runner: 'claude', timeoutMs: 300000 },
|
|
311
|
+
{ name: 'report', agentName: 'reporter', runner: 'kilo', timeoutMs: 120000 },
|
|
312
|
+
]);
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Pattern 4 : Exécution Parallèle (Fan-Out)
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
// Lancer plusieurs agents en parallèle
|
|
319
|
+
const agents = [
|
|
320
|
+
{ agentName: 'btc_analyst', runner: 'kilo', prompt: 'Analyze BTC' },
|
|
321
|
+
{ agentName: 'eth_analyst', runner: 'kilo', prompt: 'Analyze ETH' },
|
|
322
|
+
{ agentName: 'sol_analyst', runner: 'claude', prompt: 'Analyze SOL' },
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
// Lancer les 3 en parallèle
|
|
326
|
+
const runPromises = agents.map(a =>
|
|
327
|
+
run_agent({ runner: a.runner, agentName: a.agentName, prompt: a.prompt })
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
await Promise.all(runPromises);
|
|
331
|
+
|
|
332
|
+
// Attendre que tous soient prêts
|
|
333
|
+
const waitPromises = agents.map(a =>
|
|
334
|
+
agent_control({ agentName: a.agentName, runner: a.runner, action: 'wait', timeoutMs: 300000 })
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const results = await Promise.all(waitPromises);
|
|
338
|
+
|
|
339
|
+
for (const [i, r] of results.entries()) {
|
|
340
|
+
console.log(`${agents[i].agentName}:`, r.isError ? 'FAILED' : 'OK');
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Pattern 5 : Resume après Crash OverMind
|
|
345
|
+
|
|
346
|
+
Quand OverMind restart, on peut se rattacher aux agents en cours via le registry :
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
// 1. Scanner tous les agents "running" dans le registry
|
|
350
|
+
const runningAgents = await getRunningProcesses();
|
|
351
|
+
|
|
352
|
+
// 2. Pour chaque agent encore vivant mais "orphaned"
|
|
353
|
+
for (const agent of runningAgents) {
|
|
354
|
+
const status = await agent_control({
|
|
355
|
+
agentName: agent.agentName,
|
|
356
|
+
runner: agent.runner,
|
|
357
|
+
action: 'status',
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
if (status.content[0].text.includes('orphaned')) {
|
|
361
|
+
console.log(`Orphaned agent detected: ${agent.agentName} (PID: ${agent.pid})`);
|
|
362
|
+
// Option: kill et relancer, ou laisser tel quel
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 5. Tracker PID ↔ Session ↔ Agent
|
|
370
|
+
|
|
371
|
+
Le registry dans `sessions.json` stocke la cartographie complète :
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"kilo:sniper_analyst": {
|
|
376
|
+
"id": "sess_abc123",
|
|
377
|
+
"ts": 1746892800000,
|
|
378
|
+
"pid": 12345,
|
|
379
|
+
"runner": "kilo",
|
|
380
|
+
"agentName": "sniper_analyst",
|
|
381
|
+
"status": "running",
|
|
382
|
+
"outputBuffer": "Thinking...\nFetching data...",
|
|
383
|
+
"exitCode": null,
|
|
384
|
+
"lastOutputAt": 1746892900000
|
|
385
|
+
},
|
|
386
|
+
"claude:reporter": {
|
|
387
|
+
"id": "sess_def456",
|
|
388
|
+
"ts": 1746892850000,
|
|
389
|
+
"pid": 67890,
|
|
390
|
+
"runner": "claude",
|
|
391
|
+
"agentName": "reporter",
|
|
392
|
+
"status": "done",
|
|
393
|
+
"outputBuffer": "Report generated successfully.",
|
|
394
|
+
"exitCode": 0,
|
|
395
|
+
"lastOutputAt": 1746893500000
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Trouver un Agent par Timestamp
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
// Trouver tous les agents活跃 après une date donnée
|
|
404
|
+
async function findAgentsAfter(timestampMs) {
|
|
405
|
+
const allAgents = await getProcessStatus('*'); // sans runner = tous
|
|
406
|
+
|
|
407
|
+
return allAgents
|
|
408
|
+
.filter(a => a.ts >= timestampMs)
|
|
409
|
+
.sort((a, b) => a.ts - b.ts); // plus récents d'abord
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Usage
|
|
413
|
+
const recent = await findAgentsAfter(Date.now() - 3600000); // dernière heure
|
|
414
|
+
console.log(recent.map(a => `${a.agentName} @ ${new Date(a.ts).toISOString()}`));
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Trouver un Agent par PID
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
// Via le registry scan
|
|
421
|
+
async function findAgentByPid(pid) {
|
|
422
|
+
const { store } = await readStore();
|
|
423
|
+
|
|
424
|
+
for (const [key, entry] of Object.entries(store)) {
|
|
425
|
+
if (typeof entry === 'object' && entry !== null && entry.pid === pid) {
|
|
426
|
+
return { key, ...entry };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Usage
|
|
433
|
+
const agent = await findAgentByPid(12345);
|
|
434
|
+
console.log(`Found: ${agent.agentName} (${agent.runner})`);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Trouver un Agent par Session ID
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
// Via le registry scan
|
|
441
|
+
async function findAgentBySession(sessionId) {
|
|
442
|
+
const { store } = await readStore();
|
|
443
|
+
|
|
444
|
+
for (const [key, entry] of Object.entries(store)) {
|
|
445
|
+
if (typeof entry === 'object' && entry !== null && entry.id === sessionId) {
|
|
446
|
+
return { key, ...entry };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Usage
|
|
453
|
+
const agent = await findAgentBySession('sess_abc123');
|
|
454
|
+
if (agent) {
|
|
455
|
+
console.log(`PID: ${agent.pid}, Status: ${agent.status}`);
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 6. Dashboard en Temps Réel
|
|
462
|
+
|
|
463
|
+
### Exemple Complet : Dashboard CLI
|
|
464
|
+
|
|
465
|
+
```javascript
|
|
466
|
+
import { getRunningProcesses } from './lib/processRegistry.js';
|
|
467
|
+
|
|
468
|
+
async function dashboard() {
|
|
469
|
+
console.clear();
|
|
470
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
471
|
+
console.log(' OVERMIND AGENT DASHBOARD');
|
|
472
|
+
console.log('═══════════════════════════════════════════════════════\n');
|
|
473
|
+
|
|
474
|
+
const running = await getRunningProcesses();
|
|
475
|
+
|
|
476
|
+
if (running.length === 0) {
|
|
477
|
+
console.log('Aucun agent en cours d\'exécution.\n');
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
console.log(`📊 ${running.length} agent(s) actifs\n`);
|
|
482
|
+
console.log('┌──────────────────┬────────┬─────────┬───────────────┬────────────────────────┐');
|
|
483
|
+
console.log('│ Agent │ Runner │ PID │ Status │ Started │');
|
|
484
|
+
console.log('├──────────────────┼────────┼─────────┼───────────────┼────────────────────────┤');
|
|
485
|
+
|
|
486
|
+
for (const agent of running) {
|
|
487
|
+
const elapsed = Date.now() - agent.ts;
|
|
488
|
+
const elapsedStr = elapsed < 60000
|
|
489
|
+
? `${Math.floor(elapsed / 1000)}s`
|
|
490
|
+
: `${Math.floor(elapsed / 60000)}m`;
|
|
491
|
+
|
|
492
|
+
const statusColor = agent.status === 'running' ? '🟢' : '⚠️';
|
|
493
|
+
console.log(
|
|
494
|
+
`│ ${agent.agentName.padEnd(16)} │ ${(agent.runner || '?').padEnd(6)} │ ${String(agent.pid || 'N/A').padStart(7)} │ ${statusColor} ${agent.status.padEnd(11)} │ ${new Date(agent.ts).toLocaleTimeString().padEnd(22)} │`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
console.log('└──────────────────┴────────┴─────────┴───────────────┴────────────────────────┘\n');
|
|
499
|
+
|
|
500
|
+
// Detail du premier agent
|
|
501
|
+
if (running[0]) {
|
|
502
|
+
const detail = await agent_control({
|
|
503
|
+
agentName: running[0].agentName,
|
|
504
|
+
runner: running[0].runner,
|
|
505
|
+
action: 'stream',
|
|
506
|
+
});
|
|
507
|
+
console.log('═══ OUTPUT RECENT ═══');
|
|
508
|
+
console.log(detail.content[0].text.slice(-500));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Rafraîchir toutes les 3 secondes
|
|
513
|
+
setInterval(dashboard, 3000);
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Exemple : Tableau de Bord HTML
|
|
517
|
+
|
|
518
|
+
```html
|
|
519
|
+
<!DOCTYPE html>
|
|
520
|
+
<html>
|
|
521
|
+
<head>
|
|
522
|
+
<title>OverMind Dashboard</title>
|
|
523
|
+
<meta http-equiv="refresh" content="5">
|
|
524
|
+
<style>
|
|
525
|
+
body { font-family: monospace; background: #0d1117; color: #e6edf3; padding: 20px; }
|
|
526
|
+
.agent { border: 1px solid #30363d; padding: 10px; margin: 10px 0; border-radius: 6px; }
|
|
527
|
+
.running { border-left: 4px solid #3fb950; }
|
|
528
|
+
.done { border-left: 4px solid #58a6ff; }
|
|
529
|
+
.failed { border-left: 4px solid #f85149; }
|
|
530
|
+
.orphaned { border-left: 4px solid #d29922; }
|
|
531
|
+
.pid { color: #8b949e; }
|
|
532
|
+
.output { background: #161b22; padding: 8px; margin-top: 8px; max-height: 100px; overflow: auto; }
|
|
533
|
+
</style>
|
|
534
|
+
</head>
|
|
535
|
+
<body>
|
|
536
|
+
<h1>🤖 OverMind Agent Dashboard</h1>
|
|
537
|
+
<div id="agents"></div>
|
|
538
|
+
|
|
539
|
+
<script>
|
|
540
|
+
async function refresh() {
|
|
541
|
+
// Appeler agent_control pour chaque agent running
|
|
542
|
+
const response = await fetch('/api/agents/running');
|
|
543
|
+
const agents = await response.json();
|
|
544
|
+
|
|
545
|
+
document.getElementById('agents').innerHTML = agents.map(agent => `
|
|
546
|
+
<div class="agent ${agent.status}">
|
|
547
|
+
<strong>${agent.agentName}</strong>
|
|
548
|
+
<span class="pid">(${agent.runner} | PID: ${agent.pid})</span>
|
|
549
|
+
<br>
|
|
550
|
+
Status: ${agent.status} | Started: ${new Date(agent.ts).toLocaleString()}
|
|
551
|
+
<br>
|
|
552
|
+
Elapsed: ${Math.floor((Date.now() - agent.ts) / 1000)}s
|
|
553
|
+
<div class="output">${escapeHtml(agent.outputBuffer || '(no output)').slice(-200)}</div>
|
|
554
|
+
</div>
|
|
555
|
+
`).join('');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function escapeHtml(text) {
|
|
559
|
+
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
refresh();
|
|
563
|
+
setInterval(refresh, 5000);
|
|
564
|
+
</script>
|
|
565
|
+
</body>
|
|
566
|
+
</html>
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## 7. Flux Complet de Debug
|
|
572
|
+
|
|
573
|
+
Quand un agent ne répond plus ou pose problème :
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
STEP 1: Identifier le problème
|
|
577
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
578
|
+
agent_control({ agentName: "sniper_analyst", action: "status" })
|
|
579
|
+
|
|
580
|
+
→ Si status: "running" + lastOutputAt ancien → agent peut-être bloqué
|
|
581
|
+
→ Si status: "orphaned" → parent mort, child tourne encore
|
|
582
|
+
→ Si status: "done" → agent déjà terminé, problem elsewhere
|
|
583
|
+
|
|
584
|
+
STEP 2: Voir l'output
|
|
585
|
+
━━━━━━━━━━━━━━━━━━━━━━
|
|
586
|
+
agent_control({ agentName: "sniper_analyst", action: "stream" })
|
|
587
|
+
|
|
588
|
+
→ Identifier la dernière ligne avant le blocage
|
|
589
|
+
→ Vérifier s'il y a des erreurs dans le buffer
|
|
590
|
+
|
|
591
|
+
STEP 3: Décider de l'action
|
|
592
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
593
|
+
|
|
594
|
+
┌─ still running, output OK → Attendre (action: "wait", timeoutMs: X)
|
|
595
|
+
│
|
|
596
|
+
├─ still running, BLOCKED → kill (action: "kill") → restart
|
|
597
|
+
│
|
|
598
|
+
├─ orphaned → kill (action: "kill") → restart
|
|
599
|
+
│
|
|
600
|
+
└─ done with error → Analyser output → fix prompt → restart
|
|
601
|
+
|
|
602
|
+
STEP 4: Nettoyer si nécessaire
|
|
603
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
604
|
+
Le registry fait le cleanup automatique après 1h (TTL).
|
|
605
|
+
Pour forcer le cleanup immédiat :
|
|
606
|
+
|
|
607
|
+
unregisterProcess(pid) → supprime l'entrée du registry
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## 8. Référence Rapide
|
|
613
|
+
|
|
614
|
+
```javascript
|
|
615
|
+
// Status simple
|
|
616
|
+
agent_control({ agentName: "...", action: "status" })
|
|
617
|
+
|
|
618
|
+
// Stream avec filtre timestamp
|
|
619
|
+
agent_control({ agentName: "...", action: "stream", sinceTimestamp: 1746892800000 })
|
|
620
|
+
|
|
621
|
+
// Kill
|
|
622
|
+
agent_control({ agentName: "...", action: "kill" })
|
|
623
|
+
|
|
624
|
+
// Wait avec timeout custom
|
|
625
|
+
agent_control({ agentName: "...", action: "wait", timeoutMs: 300000 })
|
|
626
|
+
|
|
627
|
+
// Avec runner explicite (recommendé)
|
|
628
|
+
agent_control({ agentName: "...", runner: "kilo", action: "..." })
|
|
629
|
+
|
|
630
|
+
// Avec config path (si plusieurs OverMind)
|
|
631
|
+
agent_control({ agentName: "...", config: "/path/to/overmind", action: "..." })
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Paramètres Communs
|
|
635
|
+
|
|
636
|
+
| Param | Type | Description |
|
|
637
|
+
|-------|------|-------------|
|
|
638
|
+
| `agentName` | string | Nom unique de l'agent |
|
|
639
|
+
| `runner` | enum | Type de runner (optionnel, déduit si omis) |
|
|
640
|
+
| `config` | string | Chemin racine Overmind (optionnel) |
|
|
641
|
+
|
|
642
|
+
### Actions
|
|
643
|
+
|
|
644
|
+
| Action | Description | Retourne |
|
|
645
|
+
|--------|-------------|----------|
|
|
646
|
+
| `status` | État courant | pid, status, sessionId, outputBuffer |
|
|
647
|
+
| `stream` | Output + complétude | output, isComplete |
|
|
648
|
+
| `kill` | Arrêt forcé | confirmation ou erreur |
|
|
649
|
+
| `wait` | Attente terminaison | output final ou timeout |
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
**Fichier source** : `src/tools/agent_control.ts`
|
|
654
|
+
**Registry** : `src/lib/processRegistry.ts`
|
|
655
|
+
**Store** : `.claude/sessions.json`
|
|
656
|
+
**TTL** : 1h après terminaison (cleanup automatique)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overmind-mcp",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"preferGlobal": true,
|
|
5
5
|
"description": "Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour QwenCli et Nous Hermes. Installation automatique des dépendances Docker (PostgreSQL, pgvector) inclus.",
|
|
6
6
|
"type": "module",
|
|
@@ -83,7 +83,6 @@
|
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@changesets/cli": "^2.31.0",
|
|
85
85
|
"@eslint/js": "^9.39.4",
|
|
86
|
-
"@types/amqplib": "^0.10.8",
|
|
87
86
|
"@types/node": "^22.19.17",
|
|
88
87
|
"@types/pg": "^8.20.0",
|
|
89
88
|
"@types/pino": "^7.0.5",
|
|
@@ -97,16 +96,6 @@
|
|
|
97
96
|
"vitest": "^4.1.4"
|
|
98
97
|
},
|
|
99
98
|
"dependencies": {
|
|
100
|
-
"@opentelemetry/api": "^1.9.1",
|
|
101
|
-
"@opentelemetry/auto-instrumentations-node": "^0.75.0",
|
|
102
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.217.0",
|
|
103
|
-
"@opentelemetry/resources": "^2.7.1",
|
|
104
|
-
"@opentelemetry/sdk-node": "^0.217.0",
|
|
105
|
-
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
106
|
-
"@temporalio/activity": "^1.17.1",
|
|
107
|
-
"@temporalio/client": "^1.17.1",
|
|
108
|
-
"@temporalio/worker": "^1.17.1",
|
|
109
|
-
"@temporalio/workflow": "^1.17.1",
|
|
110
99
|
"async-mutex": "^0.5.0",
|
|
111
100
|
"dotenv": "^17.4.2",
|
|
112
101
|
"fastmcp": "^3.35.0",
|
package/scripts/auto-install.mjs
CHANGED
|
@@ -191,11 +191,6 @@ async function validateServices() {
|
|
|
191
191
|
|
|
192
192
|
const services = [
|
|
193
193
|
{ name: 'PostgreSQL', filter: 'overmind-postgres-pgvector', check: 'pg_isready' },
|
|
194
|
-
{ name: 'RabbitMQ', filter: 'overmind-rabbitmq', check: null },
|
|
195
|
-
{ name: 'Temporal', filter: 'overmind-temporal', check: null },
|
|
196
|
-
{ name: 'Prometheus', filter: 'overmind-prometheus', check: null },
|
|
197
|
-
{ name: 'Grafana', filter: 'overmind-grafana', check: null },
|
|
198
|
-
{ name: 'Jaeger', filter: 'overmind-jaeger', check: null },
|
|
199
194
|
];
|
|
200
195
|
|
|
201
196
|
let allRunning = true;
|