overmind-mcp 3.5.1 → 3.6.0
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/dist/services/AgentManager.d.ts.map +1 -1
- package/dist/services/AgentManager.js +50 -4
- package/dist/services/AgentManager.js.map +1 -1
- package/docs/overmind-bridge-commands-reference.md +438 -0
- package/docs/overmind-bridge-persistent-agents.md +463 -0
- package/package.json +1 -1
- package/docs/SOUL_pdf_bon_travail_v2.md +0 -132
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
# 🌉 Architecture 6 Bridges Isolés NEXUS — Peer-to-Peer
|
|
2
|
+
|
|
3
|
+
> **Version**: NEXUS V17 — Architecture corrigée 2026-07-09
|
|
4
|
+
> **Pattern**: 6 processes `overmind-bridge` INDÉPENDANTS, communication HTTP A2A inter-bridges
|
|
5
|
+
> **PAS de dispatcher central sur :3100** — chaque bridge a son port, son agent, son .env, ses logs
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ❌ Ce que ce n'est PAS
|
|
10
|
+
|
|
11
|
+
- ❌ Un seul `OverBridgeServer` partagé sur :3100 qui dispatche
|
|
12
|
+
- ❌ Un `OvermindBridge` qui route les appels vers les 6 agents
|
|
13
|
+
- ❌ Un bridge "central" qui connaît tous les agents
|
|
14
|
+
|
|
15
|
+
## ✅ Ce que c'est
|
|
16
|
+
|
|
17
|
+
Chaque agent NEXUS = **un process `overmind-bridge server` autonome** avec :
|
|
18
|
+
- Son propre port dédié
|
|
19
|
+
- Son agent dédié (configuré via flag)
|
|
20
|
+
- Son propre .env (clés API, peers)
|
|
21
|
+
- Ses propres logs
|
|
22
|
+
- Ses propres clients HTTP vers les autres bridges
|
|
23
|
+
|
|
24
|
+
La communication A2A = **HTTP POST inter-bridges** : agent A veut parler à agent B → POST `http://localhost:<port_b>/rpc` avec `agent.run`.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Allocation des Ports
|
|
29
|
+
|
|
30
|
+
| Bridge # | Port | Agent | Runner | Script |
|
|
31
|
+
|----------|------|-------|--------|--------|
|
|
32
|
+
| #1 | **:3101** | `nexus_master` | hermes | `start-bridge-master.ps1` |
|
|
33
|
+
| #2 | **:3102** | `nexus_trader` | hermes | `start-bridge-trader.ps1` |
|
|
34
|
+
| #3 | **:3103** | `nexus_risk_manager` | hermes | `start-bridge-risk.ps1` |
|
|
35
|
+
| #4 | **:3104** | `nexus_healer` | hermes | `start-bridge-healer.ps1` |
|
|
36
|
+
| #5 | **:3105** | `nexus_researcher` | hermes | `start-bridge-researcher.ps1` |
|
|
37
|
+
| #6 | **:3106** | `nexus_publisher` | hermes | `start-bridge-publisher.ps1` |
|
|
38
|
+
|
|
39
|
+
## Services PARTAGÉS (single instance, utilisés par les 6 bridges)
|
|
40
|
+
|
|
41
|
+
| Service | Port | Pourquoi single |
|
|
42
|
+
|---------|------|------------------|
|
|
43
|
+
| **Overmind MCP Server** | :3099 | Routing centralisé — tous les bridges passent par lui pour `run_agent` |
|
|
44
|
+
| **Hermes Gateway API** | :8642 | `X-Hermes-Profile` header route vers le bon profil — 1 process Python = 6 profils |
|
|
45
|
+
| **PostgreSQL** | :5432 | `MessageLog` partagé — tous les bridges écrivent leurs A2A messages dans la même table `bridge_messages` |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Topologie Réseau
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌────────────────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ 6 BRIDGES ISOLÉS — P2P │
|
|
54
|
+
│ │
|
|
55
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
56
|
+
│ │ :3101 │ │ :3102 │ │ :3103 │ │
|
|
57
|
+
│ │ nexus_master │◄──►│ nexus_trader │◄──►│ nexus_risk_mgr │ │
|
|
58
|
+
│ │ bridge.ts │ │ bridge.ts │ │ bridge.ts │ │
|
|
59
|
+
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
|
60
|
+
│ │ HTTP A2A │ HTTP A2A │ HTTP A2A │
|
|
61
|
+
│ │ │ │ │
|
|
62
|
+
│ ┌────────▼────────┐ ┌───────▼─────────┐ ┌──────▼──────────┐ │
|
|
63
|
+
│ │ :3104 │ │ :3105 │ │ :3106 │ │
|
|
64
|
+
│ │ nexus_healer │◄──►│ nexus_researcher│◄──►│ nexus_publisher │ │
|
|
65
|
+
│ │ bridge.ts │ │ bridge.ts │ │ bridge.ts │ │
|
|
66
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
67
|
+
│ │
|
|
68
|
+
│ │ │ │ │
|
|
69
|
+
│ └─────────────────────┼─────────────────────┘ │
|
|
70
|
+
│ │ │
|
|
71
|
+
│ ▼ │
|
|
72
|
+
│ ┌──────────────────────────────────────┐ │
|
|
73
|
+
│ │ SERVICES PARTAGÉS (single) │ │
|
|
74
|
+
│ │ • :3099 Overmind MCP Server │ │
|
|
75
|
+
│ │ • :8642 Hermes Gateway API │ │
|
|
76
|
+
│ │ • :5432 PostgreSQL (MessageLog) │ │
|
|
77
|
+
│ └──────────────────────────────────────┘ │
|
|
78
|
+
└────────────────────────────────────────────────────────────────────────┘
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Pattern de Communication
|
|
82
|
+
|
|
83
|
+
Quand `nexus_master` veut demander à `nexus_trader` d'exécuter un trade :
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Dans bridges/nexus_master/src/clients/MasterToTrader.ts
|
|
87
|
+
import { BridgeClient } from '@nexus/bridge-common';
|
|
88
|
+
|
|
89
|
+
export class MasterToTrader {
|
|
90
|
+
private client = new BridgeClient('http://127.0.0.1:3102');
|
|
91
|
+
|
|
92
|
+
async requestTrade(symbol: string, action: 'buy' | 'sell', size: number) {
|
|
93
|
+
return this.client.call('agent.run', {
|
|
94
|
+
agentName: 'nexus_trader',
|
|
95
|
+
runner: 'hermes',
|
|
96
|
+
prompt: `Exécute trade: ${action} ${size} ${symbol}`,
|
|
97
|
+
externalKey: 'master_to_trader',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Flow** :
|
|
104
|
+
1. `nexus_master` (port 3101) reçoit une requête externe
|
|
105
|
+
2. Il appelle `MasterToTrader.requestTrade()`
|
|
106
|
+
3. `BridgeClient` fait `POST http://127.0.0.1:3102/rpc`
|
|
107
|
+
4. Le bridge `nexus_trader` (port 3102) reçoit, exécute via MCP
|
|
108
|
+
5. Réponse remontée : `nexus_trader` → `nexus_master` → client externe
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Arborescence des Bridges
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
C:\Users\Deamon\Nexus\
|
|
116
|
+
│
|
|
117
|
+
├── bridges/ ← 6 WRAPPERS ISOLÉS (un par agent)
|
|
118
|
+
│ │
|
|
119
|
+
│ ├── nexus_master/ ← Bridge #1 (:3101)
|
|
120
|
+
│ │ ├── package.json ← name: @nexus/bridge-master, dep: overmind-mcp
|
|
121
|
+
│ │ ├── tsconfig.json
|
|
122
|
+
│ │ ├── .env ← AGENT_NAME, BRIDGE_PORT=3101, peers URLs
|
|
123
|
+
│ │ ├── README.md
|
|
124
|
+
│ │ ├── src/
|
|
125
|
+
│ │ │ ├── bridge.ts ← Entry point — lance OverBridgeServer
|
|
126
|
+
│ │ │ ├── config.ts ← Lit .env + export config typée
|
|
127
|
+
│ │ │ ├── logger.ts ← Pino logger dédié
|
|
128
|
+
│ │ │ ├── startup.ts ← init MessageLog + SessionStore + connect MCP
|
|
129
|
+
│ │ │ └── clients/
|
|
130
|
+
│ │ │ ├── MasterToTrader.ts ← POST :3102/rpc
|
|
131
|
+
│ │ │ ├── MasterToRisk.ts ← POST :3103/rpc
|
|
132
|
+
│ │ │ ├── MasterToResearcher.ts ← POST :3105/rpc
|
|
133
|
+
│ │ │ └── MasterToPublisher.ts ← POST :3106/rpc
|
|
134
|
+
│ │ ├── logs/
|
|
135
|
+
│ │ │ └── bridge-master.log
|
|
136
|
+
│ │ └── dist/ ← Compilé
|
|
137
|
+
│ │
|
|
138
|
+
│ ├── nexus_trader/ ← Bridge #2 (:3102)
|
|
139
|
+
│ │ ├── package.json ← name: @nexus/bridge-trader
|
|
140
|
+
│ │ ├── .env ← BRIDGE_PORT=3102
|
|
141
|
+
│ │ ├── src/
|
|
142
|
+
│ │ │ ├── bridge.ts
|
|
143
|
+
│ │ │ └── clients/
|
|
144
|
+
│ │ │ ├── TraderToMaster.ts ← POST :3101/rpc (comm au maître)
|
|
145
|
+
│ │ │ ├── TraderToRisk.ts ← POST :3103/rpc (check risk)
|
|
146
|
+
│ │ │ └── TraderToPublisher.ts ← POST :3106/rpc (publier trade)
|
|
147
|
+
│ │ └── ...
|
|
148
|
+
│ │
|
|
149
|
+
│ ├── nexus_risk_manager/ ← Bridge #3 (:3103)
|
|
150
|
+
│ │ └── ...
|
|
151
|
+
│ ├── nexus_healer/ ← Bridge #4 (:3104)
|
|
152
|
+
│ │ └── ...
|
|
153
|
+
│ ├── nexus_researcher/ ← Bridge #5 (:3105)
|
|
154
|
+
│ │ └── ...
|
|
155
|
+
│ └── nexus_publisher/ ← Bridge #6 (:3106)
|
|
156
|
+
│ └── ...
|
|
157
|
+
│
|
|
158
|
+
├── common/ ← PARTAGÉ entre les 6 bridges
|
|
159
|
+
│ ├── package.json ← name: @nexus/bridge-common
|
|
160
|
+
│ ├── src/
|
|
161
|
+
│ │ ├── BaseBridge.ts ← Classe abstraite — factorise le boot
|
|
162
|
+
│ │ ├── BridgeClient.ts ← Client HTTP vers un autre bridge
|
|
163
|
+
│ │ ├── types.ts ← Interfaces partagées
|
|
164
|
+
│ │ └── logger.ts ← Pino config commune
|
|
165
|
+
│ └── dist/
|
|
166
|
+
│
|
|
167
|
+
├── profiles/ ← Profils Hermes (existants)
|
|
168
|
+
│ ├── nexus_master/{config.yaml,SOUL.md,.env,memories/,sessions/}
|
|
169
|
+
│ ├── nexus_trader/
|
|
170
|
+
│ ├── nexus_risk_manager/
|
|
171
|
+
│ ├── nexus_healer/
|
|
172
|
+
│ ├── nexus_researcher/
|
|
173
|
+
│ └── nexus_publisher/
|
|
174
|
+
│
|
|
175
|
+
├── shared-infra/ ← SERVICES PARTAGÉS (déjà en prod)
|
|
176
|
+
│ ├── mcp-server/ ← Overmind MCP :3099
|
|
177
|
+
│ ├── hermes-gateway/ ← Gateway :8642
|
|
178
|
+
│ └── postgres/ ← :5432
|
|
179
|
+
│
|
|
180
|
+
├── scripts/ ← SCRIPTS DE GESTION
|
|
181
|
+
│ ├── start-all-bridges.ps1 ← Démarre les 6 en parallèle (Start-Job)
|
|
182
|
+
│ ├── stop-all-bridges.ps1
|
|
183
|
+
│ ├── status-bridges.ps1
|
|
184
|
+
│ ├── seed-bridges.ps1 ← Crée dossiers + .env pour les 6
|
|
185
|
+
│ └── test-a2a-network.ps1 ← Test E2E inter-bridges
|
|
186
|
+
│
|
|
187
|
+
└── logs/
|
|
188
|
+
├── bridges/
|
|
189
|
+
│ ├── nexus_master.log
|
|
190
|
+
│ ├── nexus_trader.log
|
|
191
|
+
│ ├── nexus_risk_manager.log
|
|
192
|
+
│ ├── nexus_healer.log
|
|
193
|
+
│ ├── nexus_researcher.log
|
|
194
|
+
│ └── nexus_publisher.log
|
|
195
|
+
└── network/
|
|
196
|
+
└── a2a-traffic.log
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Fichiers Clés
|
|
202
|
+
|
|
203
|
+
### 1. `bridges/nexus_master/.env`
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# === Bridge :3101 — nexus_master ===
|
|
207
|
+
AGENT_NAME=nexus_master
|
|
208
|
+
RUNNER=hermes
|
|
209
|
+
BRIDGE_PORT=3101
|
|
210
|
+
BRIDGE_HOST=127.0.0.1
|
|
211
|
+
|
|
212
|
+
# Upstream (services partagés)
|
|
213
|
+
MCP_URL=http://[::1]:3099/mcp
|
|
214
|
+
HERMES_GATEWAY_URL=http://127.0.0.1:8642
|
|
215
|
+
HERMES_GATEWAY_KEY=hIhOKpVn3AgfW_sQO8XShjMb8YRhaZngSSv6UsWY0dc
|
|
216
|
+
POSTGRES_HOST=localhost
|
|
217
|
+
POSTGRES_DB=overmind
|
|
218
|
+
POSTGRES_USER=overmind
|
|
219
|
+
POSTGRES_PASSWORD=***
|
|
220
|
+
|
|
221
|
+
# Peers (autres bridges)
|
|
222
|
+
PEER_TRADER_URL=http://127.0.0.1:3102
|
|
223
|
+
PEER_RISK_URL=http://127.0.0.1:3103
|
|
224
|
+
PEER_HEALER_URL=http://127.0.0.1:3104
|
|
225
|
+
PEER_RESEARCHER_URL=http://127.0.0.1:3105
|
|
226
|
+
PEER_PUBLISHER_URL=http://127.0.0.1:3106
|
|
227
|
+
|
|
228
|
+
# Session config
|
|
229
|
+
SESSION_TTL_MS=14400000
|
|
230
|
+
MESSAGE_LOG_ENABLED=true
|
|
231
|
+
DIRECTIVES_ENABLED=true
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 2. `common/src/BaseBridge.ts` (partagé)
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import {
|
|
238
|
+
OverBridgeServer,
|
|
239
|
+
OverBridgeService,
|
|
240
|
+
loadMessageLogConfigFromEnv,
|
|
241
|
+
createBridgeLogger,
|
|
242
|
+
} from 'overmind-mcp/bridge';
|
|
243
|
+
import { BridgeClient } from './BridgeClient.js';
|
|
244
|
+
|
|
245
|
+
export interface BaseBridgeConfig {
|
|
246
|
+
agentName: string;
|
|
247
|
+
port: number;
|
|
248
|
+
host: string;
|
|
249
|
+
mcpUrl: string;
|
|
250
|
+
logger: any;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export abstract class BaseBridge {
|
|
254
|
+
protected service: OverBridgeService;
|
|
255
|
+
protected server: OverBridgeServer;
|
|
256
|
+
|
|
257
|
+
constructor(protected config: BaseBridgeConfig) {
|
|
258
|
+
this.service = new OverBridgeService({
|
|
259
|
+
mcpUrl: config.mcpUrl,
|
|
260
|
+
defaultTimeoutMs: 60_000,
|
|
261
|
+
agentTimeoutMs: 2_700_000,
|
|
262
|
+
maxRetries: 2,
|
|
263
|
+
}, config.logger);
|
|
264
|
+
|
|
265
|
+
this.server = new OverBridgeServer(this.service, {
|
|
266
|
+
port: config.port,
|
|
267
|
+
host: config.host,
|
|
268
|
+
postgres: loadMessageLogConfigFromEnv(),
|
|
269
|
+
enableMessageLog: true,
|
|
270
|
+
enableSessionStore: true,
|
|
271
|
+
enableDirectives: true,
|
|
272
|
+
sessionTtlMs: 4 * 60 * 60 * 1000,
|
|
273
|
+
rateLimitMax: 200,
|
|
274
|
+
sanitizeJson: true,
|
|
275
|
+
}, config.logger);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
abstract getClients(): BridgeClient[];
|
|
279
|
+
|
|
280
|
+
async start(): Promise<void> {
|
|
281
|
+
await this.server.start();
|
|
282
|
+
this.config.logger.info(`🚀 Bridge ${this.config.agentName} ready on :${this.config.port}`);
|
|
283
|
+
for (const client of this.getClients()) {
|
|
284
|
+
await client.healthCheck();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async stop(): Promise<void> {
|
|
289
|
+
await this.server.stop();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 3. `bridges/nexus_master/src/bridge.ts`
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { BaseBridge } from '@nexus/bridge-common';
|
|
298
|
+
import { config } from './config.js';
|
|
299
|
+
import { MasterToTrader } from './clients/MasterToTrader.js';
|
|
300
|
+
import { MasterToRisk } from './clients/MasterToRisk.js';
|
|
301
|
+
import { MasterToResearcher } from './clients/MasterToResearcher.js';
|
|
302
|
+
import { MasterToPublisher } from './clients/MasterToPublisher.js';
|
|
303
|
+
import { logger } from './logger.js';
|
|
304
|
+
|
|
305
|
+
class MasterBridge extends BaseBridge {
|
|
306
|
+
protected getClients() {
|
|
307
|
+
return [
|
|
308
|
+
new MasterToTrader(config.peerTraderUrl, logger),
|
|
309
|
+
new MasterToRisk(config.peerRiskUrl, logger),
|
|
310
|
+
new MasterToResearcher(config.peerResearcherUrl, logger),
|
|
311
|
+
new MasterToPublisher(config.peerPublisherUrl, logger),
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const bridge = new MasterBridge();
|
|
317
|
+
await bridge.start();
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 4. `bridges/nexus_master/src/clients/MasterToTrader.ts`
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { BridgeClient } from '@nexus/bridge-common';
|
|
324
|
+
|
|
325
|
+
export class MasterToTrader {
|
|
326
|
+
private client: BridgeClient;
|
|
327
|
+
|
|
328
|
+
constructor(traderUrl: string, logger: any) {
|
|
329
|
+
this.client = new BridgeClient(traderUrl, logger);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async requestTrade(symbol: string, action: 'buy' | 'sell', size: number): Promise<any> {
|
|
333
|
+
return this.client.call('agent.run', {
|
|
334
|
+
agentName: 'nexus_trader',
|
|
335
|
+
runner: 'hermes',
|
|
336
|
+
prompt: `Exécute trade: ${action} ${size} ${symbol}`,
|
|
337
|
+
externalKey: 'master_to_trader',
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async askAnalysis(marketData: any): Promise<any> {
|
|
342
|
+
return this.client.call('agent.run', {
|
|
343
|
+
agentName: 'nexus_trader',
|
|
344
|
+
runner: 'hermes',
|
|
345
|
+
prompt: `Analyse ces données: ${JSON.stringify(marketData)}`,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Scripts de Gestion
|
|
354
|
+
|
|
355
|
+
### `scripts/start-all-bridges.ps1`
|
|
356
|
+
|
|
357
|
+
```powershell
|
|
358
|
+
# Démarre les 6 bridges en parallèle
|
|
359
|
+
$bridges = @(
|
|
360
|
+
@{ Name="master"; Port=3101 },
|
|
361
|
+
@{ Name="trader"; Port=3102 },
|
|
362
|
+
@{ Name="risk_manager"; Port=3103 },
|
|
363
|
+
@{ Name="healer"; Port=3104 },
|
|
364
|
+
@{ Name="researcher"; Port=3105 },
|
|
365
|
+
@{ Name="publisher"; Port=3106 }
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
$jobs = @()
|
|
369
|
+
foreach ($b in $bridges) {
|
|
370
|
+
$script = "cd '$PSScriptRoot\..\bridges\nexus_$($b.Name)' ; node dist/bridge.js"
|
|
371
|
+
$jobs += Start-Job -ScriptBlock { Invoke-Expression $args[0] } -ArgumentList $script
|
|
372
|
+
Write-Host "✅ Started nexus_$($b.Name) on :$($b.Port)"
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
Write-Host "`n6 bridges running. Press Ctrl+C to stop."
|
|
376
|
+
Wait-Job -Job $jobs
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### `scripts/seed-bridges.ps1`
|
|
380
|
+
|
|
381
|
+
```powershell
|
|
382
|
+
# Crée la structure de dossiers + .env pour les 6 bridges
|
|
383
|
+
$template = @'
|
|
384
|
+
AGENT_NAME={AGENT}
|
|
385
|
+
RUNNER=hermes
|
|
386
|
+
BRIDGE_PORT={PORT}
|
|
387
|
+
BRIDGE_HOST=127.0.0.1
|
|
388
|
+
MCP_URL=http://[::1]:3099/mcp
|
|
389
|
+
HERMES_GATEWAY_URL=http://127.0.0.1:8642
|
|
390
|
+
HERMES_GATEWAY_KEY=<KEY>
|
|
391
|
+
PEER_TRADER_URL=http://127.0.0.1:3102
|
|
392
|
+
PEER_RISK_URL=http://127.0.0.1:3103
|
|
393
|
+
PEER_HEALER_URL=http://127.0.0.1:3104
|
|
394
|
+
PEER_RESEARCHER_URL=http://127.0.0.1:3105
|
|
395
|
+
PEER_PUBLISHER_URL=http://127.0.0.1:3106
|
|
396
|
+
'@
|
|
397
|
+
|
|
398
|
+
$config = @(
|
|
399
|
+
@{ Name="master"; Port=3101 },
|
|
400
|
+
@{ Name="trader"; Port=3102 },
|
|
401
|
+
@{ Name="risk_manager"; Port=3103 },
|
|
402
|
+
@{ Name="healer"; Port=3104 },
|
|
403
|
+
@{ Name="researcher"; Port=3105 },
|
|
404
|
+
@{ Name="publisher"; Port=3106 }
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
foreach ($c in $config) {
|
|
408
|
+
$dir = "$PSScriptRoot\..\bridges\nexus_$($c.Name)"
|
|
409
|
+
New-Item -ItemType Directory -Force -Path "$dir/src/clients"
|
|
410
|
+
New-Item -ItemType Directory -Force -Path "$dir/logs"
|
|
411
|
+
$env = $template -replace '{AGENT}', "nexus_$($c.Name)" -replace '{PORT}', $c.Port
|
|
412
|
+
Set-Content -Path "$dir/.env" -Value $env
|
|
413
|
+
Write-Host "✅ Seeded nexus_$($c.Name) on :$($c.Port)"
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Avantages de cette Architecture
|
|
420
|
+
|
|
421
|
+
| Bénéfice | Explication |
|
|
422
|
+
|----------|-------------|
|
|
423
|
+
| **Isolation** | Chaque agent = son process, son port, ses logs. Crash d'un agent ≠ crash des autres. |
|
|
424
|
+
| **Scaling indépendant** | Tu peux redémarrer `nexus_trader` sans toucher aux autres. |
|
|
425
|
+
| **Monitoring clair** | `GET :3101/health`, `GET :3102/health`, etc. — chaque agent a sa métrique. |
|
|
426
|
+
| **Déploiement granulaire** | Tu peux déployer un agent sur une autre machine en gardant le même code. |
|
|
427
|
+
| **Logs séparés** | `logs/bridges/nexus_master.log` — debugging facile par agent. |
|
|
428
|
+
| **Config par agent** | `.env` dédié — clés API différentes si besoin. |
|
|
429
|
+
| **Pas de SPOF** | Si le bridge master crash, les 5 autres continuent à fonctionner entre eux. |
|
|
430
|
+
|
|
431
|
+
## Flow Complet — Exemple Concret
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
Discord !sniper trade BTC
|
|
435
|
+
↓
|
|
436
|
+
discord_llm bridge (:3001)
|
|
437
|
+
↓ HTTP POST /send
|
|
438
|
+
↓
|
|
439
|
+
nexus_master bridge (:3101)
|
|
440
|
+
↓ BridgeClient.call('agent.run', agentName='nexus_trader')
|
|
441
|
+
↓ HTTP POST http://localhost:3102/rpc
|
|
442
|
+
↓
|
|
443
|
+
nexus_trader bridge (:3102)
|
|
444
|
+
↓ service.runAgent() → BridgeProxy → HTTP POST :3099/mcp
|
|
445
|
+
↓
|
|
446
|
+
Overmind MCP Server (:3099)
|
|
447
|
+
↓ runHermesAgent() → HermesGatewayRunner
|
|
448
|
+
↓ HTTP POST :8642/v1/chat/completions + X-Hermes-Profile: nexus_trader
|
|
449
|
+
↓
|
|
450
|
+
Hermes Gateway (:8642)
|
|
451
|
+
↓ Route vers profil nexus_trader
|
|
452
|
+
↓ Response: "BUY 0.1 BTC @ 67500"
|
|
453
|
+
↑ retour en sens inverse ↑
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Références
|
|
459
|
+
|
|
460
|
+
- `overmind-mcp/bridge` exports : `OverBridgeServer`, `OverBridgeService`, `BridgeProxy`, `SessionStore`, `MessageLog`
|
|
461
|
+
- Doc source : `Workflow/src/bridge/OverBridgeServer.ts` (1928 lignes)
|
|
462
|
+
- Profils Hermes existants : `~/.hermes/profiles/nexus_*` (7 profils créés)
|
|
463
|
+
- Gateway API : `Workflow/src/services/HermesGatewayRunner.ts` (HTTP+SSE, port 8642)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overmind-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
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",
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# BT Secretary — Gestion bons de travail et feuilles de temps
|
|
2
|
-
|
|
3
|
-
## RÈGLE #1 — RÉPONSE OBLIGATOIRE PAR SMS
|
|
4
|
-
|
|
5
|
-
À CHAQUE message reçu, tu DOIS:
|
|
6
|
-
1. Appeler `call_sms` du serveur `voipms-mcp` pour envoyer ta réponse
|
|
7
|
-
2. Puis rédiger ta réponse dans le chat (même contenu)
|
|
8
|
-
|
|
9
|
-
```json
|
|
10
|
-
call_sms({ "dst": "<NUMERO_SANS_PLUS>", "message": "Réponse max 160 chars" })
|
|
11
|
-
```
|
|
12
|
-
- `did` est HARDCODÉ en interne — ne pas passer
|
|
13
|
-
- Le `dst` SANS le +. Ex: +14187207735 → dst="4187207735"
|
|
14
|
-
- Format SMS: texte brut, JAMAIS de markdown/gras/listes
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## IDENTITÉ
|
|
19
|
-
|
|
20
|
-
Tu es **Mamadou**, secrétaire virtuelle de **Bon Air Construction**.
|
|
21
|
-
Femme, 27 ans, chrétienne. Tu gères les bons de travail et feuilles de temps par SMS.
|
|
22
|
-
Réponds en **français**, texte brut, max 160 chars quand possible.
|
|
23
|
-
|
|
24
|
-
### TON ADAPTÉ
|
|
25
|
-
Récupère le profil: `SELECT ton, expressions, emoji_usage, surnom FROM bt_employes_profils WHERE employe_id = <id>;`
|
|
26
|
-
- professionnel: clair, efficace, peu d'emojis
|
|
27
|
-
- familier: chaleureux, expressions québécoises, emojis
|
|
28
|
-
- neutre: factuel, aucun emoji
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## BASE DE DONNÉES
|
|
33
|
-
|
|
34
|
-
PostgreSQL: localhost:5432, base: `financial_analyst`
|
|
35
|
-
|
|
36
|
-
### TABLES PRINCIPALES
|
|
37
|
-
|
|
38
|
-
**bt_employes**: id, prenom, nom, poste, tel, actif, email
|
|
39
|
-
**bt_contrats**: id, no_projet(UNIQUE), client, adresse, ville, type(commerciale|residentielle|industrielle|genie_civil|regie|non_regie), statut(actif|termine|suspendu), notes
|
|
40
|
-
**bt_semaines**: id, employe_id, contrat_id, no_projet, date_debut(lundi), heures_lun..heures_dim(numeric 4,1), description_ligne1..6, notes
|
|
41
|
-
**bt_feuilles_temps**: id, employe_id, semaine_du(lundi), semaine_au(dimanche), mois, annee, statut(en_cours|soumis|valide), pdf_path, pdf_url
|
|
42
|
-
**bt_feuilles_temps_lignes**: id, feuille_temps_id, jour(lundi|mardi|...), ligne_index(0-2), no_projet, heures_reg/comm/res/ind/ind_lourd/genie_civil, heure_debut/pause1_dbt/pause1_fin/diner_dbt/diner_fin/pause2_dbt/pause2_fin/fin, km
|
|
43
|
-
**bt_bons**: id, contrat_id, employe_id, semaine_id, feuille_temps_id, no_projet, no_bon, date_bon, description, notes, pdf_path
|
|
44
|
-
**bt_materiaux**: id, bon_id, semaine_id, description, qte, unite, prix_unitaire, prix_total
|
|
45
|
-
|
|
46
|
-
### IDENTIFICATION EMPLOYÉ
|
|
47
|
-
```sql
|
|
48
|
-
SELECT id, prenom, nom, poste FROM bt_employes
|
|
49
|
-
WHERE RIGHT(REPLACE(REPLACE(tel, '-', ''), '+', ''), 10) = RIGHT(REPLACE('<NUMERO>', '+', ''), 10) AND actif = true;
|
|
50
|
-
```
|
|
51
|
-
Si non trouvé → SMS: "Bonjour! Je ne te reconnais pas. Demande à ton contremaître de t'inscrire."
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## RÈGLES MÉTIER
|
|
56
|
-
|
|
57
|
-
### R1: SYNC BON/FEUILLE
|
|
58
|
-
Chaque bon = une semaine sur un chantier (bt_semaines). Trigger DB synchronise vers bt_feuilles_temps_lignes.
|
|
59
|
-
|
|
60
|
-
### R2: CHEF vs ÉQUIPIER
|
|
61
|
-
- Chef d'équipe (Nicolas, id=1): rédige le bon, donne descriptions + matériaux
|
|
62
|
-
- Équipier (Samuel, id=2): enregistre ses heures mais NE rédige PAS. Dis: "Heures notées! Nicolas s'occupe du bon."
|
|
63
|
-
- Exception: équipier seul sur chantier = peut rédiger
|
|
64
|
-
|
|
65
|
-
### R3: NOUVEAU CHANTIER
|
|
66
|
-
Si no_projet inexistant: `INSERT INTO bt_contrats (no_projet, client, type, statut) VALUES ('<projet>', 'À confirmer', 'non_regie', 'actif');`
|
|
67
|
-
Puis SMS: "Nouveau chantier créé. Nom du client et adresse?"
|
|
68
|
-
|
|
69
|
-
### R4: ÉCRITURE IMMÉDIATE
|
|
70
|
-
Quand un employé donne une info → exécute le SQL IMMÉDIATEMENT avant de répondre. Jamais dire "c'est noté" sans avoir fait l'INSERT/UPDATE.
|
|
71
|
-
|
|
72
|
-
### R5: DATE LUNDI OBLIGATOIRE
|
|
73
|
-
date_debut et semaine_du = TOUJOURS le lundi de la semaine. Jamais mardi/mercredi.
|
|
74
|
-
|
|
75
|
-
### R6: HORAIRES CCQ PAR DÉFAUT
|
|
76
|
-
- heure_debut: heure donnée ou '07:00'
|
|
77
|
-
- pause1: 09:00-09:15, dîner: 12:00-12:30, pause2: 14:30-14:45
|
|
78
|
-
- heure_fin: début + heures travaillées + 1h pauses
|
|
79
|
-
- km: 0.0 par défaut
|
|
80
|
-
|
|
81
|
-
### R7: ÉQUIPE NICOLAS & SAMUEL
|
|
82
|
-
- Écritures DISTINCTES obligatoires (id=1 et id=2 séparés)
|
|
83
|
-
- Samuel peut arriver en retard (ex: 08:30 au lieu de 07:00)
|
|
84
|
-
- ATTENTION TRIGGER: UPDATE bt_semaines efface les horaires détaillés dans bt_feuilles_temps_lignes → DOIT ré-écrire les horaires après chaque UPDATE bt_semaines
|
|
85
|
-
|
|
86
|
-
### R8: DOUBLONS MATÉRIAUX
|
|
87
|
-
Vérifie existence avant INSERT. Si similaire → demande clarification.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## PDF PIPELINE
|
|
92
|
-
|
|
93
|
-
NE JAMAIS créer de PDF soi-même (pas de fitz/PyMuPDF).
|
|
94
|
-
|
|
95
|
-
**Étape A**: Écrire données en DB (INSERT/UPDATE)
|
|
96
|
-
**Étape B**: Appeler les scripts:
|
|
97
|
-
```bash
|
|
98
|
-
# Bon de travail
|
|
99
|
-
/home/demon/bt-sms/pdfjob_clean/.venv/bin/python /home/demon/bt-sms/pdfjob_clean/Outils/fill_bon_travail.py --bon-id <ID>
|
|
100
|
-
# Feuille de temps
|
|
101
|
-
/home/demon/bt-sms/pdfjob_clean/.venv/bin/python /home/demon/bt-sms/pdfjob_clean/Outils/fill_feuille_temps.py --feuille-id <ID>
|
|
102
|
-
```
|
|
103
|
-
**Étape C**: Upload `POST http://localhost:3149/upload-local {path: "/home/demon/bt-sms/bons_pdf/<file>"}` puis `send_mms({dst, message, media1: url})`
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## ACTIONS SPÉCIALES
|
|
108
|
-
|
|
109
|
-
### OCR (photos de feuilles)
|
|
110
|
-
`/home/demon/bt-sms/pdfjob_clean/.venv/bin/python3 /home/demon/bt-sms/pdfjob_clean/Outils/ocr_extract.py "<URL_MEDIA>"`
|
|
111
|
-
|
|
112
|
-
### Rapport Vocal (MMS MP4)
|
|
113
|
-
1. Rédiger résumé hebdo complet
|
|
114
|
-
2. `/home/demon/bt-sms/pdfjob_clean/.venv/bin/python3 /home/demon/bt-sms/pdfjob_clean/Outils/generate_vocal_mms.py --text "<rapport>" --name "rapport_<semaine>"`
|
|
115
|
-
3. `send_mms({dst, message, media1: url})`
|
|
116
|
-
|
|
117
|
-
### Email
|
|
118
|
-
- Expéditeur: agenticspeedworkflow@gmail.com
|
|
119
|
-
- CC: nicolasracine44@gmail.com
|
|
120
|
-
- Templates HTML: /home/demon/bt-sms/templates/email_rapport_hebdo.html
|
|
121
|
-
- Toujours vérifier heures en DB avant d'envoyer (SQL SELECT)
|
|
122
|
-
- 1 bon de travail par chantier (pas de doublon par employé)
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## RÈGLES ABSOLUES
|
|
127
|
-
1. Identifier l'employé en PREMIER
|
|
128
|
-
2. Ne jamais inventer de données
|
|
129
|
-
3. Répondre par SMS/MMS via voipms-mcp
|
|
130
|
-
4. Texte brut sans markdown dans les SMS
|
|
131
|
-
5. Écrire en DB avant de confirmer
|
|
132
|
-
6. Jamais afficher de code technique dans un SMS
|