overmind-mcp 3.5.2 → 3.6.1
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/bridge/BridgeProxy.d.ts +4 -2
- package/dist/bridge/BridgeProxy.d.ts.map +1 -1
- package/dist/bridge/BridgeProxy.js +31 -13
- package/dist/bridge/BridgeProxy.js.map +1 -1
- package/dist/bridge/types.d.ts +1 -1
- package/dist/bridge/types.d.ts.map +1 -1
- package/dist/bridge/types.js +4 -2
- package/dist/bridge/types.js.map +1 -1
- package/docs/overmind-bridge-guide.md +665 -0
- package/package.json +1 -1
- package/docs/SOUL_pdf_bon_travail_v2.md +0 -132
- package/docs/agent-http-tutorial.md +0 -524
- package/docs/doc_guide_agent_hermes_permanent.md +0 -315
- package/docs/guide_agent_hermes_overmind.md +0 -403
- package/docs/overmind-bridge-persistent-agents.md +0 -892
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
# 🌉 Overmind Bridge — Agents Persistants & A2A (Guide Unifié)
|
|
2
|
+
|
|
3
|
+
> **Version**: Overmind v3.5.2 — Pattern générique, 2 à 100 agents
|
|
4
|
+
> **Date**: 2026-07-10
|
|
5
|
+
> **Statut**: Remplace `overmind-bridge-persistent-agents.md`, `overmind-bridge-commands-reference.md`, `doc_guide_agent_hermes_permanent.md`, `guide_agent_hermes_overmind.md`, `agent-http-tutorial.md`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Concepts
|
|
10
|
+
|
|
11
|
+
### Qu'est-ce qu'un agent persistant ?
|
|
12
|
+
|
|
13
|
+
Un agent persistant = **un process `overmind-bridge` autonome** qui :
|
|
14
|
+
- Écoute sur son propre port HTTP
|
|
15
|
+
- A son propre agent Hermes dédié (profil)
|
|
16
|
+
- Garde sa session entre les appels (mémoire conversationnelle)
|
|
17
|
+
- Communique avec les autres agents via HTTP A2A (peer-to-peer)
|
|
18
|
+
- Forward les appels LLM vers le MCP Overmind → Hermes Gateway
|
|
19
|
+
|
|
20
|
+
### Pourquoi des bridges isolés ?
|
|
21
|
+
|
|
22
|
+
| Sans bridge | Avec bridge isolé |
|
|
23
|
+
|-------------|-------------------|
|
|
24
|
+
| `spawn('hermes', ['-p', agent])` à chaque call | Process persistant, session conservée |
|
|
25
|
+
| 5-10s startup Python par call | <500ms (HTTP direct au Gateway) |
|
|
26
|
+
| Pas de communication inter-agent | A2A HTTP peer-to-peer |
|
|
27
|
+
| Crash d'un agent = crash global | Crash d'un agent ≠ impact sur les autres |
|
|
28
|
+
| Pas de monitoring par agent | `GET /health` par agent |
|
|
29
|
+
|
|
30
|
+
### L'échelle : 2 à 100 agents
|
|
31
|
+
|
|
32
|
+
Le pattern est **identique** que tu aies 2 ou 100 agents. Chaque agent = :
|
|
33
|
+
- 1 profil Hermes (`~/.hermes/profiles/<name>/`)
|
|
34
|
+
- 1 process bridge (`node dist/bridges/<name>/src/bridge.js`)
|
|
35
|
+
- 1 port dédié (séquence : 3101, 3102, ..., 31XX)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Architecture
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
43
|
+
│ N BRIDGES ISOLÉS — PEER-TO-PEER │
|
|
44
|
+
│ │
|
|
45
|
+
│ :3101 agent_alpha → RPC locaux + A2A vers peers │
|
|
46
|
+
│ :3102 agent_beta → RPC locaux + A2A vers peers │
|
|
47
|
+
│ :3103 agent_gamma → RPC locaux + A2A vers peers │
|
|
48
|
+
│ ... │
|
|
49
|
+
│ :31XX agent_omega → RPC locaux + A2A vers peers │
|
|
50
|
+
│ │
|
|
51
|
+
│ A2A = HTTP POST inter-bridges (JSON-RPC 2.0) │
|
|
52
|
+
│ Chaque bridge a ses propres clients vers les autres │
|
|
53
|
+
│ │
|
|
54
|
+
│ SERVICES PARTAGÉS (single instance): │
|
|
55
|
+
│ :3099 Overmind MCP Server (routing run_agent, memory, ...) │
|
|
56
|
+
│ :8642 Hermes Gateway API (X-Hermes-Profile routing) │
|
|
57
|
+
│ :5432 PostgreSQL (MessageLog + pgvector Memory) │
|
|
58
|
+
└──────────────────────────────────────────────────────────────┘
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Ce que ce n'est PAS
|
|
62
|
+
|
|
63
|
+
- ❌ Un seul `OverBridgeServer` partagé qui dispatche vers N agents
|
|
64
|
+
- ❌ Un bridge "central" qui connaît tous les agents
|
|
65
|
+
- ❌ N instances Hermes Gateway (1 seule suffit, le header `X-Hermes-Profile` route)
|
|
66
|
+
|
|
67
|
+
### Services partagés (NE PAS dupliquer)
|
|
68
|
+
|
|
69
|
+
| Service | Port | URL | Rôle |
|
|
70
|
+
|---------|------|-----|------|
|
|
71
|
+
| **Overmind MCP** | :3099 | `http://[::1]:3099/mcp` | 14 tools : run_agent, a2a_hub, agent_control, memory_*, create_agent |
|
|
72
|
+
| **Hermes Gateway** | :8642 | `http://127.0.0.1:8642` | API Server HTTP+SSE, OpenAI-compatible, profile routing |
|
|
73
|
+
| **PostgreSQL** | :5432 | `localhost` | MessageLog (`bridge_messages`) + Memory (pgvector) |
|
|
74
|
+
|
|
75
|
+
### Allocation des ports
|
|
76
|
+
|
|
77
|
+
Les ports suivent une séquence simple : **3101 + offset**.
|
|
78
|
+
|
|
79
|
+
| Agent # | Port | Exemple nom |
|
|
80
|
+
|---------|------|-------------|
|
|
81
|
+
| #1 | 3101 | `agent_alpha` |
|
|
82
|
+
| #2 | 3102 | `agent_beta` |
|
|
83
|
+
| #3 | 3103 | `agent_gamma` |
|
|
84
|
+
| ... | ... | ... |
|
|
85
|
+
| #N | 3100+N | `agent_<name>` |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 3. Créer un Agent Persistant
|
|
90
|
+
|
|
91
|
+
### Étape 1 : Créer le profil Hermes
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
# Via MCP tool (recommandé)
|
|
95
|
+
create_agent(
|
|
96
|
+
name: "agent_alpha",
|
|
97
|
+
runner: "hermes",
|
|
98
|
+
prompt: "Tu es l'agent Alpha. Tes missions: ...",
|
|
99
|
+
model: "glm-5.2"
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Ou via CLI :
|
|
104
|
+
```bash
|
|
105
|
+
hermes profile create agent_alpha --no-alias --description "Agent Alpha"
|
|
106
|
+
hermes -p agent_alpha config set model.provider z-ai
|
|
107
|
+
hermes -p agent_alpha config set model.model glm-5.2
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Structure créée sur disque
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
~/.hermes/profiles/agent_alpha/
|
|
114
|
+
├── config.yaml # provider, model, mcp_servers
|
|
115
|
+
├── .env # clés API (GLM_API_KEY, MINIMAX_CN_API_KEY, ...)
|
|
116
|
+
├── SOUL.md # system prompt + instructions mémoire
|
|
117
|
+
├── profile.yaml # metadata kanban routing
|
|
118
|
+
├── workspace.yaml # kind: persistent, gc_eligible: false
|
|
119
|
+
├── memories/ # state.db (mémoire SQLite isolée)
|
|
120
|
+
├── sessions/ # historique conversations
|
|
121
|
+
└── skills/ # mémoire procédurale
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Auto-détection du provider
|
|
125
|
+
|
|
126
|
+
| Modèle contient | Provider | Clé API |
|
|
127
|
+
|-----------------|----------|---------|
|
|
128
|
+
| `minimax`, `m3` | `minimax-cn` | `MINIMAX_CN_API_KEY` |
|
|
129
|
+
| `glm`, `zai` | `z-ai` | `GLM_API_KEY` |
|
|
130
|
+
| `claude`, `sonnet` | `anthropic` | `ANTHROPIC_API_KEY` |
|
|
131
|
+
| `gpt` | `openai` | `OPENAI_API_KEY` |
|
|
132
|
+
| `deepseek` | `deepseek` | `DEEPSEEK_API_KEY` |
|
|
133
|
+
| *(autre)* | `openrouter` | `OPENROUTER_API_KEY` |
|
|
134
|
+
|
|
135
|
+
### Étape 2 : Créer le bridge
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Créer la structure
|
|
139
|
+
mkdir -p bridges/agent_alpha/{src/clients,logs}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**`bridges/agent_alpha/.env`** :
|
|
143
|
+
```bash
|
|
144
|
+
AGENT_NAME=agent_alpha
|
|
145
|
+
RUNNER=hermes
|
|
146
|
+
BRIDGE_PORT=3101
|
|
147
|
+
BRIDGE_HOST=127.0.0.1
|
|
148
|
+
MCP_URL=http://[::1]:3099/mcp
|
|
149
|
+
HERMES_GATEWAY_URL=http://127.0.0.1:8642
|
|
150
|
+
HERMES_GATEWAY_KEY=<key>
|
|
151
|
+
SESSION_TTL_MS=14400000
|
|
152
|
+
MESSAGE_LOG_ENABLED=true
|
|
153
|
+
MCP_TIMEOUT_MS=120000
|
|
154
|
+
|
|
155
|
+
# Peers (autres bridges — vide si seul, ou liste tous les autres)
|
|
156
|
+
PEER_BETA_URL=http://127.0.0.1:3102
|
|
157
|
+
PEER_GAMMA_URL=http://127.0.0.1:3103
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**`bridges/agent_alpha/src/config.ts`** :
|
|
161
|
+
```typescript
|
|
162
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
163
|
+
import { resolve, dirname } from 'node:path';
|
|
164
|
+
import { fileURLToPath } from 'node:url';
|
|
165
|
+
import type { PeerMap } from '../../../common/src/types.js';
|
|
166
|
+
|
|
167
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
168
|
+
|
|
169
|
+
function loadEnv(): Record<string, string> {
|
|
170
|
+
const candidatePaths = [
|
|
171
|
+
resolve(__dirname, '..', '.env'),
|
|
172
|
+
resolve(__dirname, '..', '..', '..', '.env'),
|
|
173
|
+
];
|
|
174
|
+
for (const p of candidatePaths) {
|
|
175
|
+
if (existsSync(p)) return parseEnv(readFileSync(p, 'utf-8'));
|
|
176
|
+
}
|
|
177
|
+
throw new Error(`Missing .env. Looked in:\n ${candidatePaths.join('\n ')}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function parseEnv(raw: string): Record<string, string> {
|
|
181
|
+
const env: Record<string, string> = {};
|
|
182
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
183
|
+
const t = line.trim();
|
|
184
|
+
if (!t || t.startsWith('#')) continue;
|
|
185
|
+
const idx = t.indexOf('=');
|
|
186
|
+
if (idx === -1) continue;
|
|
187
|
+
env[t.slice(0, idx).trim()] = t.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
|
|
188
|
+
}
|
|
189
|
+
return env;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const env = loadEnv();
|
|
193
|
+
|
|
194
|
+
export const config = {
|
|
195
|
+
agentName: env.AGENT_NAME ?? 'agent_alpha',
|
|
196
|
+
runner: env.RUNNER ?? 'hermes',
|
|
197
|
+
port: parseInt(env.BRIDGE_PORT ?? '3101', 10),
|
|
198
|
+
host: env.BRIDGE_HOST ?? '127.0.0.1',
|
|
199
|
+
mcpUrl: env.MCP_URL ?? 'http://[::1]:3099/mcp',
|
|
200
|
+
hermesGatewayUrl: env.HERMES_GATEWAY_URL ?? 'http://127.0.0.1:8642',
|
|
201
|
+
gatewayKey: env.HERMES_GATEWAY_KEY ?? '',
|
|
202
|
+
peers: {
|
|
203
|
+
beta: env.PEER_BETA_URL,
|
|
204
|
+
gamma: env.PEER_GAMMA_URL,
|
|
205
|
+
// ... ajouter autant de peers que nécessaire
|
|
206
|
+
} as PeerMap,
|
|
207
|
+
sessionTtlMs: parseInt(env.SESSION_TTL_MS ?? '14400000', 10),
|
|
208
|
+
messageLogEnabled: env.MESSAGE_LOG_ENABLED === 'true',
|
|
209
|
+
mcpTimeoutMs: parseInt(env.MCP_TIMEOUT_MS ?? '120000', 10),
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**`bridges/agent_alpha/src/bridge.ts`** :
|
|
214
|
+
```typescript
|
|
215
|
+
import { BaseBridge } from '../../../common/src/BaseBridge.js';
|
|
216
|
+
import { Logger } from '../../../common/src/logger.js';
|
|
217
|
+
import { config } from './config.js';
|
|
218
|
+
|
|
219
|
+
const logger = new Logger(config.agentName);
|
|
220
|
+
|
|
221
|
+
class AgentAlphaBridge extends BaseBridge {
|
|
222
|
+
constructor() {
|
|
223
|
+
super({
|
|
224
|
+
agentName: config.agentName,
|
|
225
|
+
port: config.port,
|
|
226
|
+
host: config.host,
|
|
227
|
+
mcpUrl: config.mcpUrl,
|
|
228
|
+
gatewayUrl: config.hermesGatewayUrl,
|
|
229
|
+
peers: config.peers,
|
|
230
|
+
mcpTimeoutMs: config.mcpTimeoutMs,
|
|
231
|
+
sessionTtlMs: config.sessionTtlMs,
|
|
232
|
+
messageLogEnabled: config.messageLogEnabled,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Enregistrer les méthodes RPC locales spécifiques à cet agent
|
|
236
|
+
this.registerRpcMethod('alpha.execute', async (params) => {
|
|
237
|
+
logger.info('Execute requested', params);
|
|
238
|
+
return { status: 'done', ts: Date.now() };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const bridge = new AgentAlphaBridge();
|
|
244
|
+
bridge.start().catch((err) => {
|
|
245
|
+
logger.error('Failed to start', { error: (err as Error).message });
|
|
246
|
+
process.exit(1);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const shutdown = async (signal: string) => {
|
|
250
|
+
logger.info(`Received ${signal} — shutting down`);
|
|
251
|
+
await bridge.stop();
|
|
252
|
+
process.exit(0);
|
|
253
|
+
};
|
|
254
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
255
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Étape 3 : Build et démarrage
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Build (depuis la racine du projet)
|
|
262
|
+
npm run build
|
|
263
|
+
|
|
264
|
+
# Démarrer ce bridge
|
|
265
|
+
node dist/bridges/agent_alpha/src/bridge.js
|
|
266
|
+
|
|
267
|
+
# Vérifier
|
|
268
|
+
curl http://127.0.0.1:3101/health
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 4. Module Common (partagé entre tous les bridges)
|
|
274
|
+
|
|
275
|
+
### `common/src/BaseBridge.ts`
|
|
276
|
+
|
|
277
|
+
Classe abstraite — chaque bridge l'étend. Fournit :
|
|
278
|
+
- Serveur HTTP (`POST /rpc`, `GET /health`, `POST /shutdown`)
|
|
279
|
+
- `registerRpcMethod(name, handler)` — méthodes RPC locales
|
|
280
|
+
- `forwardToMcp(request)` — forward vers MCP Overmind (`:3099/mcp`)
|
|
281
|
+
- SSE parsing (FastMCP répond en Server-Sent Events)
|
|
282
|
+
- Keep-alive HTTP agent (perf: connection reuse)
|
|
283
|
+
- Graceful shutdown (SIGINT/SIGTERM)
|
|
284
|
+
|
|
285
|
+
**Routage RPC interne** :
|
|
286
|
+
```
|
|
287
|
+
POST /rpc → dispatchRpc(method)
|
|
288
|
+
1. health.ping → local (toujours)
|
|
289
|
+
2. Méthode locale (registerRpcMethod) → handler local
|
|
290
|
+
3. Sinon → forwardToMcp() → POST http://[::1]:3099/mcp
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `common/src/BridgeClient.ts`
|
|
294
|
+
|
|
295
|
+
Client HTTP pour appels inter-bridges (A2A). Fournit :
|
|
296
|
+
- `call(method, params)` — JSON-RPC 2.0 avec retry + backoff
|
|
297
|
+
- `healthCheck()` — GET /health sur un peer
|
|
298
|
+
- `sendToAgent(agentName, prompt)` — wrapper `agent.run`
|
|
299
|
+
- UUID uniques (pas de collision)
|
|
300
|
+
- Keep-alive agent partagé
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const client = new BridgeClient('http://127.0.0.1:3102');
|
|
304
|
+
const result = await client.call('beta.analyze', { symbol: 'BTC' });
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### `common/src/types.ts`
|
|
308
|
+
|
|
309
|
+
Interfaces partagées : `BridgeConfig`, `PeerMap`, `HealthStatus`, `JsonRpcRequest/Response`, `RunnerType`.
|
|
310
|
+
|
|
311
|
+
### `common/src/logger.ts`
|
|
312
|
+
|
|
313
|
+
Logger zero-dep : console colorisée + fichier async (non bloquant), rotation 50MB, safe stringify (circular refs).
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## 5. Commandes RPC (par bridge)
|
|
318
|
+
|
|
319
|
+
### Format de requête
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
curl -X POST http://127.0.0.1:<PORT>/rpc \
|
|
323
|
+
-H "Content-Type: application/json" \
|
|
324
|
+
-d '{"jsonrpc":"2.0","id":"<id>","method":"<method>","params":{...}}'
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Endpoints communs (tous les bridges)
|
|
328
|
+
|
|
329
|
+
| Endpoint | HTTP | Description |
|
|
330
|
+
|----------|------|-------------|
|
|
331
|
+
| `GET /health` | GET | `{ agent, status, uptime, rpcMethods[], peerCount }` |
|
|
332
|
+
| `POST /rpc` | POST | JSON-RPC 2.0 dispatcher |
|
|
333
|
+
| `POST /shutdown` | POST | Arrêt propre |
|
|
334
|
+
|
|
335
|
+
### Méthodes RPC standards (tous les bridges)
|
|
336
|
+
|
|
337
|
+
| Méthode | Params | Description |
|
|
338
|
+
|---------|--------|-------------|
|
|
339
|
+
| `health.ping` | — | Ping local (toujours OK) |
|
|
340
|
+
|
|
341
|
+
### Méthodes RPC customs (spécifiques par agent)
|
|
342
|
+
|
|
343
|
+
Chaque agent enregistre ses propres méthodes via `registerRpcMethod()`. Exemple avec NEXUS :
|
|
344
|
+
|
|
345
|
+
#### Exemple : nexus_master (orchestrateur)
|
|
346
|
+
|
|
347
|
+
| Méthode | Params | Description |
|
|
348
|
+
|---------|--------|-------------|
|
|
349
|
+
| `master.status` | — | Agrège la santé de tous les peers |
|
|
350
|
+
| `master.broadcast` | `{ message }` | Fan-out à tous les peers |
|
|
351
|
+
| `master.pipeline` | `{ steps: [{ peer, prompt }] }` | Chaîne A→B→C |
|
|
352
|
+
| `master.fanout` | `{ peers[], prompt, merge? }` | Parallèle N + merge |
|
|
353
|
+
|
|
354
|
+
#### Exemple : nexus_trader
|
|
355
|
+
|
|
356
|
+
| Méthode | Params | Description |
|
|
357
|
+
|---------|--------|-------------|
|
|
358
|
+
| `trade.request` | `{ symbol, side, quantity }` | Valide via risk, notifie publisher |
|
|
359
|
+
| `trade.analysis` | `{ symbol, timeframe? }` | Délègue au researcher |
|
|
360
|
+
|
|
361
|
+
#### Exemple : nexus_risk_manager
|
|
362
|
+
|
|
363
|
+
| Méthode | Params | Description |
|
|
364
|
+
|---------|--------|-------------|
|
|
365
|
+
| `risk.validate` | `{ symbol, side, quantity }` | Valide un trade |
|
|
366
|
+
| `risk.drawdown` | — | Check drawdown |
|
|
367
|
+
| `risk.feedback` | `{ message, type }` | Feedback au trader |
|
|
368
|
+
|
|
369
|
+
#### Pattern pour créer tes propres méthodes
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// Dans ton bridge.ts
|
|
373
|
+
this.registerRpcMethod('myagent.dosomething', async (params) => {
|
|
374
|
+
const p = params as { input: string };
|
|
375
|
+
// Logique métier ici
|
|
376
|
+
return { result: 'done', ts: Date.now() };
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## 6. A2A — Communication Inter-Bridges
|
|
383
|
+
|
|
384
|
+
### A2A direct (bridge → bridge)
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
// Dans un bridge, appeler un autre bridge
|
|
388
|
+
import { BridgeClient } from '../../../common/src/BridgeClient.js';
|
|
389
|
+
|
|
390
|
+
const peerClient = new BridgeClient('http://127.0.0.1:3102');
|
|
391
|
+
const result = await peerClient.call('trade.request', {
|
|
392
|
+
symbol: 'BTC', side: 'BUY', quantity: 0.1,
|
|
393
|
+
});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### A2A via MCP Hub (tool `a2a_hub`)
|
|
397
|
+
|
|
398
|
+
Le MCP Overmind expose le tool `a2a_hub` avec 8 actions :
|
|
399
|
+
|
|
400
|
+
| Action | Params | Description |
|
|
401
|
+
|--------|--------|-------------|
|
|
402
|
+
| `discover` | — | Liste tous les agents + statut |
|
|
403
|
+
| `status` | `target` | État détaillé d'un agent |
|
|
404
|
+
| `send` | `target, message` | Message synchrone A→B |
|
|
405
|
+
| `delegate` | `target, message, callbackUrl?` | Async (retourne taskId) |
|
|
406
|
+
| `pipeline` | `message, steps[]` | Chaîne A→B→C |
|
|
407
|
+
| `fanout` | `targets[], message, mergeStrategy?` | 1→N + merge |
|
|
408
|
+
| `query` | `targets[], message` | Question multi-agents |
|
|
409
|
+
| `broadcast` | `message, race?` | Global à tous |
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
a2a_hub(action="send", target="nexus_trader", message="Analyse BTC")
|
|
413
|
+
a2a_hub(action="fanout", targets=["agent_a","agent_b"], message="BTC?", mergeStrategy="best")
|
|
414
|
+
a2a_hub(action="pipeline", message="Analyse", steps=[{"agentName":"researcher"},{"agentName":"trader"}])
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### A2A via OverBridgeServer (JSON-RPC 24 méthodes)
|
|
418
|
+
|
|
419
|
+
Le `OverBridgeServer` expose des méthodes A2A avancées avec persistence Postgres :
|
|
420
|
+
|
|
421
|
+
| Méthode | Description |
|
|
422
|
+
|---------|-------------|
|
|
423
|
+
| `agent.run` | Lance un agent (avec SessionStore multi-tenant) |
|
|
424
|
+
| `agent.a2a` | A→B avec header A2A standardisé |
|
|
425
|
+
| `agent.broadcast` | 1→N (race ou attend tous) |
|
|
426
|
+
| `agent.pipeline` | Chaîne A→B→C (accumulateContext?) |
|
|
427
|
+
| `agent.fanout` | 1→N + merge (concat/best/vote/first_success) |
|
|
428
|
+
| `agent.delegate` | Fire-and-forget + callback URL |
|
|
429
|
+
| `agent.query` | Multi-agent read-only rapide |
|
|
430
|
+
| `agent.status` | Status live (busy/idle/online) |
|
|
431
|
+
| `agent.list` | Liste filtrée |
|
|
432
|
+
| `agent.kill` | Kill un agent |
|
|
433
|
+
| `message.history` | Historique paginé (Postgres) |
|
|
434
|
+
| `message.get` | Récupère un message par UUID |
|
|
435
|
+
| `message.replay` | Rejoue un message |
|
|
436
|
+
| `message.stats` | Stats globales |
|
|
437
|
+
| `session.get` | Session par externalKey + agentName |
|
|
438
|
+
| `session.list` | Toutes les sessions |
|
|
439
|
+
| `session.delete` | Supprime une session |
|
|
440
|
+
| `session.stats` | Stats sessions |
|
|
441
|
+
| `webhook.sms` | Adapt + auto-dispatch SMS |
|
|
442
|
+
| `health.ping` | Liveness |
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## 7. Lancer un Agent
|
|
447
|
+
|
|
448
|
+
### Via Gateway HTTP (recommandé — zero subprocess)
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
run_agent(runner: "hermes", agentName: "agent_alpha", prompt: "Analyse le marché")
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Sous le capot : `HermesGatewayRunner` → `POST :8642/v1/chat/completions` avec `X-Hermes-Profile: agent_alpha` + SSE streaming. Pas de spawn CLI.
|
|
455
|
+
|
|
456
|
+
### Via curl direct sur le Gateway
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
curl -X POST http://127.0.0.1:8642/v1/chat/completions \
|
|
460
|
+
-H "Content-Type: application/json" \
|
|
461
|
+
-H "Authorization: Bearer ${API_SERVER_KEY}" \
|
|
462
|
+
-H "X-Hermes-Profile: agent_alpha" \
|
|
463
|
+
-d '{"model":"glm-5.2","messages":[{"role":"user","content":"Analyse le BTC"}],"stream":true}'
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Via bridge RPC
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
curl -X POST http://127.0.0.1:3101/rpc \
|
|
470
|
+
-H "Content-Type: application/json" \
|
|
471
|
+
-d '{"jsonrpc":"2.0","id":"1","method":"agent.run","params":{"agentName":"agent_alpha","runner":"hermes","prompt":"Analyse le BTC"}}'
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Via Hermes CLI
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
hermes -p agent_alpha chat -q "Analyse le BTC" -Q --yolo
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## 8. Gestion du Cycle de Vie
|
|
483
|
+
|
|
484
|
+
### Profils Hermes
|
|
485
|
+
|
|
486
|
+
| Action | Commande |
|
|
487
|
+
|--------|----------|
|
|
488
|
+
| Lister | `hermes profile list` |
|
|
489
|
+
| Voir | `hermes profile show agent_alpha` |
|
|
490
|
+
| Supprimer | `hermes profile delete agent_alpha --yes` |
|
|
491
|
+
| Changer modèle | `hermes -p agent_alpha config set model.model "MiniMax-M3"` |
|
|
492
|
+
| Update via Overmind | `update_agent_config(name: "agent_alpha", model: "new-model")` |
|
|
493
|
+
|
|
494
|
+
### Runtime
|
|
495
|
+
|
|
496
|
+
| Action | Commande |
|
|
497
|
+
|--------|----------|
|
|
498
|
+
| Status | `agent_control(agentName: "agent_alpha", action: "status")` |
|
|
499
|
+
| Stream output | `agent_control(agentName: "agent_alpha", action: "stream")` |
|
|
500
|
+
| Kill | `agent_control(agentName: "agent_alpha", action: "kill")` |
|
|
501
|
+
| Health bridge | `curl http://127.0.0.1:3101/health` |
|
|
502
|
+
| Shutdown bridge | `curl -X POST http://127.0.0.1:3101/shutdown` |
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## 9. Scripts Helper
|
|
507
|
+
|
|
508
|
+
### Démarrage N bridges
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
# Start all (NEXUS example with 6)
|
|
512
|
+
node scripts/start-all-bridges.cjs
|
|
513
|
+
|
|
514
|
+
# Stop all
|
|
515
|
+
node scripts/stop-all-bridges.cjs
|
|
516
|
+
|
|
517
|
+
# Status
|
|
518
|
+
node scripts/status-bridges.cjs
|
|
519
|
+
|
|
520
|
+
# Test A2A network
|
|
521
|
+
node scripts/test-a2a.cjs
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Seed (créer la structure pour N agents)
|
|
525
|
+
|
|
526
|
+
```bash
|
|
527
|
+
node scripts/seed-bridges.cjs
|
|
528
|
+
# Crée bridges/<name>/{src/clients,logs} + .env pour chaque agent
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Build
|
|
532
|
+
|
|
533
|
+
```bash
|
|
534
|
+
# Build complet (tsc + postbuild copie .env et config)
|
|
535
|
+
npm run build
|
|
536
|
+
|
|
537
|
+
# Le postbuild copie automatiquement:
|
|
538
|
+
# config/*.json → dist/config/
|
|
539
|
+
# bridges/*/.env → dist/bridges/*/.env
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Activation Hermes Gateway
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# Dans config.yaml
|
|
546
|
+
gateway:
|
|
547
|
+
platforms:
|
|
548
|
+
api_server:
|
|
549
|
+
enabled: true
|
|
550
|
+
|
|
551
|
+
# Dans .env
|
|
552
|
+
API_SERVER_KEY=<key>
|
|
553
|
+
API_SERVER_ENABLED=1
|
|
554
|
+
|
|
555
|
+
# Redémarrer
|
|
556
|
+
hermes gateway restart
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## 10. Ce que l'Agent Hérite Automatiquement
|
|
562
|
+
|
|
563
|
+
| Héritage | Source |
|
|
564
|
+
|----------|--------|
|
|
565
|
+
| **Mémoire isolée** | `state.db` SQLite dans `memories/` — `OVERMIND_AGENT_NAME` injecté |
|
|
566
|
+
| **Instructions mémoire** | Bloc "## Mémoire Overmind" injecté dans `SOUL.md` |
|
|
567
|
+
| **MCP servers** | `memory` (3 tools: search/store/runs) par défaut |
|
|
568
|
+
| **Clés API** | Toutes les clés du `.env` parent forwardées (GLM, MiniMax, OpenAI, ...) |
|
|
569
|
+
| **Sessions persistantes** | `sessions/` garde l'historique, `workspace.yaml: persistent` |
|
|
570
|
+
| **Kanban routing** | `profile.yaml` pour découverte par `a2a_hub` |
|
|
571
|
+
| **Gateway HTTP** | `HermesGatewayRunner` → `POST :8642` avec `X-Hermes-Profile` |
|
|
572
|
+
| **Circuit breaker** | `BridgeProxy` : 5 failures → open, 30s → half-open, 3 success → closed |
|
|
573
|
+
| **Retry automatique** | `ETIMEDOUT`, `EBODYREAD`, `ECONNRESET` → retry avec backoff |
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## 11. Bugs Source Corrigés (2026-07-10)
|
|
578
|
+
|
|
579
|
+
### Overmind (`Workflow/src/bridge/`)
|
|
580
|
+
|
|
581
|
+
| Bug | Fichier | Fix |
|
|
582
|
+
|-----|---------|-----|
|
|
583
|
+
| `localhost` au lieu de `[::1]` (IPv4/IPv6 mismatch) | `types.ts` | → `http://[::1]:3099/mcp` |
|
|
584
|
+
| `ping()` sans SSE Accept (FastMCP rejette) | `BridgeProxy.ts` | → `Accept: text/event-stream` + fallback `GET /health` |
|
|
585
|
+
| `parseSseText` non importé | `BridgeProxy.ts` | → Import ajouté |
|
|
586
|
+
|
|
587
|
+
### NEXUS (`Nexus/common/` + `bridges/`)
|
|
588
|
+
|
|
589
|
+
| Bug | Fichier | Fix |
|
|
590
|
+
|-----|---------|-----|
|
|
591
|
+
| MCP URL `/rpc` au lieu de `/mcp` (404) | `BaseBridge.ts` | → `/mcp` + SSE parsing |
|
|
592
|
+
| Timeout MCP hardcodé 60s | `BaseBridge.ts` | → `config.mcpTimeoutMs` (120s) |
|
|
593
|
+
| `Date.now()` ID collision | `BridgeClient.ts` | → `crypto.randomUUID()` |
|
|
594
|
+
| `appendFileSync` (sync I/O) | `logger.ts` | → `appendFile` async + rotation 50MB |
|
|
595
|
+
| RPC custom forwardée au MCP (404) | `BaseBridge.ts` | → `registerRpcMethod()` dispatch local |
|
|
596
|
+
| `.env` introuvable après build | `config.ts` | → `candidatePaths[]` multi-niveaux |
|
|
597
|
+
| `postbuild` ne copiait pas `.env` | `postbuild.cjs` | → Section 2: copy bridges/.env |
|
|
598
|
+
| `*/` dans JSDoc cassait CJS | `postbuild.cjs` | → Comment reworded |
|
|
599
|
+
| Pas de graceful shutdown | `bridge.ts` ×N | → `process.on('SIGINT'/'SIGTERM')` |
|
|
600
|
+
| Pas de keep-alive HTTP | `BridgeClient.ts` | → `HttpAgent({ keepAlive: true })` |
|
|
601
|
+
|
|
602
|
+
### discord_llm
|
|
603
|
+
|
|
604
|
+
| Bug | Fichier | Fix |
|
|
605
|
+
|-----|---------|-----|
|
|
606
|
+
| `localhost:3099` au lieu de `[::1]` | `overmind-bridge.ts` | → `http://[::1]:3099/mcp` |
|
|
607
|
+
| `no-useless-assignment` lint | `overmind-bridge.ts` | → `let mcpStatus: string` |
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## 12. Exemple Complet — 3 Agents qui Communiquent
|
|
612
|
+
|
|
613
|
+
### Créer 3 agents
|
|
614
|
+
|
|
615
|
+
```python
|
|
616
|
+
create_agent(name: "coordinator", runner: "hermes", prompt: "Tu coordonnes...", model: "glm-5.2")
|
|
617
|
+
create_agent(name: "worker_a", runner: "hermes", prompt: "Tu exécutes...", model: "glm-5.2")
|
|
618
|
+
create_agent(name: "worker_b", runner: "hermes", prompt: "Tu valides...", model: "glm-5.2")
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Structure
|
|
622
|
+
|
|
623
|
+
```
|
|
624
|
+
bridges/
|
|
625
|
+
├── coordinator/ # :3101
|
|
626
|
+
│ ├── .env # PEER_WORKER_A_URL=http://127.0.0.1:3102
|
|
627
|
+
│ │ # PEER_WORKER_B_URL=http://127.0.0.1:3103
|
|
628
|
+
│ ├── src/bridge.ts # registerRpcMethod('coord.dispatch', ...)
|
|
629
|
+
│ └── src/clients/CoordinatorToWorkerA.ts
|
|
630
|
+
│
|
|
631
|
+
├── worker_a/ # :3102
|
|
632
|
+
│ ├── .env # PEER_COORDINATOR_URL=http://127.0.0.1:3101
|
|
633
|
+
│ └── src/bridge.ts # registerRpcMethod('worker.execute', ...)
|
|
634
|
+
│
|
|
635
|
+
└── worker_b/ # :3103
|
|
636
|
+
├── .env # PEER_COORDINATOR_URL=http://127.0.0.1:3101
|
|
637
|
+
└── src/bridge.ts # registerRpcMethod('worker.validate', ...)
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Communication
|
|
641
|
+
|
|
642
|
+
```bash
|
|
643
|
+
# Coordinator → Worker A (via bridge HTTP)
|
|
644
|
+
curl -X POST http://127.0.0.1:3101/rpc \
|
|
645
|
+
-d '{"jsonrpc":"2.0","id":"1","method":"coord.dispatch","params":{"task":"analyze BTC"}}'
|
|
646
|
+
|
|
647
|
+
# Worker A → Worker B (via BridgeClient dans le code)
|
|
648
|
+
const client = new BridgeClient('http://127.0.0.1:3103');
|
|
649
|
+
await client.call('worker.validate', { result: 'BTC bullish' });
|
|
650
|
+
|
|
651
|
+
# Coordinator → tous (broadcast)
|
|
652
|
+
curl -X POST http://127.0.0.1:3101/rpc \
|
|
653
|
+
-d '{"jsonrpc":"2.0","id":"2","method":"master.broadcast","params":{"message":"Standby"}}'
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### Démarrage
|
|
657
|
+
|
|
658
|
+
```bash
|
|
659
|
+
node scripts/start-all-bridges.cjs # Lance les 3 en parallèle
|
|
660
|
+
curl http://127.0.0.1:3101/health # Verify coordinator
|
|
661
|
+
curl http://127.0.0.1:3102/health # Verify worker_a
|
|
662
|
+
curl http://127.0.0.1:3103/health # Verify worker_b
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Le pattern est **identique** pour 2, 6, 10, ou 100 agents. Ajoute un bridge, un port, un .env, et il communique avec les autres via HTTP.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overmind-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|