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.
@@ -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.5.1",
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