societyai 0.0.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/CHANGELOG.md +111 -0
- package/LICENSE +21 -0
- package/README.md +879 -0
- package/dist/builder.d.ts +181 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +667 -0
- package/dist/builder.js.map +1 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +107 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +319 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +85 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +219 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +395 -0
- package/dist/events.js.map +1 -0
- package/dist/graph.d.ts +104 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +366 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory.d.ts +146 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +353 -0
- package/dist/memory.js.map +1 -0
- package/dist/metrics.d.ts +143 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +271 -0
- package/dist/metrics.js.map +1 -0
- package/dist/middleware.d.ts +147 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +484 -0
- package/dist/middleware.js.map +1 -0
- package/dist/models.d.ts +32 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +211 -0
- package/dist/models.js.map +1 -0
- package/dist/patterns.d.ts +6 -0
- package/dist/patterns.d.ts.map +1 -0
- package/dist/patterns.js +68 -0
- package/dist/patterns.js.map +1 -0
- package/dist/pipeline.d.ts +84 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +569 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/retry.d.ts +5 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +70 -0
- package/dist/retry.js.map +1 -0
- package/dist/society.d.ts +94 -0
- package/dist/society.d.ts.map +1 -0
- package/dist/society.js +721 -0
- package/dist/society.js.map +1 -0
- package/dist/strategies.d.ts +55 -0
- package/dist/strategies.d.ts.map +1 -0
- package/dist/strategies.js +678 -0
- package/dist/strategies.js.map +1 -0
- package/dist/tools.d.ts +88 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +366 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +64 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +334 -0
- package/dist/validation.js.map +1 -0
- package/dist/worker-pool.d.ts +17 -0
- package/dist/worker-pool.d.ts.map +1 -0
- package/dist/worker-pool.js +80 -0
- package/dist/worker-pool.js.map +1 -0
- package/docs/README.md +468 -0
- package/docs/advanced.md +616 -0
- package/docs/aggregation-strategies.md +926 -0
- package/docs/api-reference.md +771 -0
- package/docs/architecture.md +648 -0
- package/docs/context-system.md +642 -0
- package/docs/event-system.md +1047 -0
- package/docs/examples.md +576 -0
- package/docs/getting-started.md +564 -0
- package/docs/graph-execution.md +389 -0
- package/docs/memory-system.md +497 -0
- package/docs/metrics-observability.md +560 -0
- package/docs/middleware-system.md +1038 -0
- package/docs/migration.md +296 -0
- package/docs/pipeline-patterns.md +761 -0
- package/docs/structured-output.md +612 -0
- package/docs/tool-calling.md +491 -0
- package/docs/workflows.md +740 -0
- package/examples/README.md +234 -0
- package/examples/advanced-patterns.ts +115 -0
- package/examples/complete-integration.ts +327 -0
- package/examples/graph-workflow.ts +161 -0
- package/examples/memory-system.ts +155 -0
- package/examples/metrics-tracking.ts +243 -0
- package/examples/structured-output.ts +231 -0
- package/examples/tool-calling.ts +163 -0
- package/package.json +94 -0
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
# Event System
|
|
2
|
+
|
|
3
|
+
Le système d'événements de SocietyAI fournit un mécanisme d'observation type-safe pour surveiller le cycle de vie des workflows, suivre la progression, et intégrer avec des systèmes externes.
|
|
4
|
+
|
|
5
|
+
## Table des Matières
|
|
6
|
+
|
|
7
|
+
- [Vue d'ensemble](#vue-densemble)
|
|
8
|
+
- [Types d'Événements](#types-dévénements)
|
|
9
|
+
- [Event Emitter](#event-emitter)
|
|
10
|
+
- [Event Handlers](#event-handlers)
|
|
11
|
+
- [Progress Tracking](#progress-tracking)
|
|
12
|
+
- [Event Filtering](#event-filtering)
|
|
13
|
+
- [Event History](#event-history)
|
|
14
|
+
- [Intégrations](#intégrations)
|
|
15
|
+
- [Exemples Complets](#exemples-complets)
|
|
16
|
+
|
|
17
|
+
## Vue d'ensemble
|
|
18
|
+
|
|
19
|
+
Le système d'événements permet de:
|
|
20
|
+
|
|
21
|
+
- **Observer le cycle de vie** des workflows, steps et agents
|
|
22
|
+
- **Suivre la progression** en temps réel
|
|
23
|
+
- **Déboguer** avec des hooks détaillés
|
|
24
|
+
- **Intégrer** avec des systèmes de logging/monitoring externes
|
|
25
|
+
- **Historique** des événements pour replay et analyse
|
|
26
|
+
|
|
27
|
+
### Principes de Design
|
|
28
|
+
|
|
29
|
+
- **Type-safe**: Support complet TypeScript pour tous les types d'événements
|
|
30
|
+
- **Async**: Les handlers asynchrones ne bloquent pas l'exécution
|
|
31
|
+
- **Extensible**: Facile d'ajouter des événements personnalisés
|
|
32
|
+
- **Non-bloquant**: L'exécution continue même si les handlers échouent
|
|
33
|
+
- **Zero runtime deps**: Implémentation pure TypeScript
|
|
34
|
+
|
|
35
|
+
## Types d'Événements
|
|
36
|
+
|
|
37
|
+
### Événements de Workflow
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Démarrage de workflow
|
|
41
|
+
interface WorkflowStartEvent {
|
|
42
|
+
type: 'workflow:start';
|
|
43
|
+
workflowId: string;
|
|
44
|
+
workflowName: string;
|
|
45
|
+
input: string;
|
|
46
|
+
agentCount: number;
|
|
47
|
+
timestamp: number;
|
|
48
|
+
correlationId?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Complétion de workflow
|
|
52
|
+
interface WorkflowCompleteEvent {
|
|
53
|
+
type: 'workflow:complete';
|
|
54
|
+
workflowId: string;
|
|
55
|
+
workflowName: string;
|
|
56
|
+
result: WorkflowResult;
|
|
57
|
+
duration: number;
|
|
58
|
+
timestamp: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Erreur de workflow
|
|
62
|
+
interface WorkflowErrorEvent {
|
|
63
|
+
type: 'workflow:error';
|
|
64
|
+
workflowId: string;
|
|
65
|
+
workflowName: string;
|
|
66
|
+
error: Error;
|
|
67
|
+
timestamp: number;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Événements de Step
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Démarrage de step
|
|
75
|
+
interface StepStartEvent {
|
|
76
|
+
type: 'step:start';
|
|
77
|
+
stepId: string;
|
|
78
|
+
stepName: string;
|
|
79
|
+
agentIds: string[];
|
|
80
|
+
executionType: string;
|
|
81
|
+
timestamp: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Complétion de step
|
|
85
|
+
interface StepCompleteEvent {
|
|
86
|
+
type: 'step:complete';
|
|
87
|
+
stepId: string;
|
|
88
|
+
stepName: string;
|
|
89
|
+
results: StepResult[];
|
|
90
|
+
duration: number;
|
|
91
|
+
timestamp: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Erreur de step
|
|
95
|
+
interface StepErrorEvent {
|
|
96
|
+
type: 'step:error';
|
|
97
|
+
stepId: string;
|
|
98
|
+
stepName: string;
|
|
99
|
+
error: Error;
|
|
100
|
+
timestamp: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Step sauté
|
|
104
|
+
interface StepSkippedEvent {
|
|
105
|
+
type: 'step:skipped';
|
|
106
|
+
stepId: string;
|
|
107
|
+
stepName: string;
|
|
108
|
+
reason: string;
|
|
109
|
+
timestamp: number;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Événements d'Agent
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Démarrage d'agent
|
|
117
|
+
interface AgentStartEvent {
|
|
118
|
+
type: 'agent:start';
|
|
119
|
+
agentId: string;
|
|
120
|
+
agentName?: string;
|
|
121
|
+
modelName: string;
|
|
122
|
+
prompt: unknown;
|
|
123
|
+
timestamp: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Complétion d'agent
|
|
127
|
+
interface AgentCompleteEvent {
|
|
128
|
+
type: 'agent:complete';
|
|
129
|
+
agentId: string;
|
|
130
|
+
agentName?: string;
|
|
131
|
+
modelName: string;
|
|
132
|
+
result: string;
|
|
133
|
+
duration: number;
|
|
134
|
+
timestamp: number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Erreur d'agent
|
|
138
|
+
interface AgentErrorEvent {
|
|
139
|
+
type: 'agent:error';
|
|
140
|
+
agentId: string;
|
|
141
|
+
agentName?: string;
|
|
142
|
+
modelName: string;
|
|
143
|
+
error: Error;
|
|
144
|
+
timestamp: number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Retry d'agent
|
|
148
|
+
interface AgentRetryEvent {
|
|
149
|
+
type: 'agent:retry';
|
|
150
|
+
agentId: string;
|
|
151
|
+
agentName?: string;
|
|
152
|
+
attempt: number;
|
|
153
|
+
maxAttempts: number;
|
|
154
|
+
error: Error;
|
|
155
|
+
timestamp: number;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Événements de Progression
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface ProgressEvent {
|
|
163
|
+
type: 'progress';
|
|
164
|
+
percent: number; // 0-100
|
|
165
|
+
phase: string; // Description de la phase
|
|
166
|
+
estimatedTimeRemaining?: number; // ms
|
|
167
|
+
details?: Record<string, unknown>;
|
|
168
|
+
timestamp: number;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Événements de Message
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Message envoyé
|
|
176
|
+
interface MessageSentEvent {
|
|
177
|
+
type: 'message:sent';
|
|
178
|
+
from: string;
|
|
179
|
+
to: string | 'broadcast';
|
|
180
|
+
messageType: string;
|
|
181
|
+
content: string;
|
|
182
|
+
timestamp: number;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Message reçu
|
|
186
|
+
interface MessageReceivedEvent {
|
|
187
|
+
type: 'message:received';
|
|
188
|
+
from: string;
|
|
189
|
+
to: string;
|
|
190
|
+
messageType: string;
|
|
191
|
+
content: string;
|
|
192
|
+
timestamp: number;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Événements de Debug
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
interface DebugEvent {
|
|
200
|
+
type: 'debug';
|
|
201
|
+
level: 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
202
|
+
message: string;
|
|
203
|
+
data?: unknown;
|
|
204
|
+
timestamp: number;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Événements Personnalisés
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
interface CustomEvent {
|
|
212
|
+
type: 'custom';
|
|
213
|
+
name: string;
|
|
214
|
+
data: unknown;
|
|
215
|
+
timestamp: number;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Event Emitter
|
|
220
|
+
|
|
221
|
+
### Création et Utilisation de Base
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { SocietyEventEmitter } from 'societyai';
|
|
225
|
+
|
|
226
|
+
const emitter = new SocietyEventEmitter();
|
|
227
|
+
|
|
228
|
+
// Écouter des événements
|
|
229
|
+
emitter.on('workflow:start', (event) => {
|
|
230
|
+
console.log(`Workflow started: ${event.workflowName}`);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
emitter.on('agent:complete', (event) => {
|
|
234
|
+
console.log(`Agent ${event.agentId} completed in ${event.duration}ms`);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Handlers asynchrones
|
|
238
|
+
emitter.on('workflow:complete', async (event) => {
|
|
239
|
+
await saveResults(event.result);
|
|
240
|
+
await notifyUser(event.workflowId);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Émission d'événements
|
|
244
|
+
emitter.emit({
|
|
245
|
+
type: 'workflow:start',
|
|
246
|
+
workflowId: 'wf-123',
|
|
247
|
+
workflowName: 'Analysis',
|
|
248
|
+
input: 'Analyze this',
|
|
249
|
+
agentCount: 3,
|
|
250
|
+
timestamp: Date.now(),
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Wildcard et Événements Multiples
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// Écouter tous les événements
|
|
258
|
+
emitter.on('*', (event) => {
|
|
259
|
+
console.log(`Event: ${event.type}`);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Écouter plusieurs types
|
|
263
|
+
emitter.on('workflow:start', handleWorkflowStart);
|
|
264
|
+
emitter.on('workflow:complete', handleWorkflowComplete);
|
|
265
|
+
emitter.on('workflow:error', handleWorkflowError);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Once - Écouter une seule fois
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// S'exécute une seule fois puis se détache
|
|
272
|
+
emitter.once('workflow:complete', (event) => {
|
|
273
|
+
console.log('First workflow completed!');
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Détachement des Handlers
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
const handler = (event) => console.log(event);
|
|
281
|
+
|
|
282
|
+
emitter.on('agent:start', handler);
|
|
283
|
+
|
|
284
|
+
// Détacher plus tard
|
|
285
|
+
emitter.off('agent:start', handler);
|
|
286
|
+
|
|
287
|
+
// Détacher tous les handlers d'un type
|
|
288
|
+
emitter.removeAllListeners('agent:start');
|
|
289
|
+
|
|
290
|
+
// Détacher tous les handlers
|
|
291
|
+
emitter.removeAllListeners();
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Event Handlers
|
|
295
|
+
|
|
296
|
+
### Handler Type-Safe
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { EventHandler } from 'societyai';
|
|
300
|
+
|
|
301
|
+
// Handler typé pour un type d'événement spécifique
|
|
302
|
+
const workflowHandler: EventHandler<WorkflowCompleteEvent> = (event) => {
|
|
303
|
+
// 'event' est correctement typé comme WorkflowCompleteEvent
|
|
304
|
+
console.log(event.result.output);
|
|
305
|
+
console.log(event.duration);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
emitter.on('workflow:complete', workflowHandler);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Handler avec Gestion d'Erreur
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
emitter.on('agent:error', (event) => {
|
|
315
|
+
console.error(`Agent ${event.agentId} failed:`, event.error);
|
|
316
|
+
|
|
317
|
+
// Notification
|
|
318
|
+
notifyDevelopers({
|
|
319
|
+
agentId: event.agentId,
|
|
320
|
+
error: event.error.message,
|
|
321
|
+
timestamp: event.timestamp,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Logging
|
|
325
|
+
logger.error('Agent execution failed', {
|
|
326
|
+
agentId: event.agentId,
|
|
327
|
+
model: event.modelName,
|
|
328
|
+
error: event.error,
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Handler Conditionnel
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
emitter.on('agent:complete', (event) => {
|
|
337
|
+
// Seulement pour certains agents
|
|
338
|
+
if (event.agentId.startsWith('critical-')) {
|
|
339
|
+
// Action spéciale
|
|
340
|
+
priorityLog(event);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Seulement si lent
|
|
344
|
+
if (event.duration > 5000) {
|
|
345
|
+
console.warn(`Slow agent: ${event.agentId} took ${event.duration}ms`);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Progress Tracking
|
|
351
|
+
|
|
352
|
+
### ProgressTracker
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { ProgressTracker } from 'societyai';
|
|
356
|
+
|
|
357
|
+
const tracker = new ProgressTracker(emitter);
|
|
358
|
+
|
|
359
|
+
// Démarrer le tracking
|
|
360
|
+
tracker.start('workflow-123', {
|
|
361
|
+
totalSteps: 5,
|
|
362
|
+
estimatedDuration: 30000, // 30s
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Mettre à jour la progression
|
|
366
|
+
tracker.updateProgress('workflow-123', {
|
|
367
|
+
current: 1,
|
|
368
|
+
phase: 'Analyzing input',
|
|
369
|
+
details: { agentsActive: 2 },
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
tracker.updateProgress('workflow-123', {
|
|
373
|
+
current: 2,
|
|
374
|
+
phase: 'Processing data',
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Compléter
|
|
378
|
+
tracker.complete('workflow-123');
|
|
379
|
+
|
|
380
|
+
// Les événements 'progress' sont automatiquement émis
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Tracking Manuel
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// Émettre manuellement des événements de progression
|
|
387
|
+
emitter.emit({
|
|
388
|
+
type: 'progress',
|
|
389
|
+
percent: 25,
|
|
390
|
+
phase: 'Step 1 of 4',
|
|
391
|
+
estimatedTimeRemaining: 15000,
|
|
392
|
+
timestamp: Date.now(),
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Avec détails
|
|
396
|
+
emitter.emit({
|
|
397
|
+
type: 'progress',
|
|
398
|
+
percent: 50,
|
|
399
|
+
phase: 'Processing',
|
|
400
|
+
details: {
|
|
401
|
+
itemsProcessed: 50,
|
|
402
|
+
itemsTotal: 100,
|
|
403
|
+
currentItem: 'item-50',
|
|
404
|
+
},
|
|
405
|
+
timestamp: Date.now(),
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Progress UI
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
// Intégration avec une barre de progression
|
|
413
|
+
emitter.on('progress', (event) => {
|
|
414
|
+
updateProgressBar(event.percent);
|
|
415
|
+
updateStatusText(event.phase);
|
|
416
|
+
|
|
417
|
+
if (event.estimatedTimeRemaining) {
|
|
418
|
+
updateETA(event.estimatedTimeRemaining);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Console progress bar
|
|
423
|
+
emitter.on('progress', (event) => {
|
|
424
|
+
const bar = '='.repeat(event.percent / 2) + ' '.repeat(50 - event.percent / 2);
|
|
425
|
+
process.stdout.write(`\r[${bar}] ${event.percent}% - ${event.phase}`);
|
|
426
|
+
});
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Event Filtering
|
|
430
|
+
|
|
431
|
+
### FilteredEventEmitter
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
import { FilteredEventEmitter } from 'societyai';
|
|
435
|
+
|
|
436
|
+
const baseEmitter = new SocietyEventEmitter();
|
|
437
|
+
|
|
438
|
+
// Créer un emitter filtré
|
|
439
|
+
const filteredEmitter = new FilteredEventEmitter(baseEmitter, (event) => {
|
|
440
|
+
// Filtrer seulement les événements d'agents spécifiques
|
|
441
|
+
if (event.type.startsWith('agent:')) {
|
|
442
|
+
const agentEvent = event as AgentStartEvent;
|
|
443
|
+
return agentEvent.agentId.startsWith('production-');
|
|
444
|
+
}
|
|
445
|
+
return true;
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Seulement les événements filtrés passent
|
|
449
|
+
filteredEmitter.on('agent:start', (event) => {
|
|
450
|
+
// Seulement les agents de production
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Filtres par Type
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
// Créer des emitters spécialisés
|
|
458
|
+
const workflowEmitter = new FilteredEventEmitter(baseEmitter, (event) =>
|
|
459
|
+
event.type.startsWith('workflow:')
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
const agentEmitter = new FilteredEventEmitter(baseEmitter, (event) =>
|
|
463
|
+
event.type.startsWith('agent:')
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
// Chacun reçoit seulement son type d'événements
|
|
467
|
+
workflowEmitter.on('workflow:start', handleWorkflowStart);
|
|
468
|
+
agentEmitter.on('agent:complete', handleAgentComplete);
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Filtres Complexes
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
const criticalEmitter = new FilteredEventEmitter(baseEmitter, (event) => {
|
|
475
|
+
// Seulement les erreurs
|
|
476
|
+
if (event.type.includes('error')) return true;
|
|
477
|
+
|
|
478
|
+
// Agents lents
|
|
479
|
+
if (event.type === 'agent:complete') {
|
|
480
|
+
const agentEvent = event as AgentCompleteEvent;
|
|
481
|
+
return agentEvent.duration > 10000;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Workflows échoués
|
|
485
|
+
if (event.type === 'workflow:complete') {
|
|
486
|
+
const wfEvent = event as WorkflowCompleteEvent;
|
|
487
|
+
return !wfEvent.result.success;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return false;
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// Monitoring critique seulement
|
|
494
|
+
criticalEmitter.on('*', (event) => {
|
|
495
|
+
alertOpsTeam(event);
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
## Event History
|
|
500
|
+
|
|
501
|
+
### Activer l'Historique
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
const emitter = new SocietyEventEmitter();
|
|
505
|
+
|
|
506
|
+
// Activer avec taille max
|
|
507
|
+
emitter.enableHistory(1000); // Garde 1000 derniers événements
|
|
508
|
+
|
|
509
|
+
// Désactiver
|
|
510
|
+
emitter.disableHistory();
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Accéder à l'Historique
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
// Tous les événements
|
|
517
|
+
const allEvents = emitter.getHistory();
|
|
518
|
+
|
|
519
|
+
// Filtrer par type
|
|
520
|
+
const workflowEvents = emitter.getHistoryByType('workflow:start');
|
|
521
|
+
|
|
522
|
+
// Filtrer par temps
|
|
523
|
+
const recentEvents = emitter.getHistorySince(Date.now() - 60000); // 1 minute
|
|
524
|
+
|
|
525
|
+
// Événements entre deux timestamps
|
|
526
|
+
const events = emitter.getHistoryBetween(startTime, endTime);
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Replay des Événements
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
const history = emitter.getHistory();
|
|
533
|
+
|
|
534
|
+
// Replay dans un nouvel emitter
|
|
535
|
+
const replayEmitter = new SocietyEventEmitter();
|
|
536
|
+
replayEmitter.on('*', logEvent);
|
|
537
|
+
|
|
538
|
+
for (const event of history) {
|
|
539
|
+
replayEmitter.emit(event);
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Clear History
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
// Vider l'historique
|
|
547
|
+
emitter.clearHistory();
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## Intégrations
|
|
551
|
+
|
|
552
|
+
### Event Logger
|
|
553
|
+
|
|
554
|
+
```typescript
|
|
555
|
+
import { EventLogger } from 'societyai';
|
|
556
|
+
|
|
557
|
+
const logger = new EventLogger(emitter, {
|
|
558
|
+
logToConsole: true,
|
|
559
|
+
logToFile: './logs/events.log',
|
|
560
|
+
includeTypes: ['workflow:*', 'agent:error'],
|
|
561
|
+
excludeTypes: ['debug'],
|
|
562
|
+
formatter: (event) => {
|
|
563
|
+
return `[${new Date(event.timestamp).toISOString()}] ${event.type}`;
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// Les événements sont automatiquement loggés
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Event Aggregator
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
import { EventAggregator } from 'societyai';
|
|
574
|
+
|
|
575
|
+
const aggregator = new EventAggregator(emitter);
|
|
576
|
+
|
|
577
|
+
// Agréger sur une période
|
|
578
|
+
aggregator.startAggregation({
|
|
579
|
+
windowSize: 60000, // 1 minute
|
|
580
|
+
onAggregated: (summary) => {
|
|
581
|
+
console.log('Events in last minute:', summary.total);
|
|
582
|
+
console.log('By type:', summary.byType);
|
|
583
|
+
console.log('Errors:', summary.errors);
|
|
584
|
+
},
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// Récupérer le résumé
|
|
588
|
+
const summary = aggregator.getSummary();
|
|
589
|
+
console.log(`Total workflows: ${summary.workflows}`);
|
|
590
|
+
console.log(`Total agents: ${summary.agents}`);
|
|
591
|
+
console.log(`Average duration: ${summary.avgDuration}ms`);
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### Intégration avec Society
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
import { Society, createEventEmitter } from 'societyai';
|
|
598
|
+
|
|
599
|
+
const emitter = createEventEmitter();
|
|
600
|
+
|
|
601
|
+
// Logger tous les événements
|
|
602
|
+
emitter.on('*', (event) => {
|
|
603
|
+
console.log(`[${event.type}]`, event);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
// Tracker la progression
|
|
607
|
+
emitter.on('progress', (event) => {
|
|
608
|
+
updateUI(event.percent, event.phase);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// Utiliser avec Society
|
|
612
|
+
const result = await Society.create()
|
|
613
|
+
.withName('Event-Tracked Society')
|
|
614
|
+
.withEvents(emitter) // Attacher l'emitter
|
|
615
|
+
.addAgent(/* ... */)
|
|
616
|
+
.execute(input);
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
## Exemples Complets
|
|
620
|
+
|
|
621
|
+
### Exemple 1: Monitoring Complet
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
import { SocietyEventEmitter, ProgressTracker, EventLogger, Society } from 'societyai';
|
|
625
|
+
|
|
626
|
+
// Configuration du monitoring
|
|
627
|
+
const emitter = new SocietyEventEmitter().enableHistory(500);
|
|
628
|
+
|
|
629
|
+
const tracker = new ProgressTracker(emitter);
|
|
630
|
+
const logger = new EventLogger(emitter, {
|
|
631
|
+
logToFile: './logs/workflow.log',
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
// Métriques
|
|
635
|
+
const metrics = {
|
|
636
|
+
workflows: 0,
|
|
637
|
+
agents: 0,
|
|
638
|
+
errors: 0,
|
|
639
|
+
totalDuration: 0,
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
emitter.on('workflow:start', (event) => {
|
|
643
|
+
metrics.workflows++;
|
|
644
|
+
console.log(`📊 Starting workflow: ${event.workflowName}`);
|
|
645
|
+
tracker.start(event.workflowId, {
|
|
646
|
+
totalSteps: event.agentCount,
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
emitter.on('agent:start', (event) => {
|
|
651
|
+
metrics.agents++;
|
|
652
|
+
console.log(`🤖 Agent ${event.agentId} processing...`);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
emitter.on('agent:complete', (event) => {
|
|
656
|
+
console.log(`✅ Agent ${event.agentId} done in ${event.duration}ms`);
|
|
657
|
+
tracker.updateProgress(event.agentId, {
|
|
658
|
+
current: metrics.agents,
|
|
659
|
+
phase: `Agent ${event.agentId} completed`,
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
emitter.on('agent:error', (event) => {
|
|
664
|
+
metrics.errors++;
|
|
665
|
+
console.error(`❌ Agent ${event.agentId} failed:`, event.error);
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
emitter.on('workflow:complete', (event) => {
|
|
669
|
+
metrics.totalDuration += event.duration;
|
|
670
|
+
const avgDuration = metrics.totalDuration / metrics.workflows;
|
|
671
|
+
|
|
672
|
+
console.log(`
|
|
673
|
+
🎉 Workflow Complete!
|
|
674
|
+
Duration: ${event.duration}ms
|
|
675
|
+
Success: ${event.result.success}
|
|
676
|
+
Average: ${avgDuration.toFixed(0)}ms
|
|
677
|
+
Total Agents: ${metrics.agents}
|
|
678
|
+
Errors: ${metrics.errors}
|
|
679
|
+
`);
|
|
680
|
+
|
|
681
|
+
tracker.complete(event.workflowId);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// Utiliser avec Society
|
|
685
|
+
const result = await Society.create()
|
|
686
|
+
.withName('Monitored Workflow')
|
|
687
|
+
.withEvents(emitter)
|
|
688
|
+
.addAgent(/* ... */)
|
|
689
|
+
.execute(input);
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Exemple 2: Dashboard en Temps Réel
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
interface DashboardState {
|
|
696
|
+
activeWorkflows: Map<string, WorkflowInfo>;
|
|
697
|
+
completedWorkflows: number;
|
|
698
|
+
failedWorkflows: number;
|
|
699
|
+
activeAgents: Set<string>;
|
|
700
|
+
lastEvents: SocietyEvent[];
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
class WorkflowDashboard {
|
|
704
|
+
private state: DashboardState = {
|
|
705
|
+
activeWorkflows: new Map(),
|
|
706
|
+
completedWorkflows: 0,
|
|
707
|
+
failedWorkflows: 0,
|
|
708
|
+
activeAgents: new Set(),
|
|
709
|
+
lastEvents: [],
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
constructor(private emitter: SocietyEventEmitter) {
|
|
713
|
+
this.setupListeners();
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
private setupListeners() {
|
|
717
|
+
this.emitter.on('workflow:start', (event) => {
|
|
718
|
+
this.state.activeWorkflows.set(event.workflowId, {
|
|
719
|
+
id: event.workflowId,
|
|
720
|
+
name: event.workflowName,
|
|
721
|
+
startTime: event.timestamp,
|
|
722
|
+
agentCount: event.agentCount,
|
|
723
|
+
completedAgents: 0,
|
|
724
|
+
});
|
|
725
|
+
this.update();
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
this.emitter.on('agent:start', (event) => {
|
|
729
|
+
this.state.activeAgents.add(event.agentId);
|
|
730
|
+
this.update();
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
this.emitter.on('agent:complete', (event) => {
|
|
734
|
+
this.state.activeAgents.delete(event.agentId);
|
|
735
|
+
|
|
736
|
+
// Mettre à jour le workflow
|
|
737
|
+
for (const workflow of this.state.activeWorkflows.values()) {
|
|
738
|
+
workflow.completedAgents++;
|
|
739
|
+
}
|
|
740
|
+
this.update();
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
this.emitter.on('workflow:complete', (event) => {
|
|
744
|
+
this.state.activeWorkflows.delete(event.workflowId);
|
|
745
|
+
if (event.result.success) {
|
|
746
|
+
this.state.completedWorkflows++;
|
|
747
|
+
} else {
|
|
748
|
+
this.state.failedWorkflows++;
|
|
749
|
+
}
|
|
750
|
+
this.update();
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
this.emitter.on('*', (event) => {
|
|
754
|
+
this.state.lastEvents.unshift(event);
|
|
755
|
+
if (this.state.lastEvents.length > 10) {
|
|
756
|
+
this.state.lastEvents.pop();
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
private update() {
|
|
762
|
+
// Rafraîchir l'UI
|
|
763
|
+
console.clear();
|
|
764
|
+
console.log('╔══════════════════════════════════════╗');
|
|
765
|
+
console.log('║ SocietyAI Workflow Dashboard ║');
|
|
766
|
+
console.log('╠══════════════════════════════════════╣');
|
|
767
|
+
console.log(`║ Active Workflows: ${this.state.activeWorkflows.size} ║`);
|
|
768
|
+
console.log(`║ Completed: ${this.state.completedWorkflows} ║`);
|
|
769
|
+
console.log(`║ Failed: ${this.state.failedWorkflows} ║`);
|
|
770
|
+
console.log(`║ Active Agents: ${this.state.activeAgents.size} ║`);
|
|
771
|
+
console.log('╠══════════════════════════════════════╣');
|
|
772
|
+
|
|
773
|
+
for (const workflow of this.state.activeWorkflows.values()) {
|
|
774
|
+
const progress = (workflow.completedAgents / workflow.agentCount) * 100;
|
|
775
|
+
const bar = '█'.repeat(progress / 5) + '░'.repeat(20 - progress / 5);
|
|
776
|
+
console.log(`║ ${workflow.name.padEnd(20)} [${bar}] ${progress.toFixed(0)}%`);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
console.log('╚══════════════════════════════════════╝');
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
getState(): DashboardState {
|
|
783
|
+
return this.state;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Utilisation
|
|
788
|
+
const emitter = new SocietyEventEmitter();
|
|
789
|
+
const dashboard = new WorkflowDashboard(emitter);
|
|
790
|
+
|
|
791
|
+
// Exécuter workflows...
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### Exemple 3: Testing avec Event Assertions
|
|
795
|
+
|
|
796
|
+
```typescript
|
|
797
|
+
describe('Workflow Events', () => {
|
|
798
|
+
let emitter: SocietyEventEmitter;
|
|
799
|
+
let events: SocietyEvent[];
|
|
800
|
+
|
|
801
|
+
beforeEach(() => {
|
|
802
|
+
emitter = new SocietyEventEmitter().enableHistory();
|
|
803
|
+
events = [];
|
|
804
|
+
|
|
805
|
+
emitter.on('*', (event) => {
|
|
806
|
+
events.push(event);
|
|
807
|
+
});
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
it('should emit workflow lifecycle events', async () => {
|
|
811
|
+
await Society.create().withEvents(emitter).addAgent(/* ... */).execute('test input');
|
|
812
|
+
|
|
813
|
+
// Vérifier l'ordre des événements
|
|
814
|
+
expect(events[0].type).toBe('workflow:start');
|
|
815
|
+
expect(events[events.length - 1].type).toBe('workflow:complete');
|
|
816
|
+
|
|
817
|
+
// Vérifier qu'on a des événements d'agents
|
|
818
|
+
const agentEvents = events.filter((e) => e.type.startsWith('agent:'));
|
|
819
|
+
expect(agentEvents.length).toBeGreaterThan(0);
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
it('should emit error events on failure', async () => {
|
|
823
|
+
// Agent qui échoue
|
|
824
|
+
const failingModel = {
|
|
825
|
+
name: () => 'FailingModel',
|
|
826
|
+
process: async () => {
|
|
827
|
+
throw new Error('Test error');
|
|
828
|
+
},
|
|
829
|
+
supportsPromptType: () => true,
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
try {
|
|
833
|
+
await Society.create()
|
|
834
|
+
.withEvents(emitter)
|
|
835
|
+
.addAgent((a) =>
|
|
836
|
+
a
|
|
837
|
+
.withId('failing')
|
|
838
|
+
.withRole((r) => r.withSystemPrompt('test'))
|
|
839
|
+
.withModel(failingModel)
|
|
840
|
+
)
|
|
841
|
+
.execute('test');
|
|
842
|
+
} catch (e) {
|
|
843
|
+
// Expected
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const errorEvents = events.filter((e) => e.type.includes('error'));
|
|
847
|
+
expect(errorEvents.length).toBeGreaterThan(0);
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
### Exemple 4: Audit Trail
|
|
853
|
+
|
|
854
|
+
```typescript
|
|
855
|
+
class AuditTrail {
|
|
856
|
+
private db: Database;
|
|
857
|
+
|
|
858
|
+
constructor(private emitter: SocietyEventEmitter) {
|
|
859
|
+
this.setupAuditLogging();
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
private setupAuditLogging() {
|
|
863
|
+
// Logger tous les événements importants
|
|
864
|
+
const auditEvents = [
|
|
865
|
+
'workflow:start',
|
|
866
|
+
'workflow:complete',
|
|
867
|
+
'workflow:error',
|
|
868
|
+
'agent:start',
|
|
869
|
+
'agent:complete',
|
|
870
|
+
'agent:error',
|
|
871
|
+
];
|
|
872
|
+
|
|
873
|
+
for (const eventType of auditEvents) {
|
|
874
|
+
this.emitter.on(eventType as any, async (event) => {
|
|
875
|
+
await this.logToDatabase(event);
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
private async logToDatabase(event: SocietyEvent) {
|
|
881
|
+
await this.db.auditLogs.insert({
|
|
882
|
+
eventType: event.type,
|
|
883
|
+
timestamp: event.timestamp,
|
|
884
|
+
correlationId: event.correlationId,
|
|
885
|
+
data: JSON.stringify(event),
|
|
886
|
+
userId: getCurrentUser()?.id,
|
|
887
|
+
sessionId: getCurrentSession()?.id,
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
async getAuditLog(workflowId: string): Promise<AuditLog[]> {
|
|
892
|
+
return await this.db.auditLogs
|
|
893
|
+
.query()
|
|
894
|
+
.where('correlationId', workflowId)
|
|
895
|
+
.orderBy('timestamp', 'asc')
|
|
896
|
+
.all();
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
async searchAudit(criteria: AuditSearchCriteria): Promise<AuditLog[]> {
|
|
900
|
+
let query = this.db.auditLogs.query();
|
|
901
|
+
|
|
902
|
+
if (criteria.eventType) {
|
|
903
|
+
query = query.where('eventType', criteria.eventType);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (criteria.dateRange) {
|
|
907
|
+
query = query
|
|
908
|
+
.where('timestamp', '>=', criteria.dateRange.start)
|
|
909
|
+
.where('timestamp', '<=', criteria.dateRange.end);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (criteria.userId) {
|
|
913
|
+
query = query.where('userId', criteria.userId);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
return await query.all();
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
## Bonnes Pratiques
|
|
922
|
+
|
|
923
|
+
### 1. Gestion des Erreurs dans les Handlers
|
|
924
|
+
|
|
925
|
+
```typescript
|
|
926
|
+
// ✅ Bon - handler avec try-catch
|
|
927
|
+
emitter.on('workflow:complete', async (event) => {
|
|
928
|
+
try {
|
|
929
|
+
await saveResults(event.result);
|
|
930
|
+
} catch (error) {
|
|
931
|
+
console.error('Failed to save results:', error);
|
|
932
|
+
// Ne pas propager l'erreur
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
// ❌ Mauvais - erreurs non gérées
|
|
937
|
+
emitter.on('workflow:complete', async (event) => {
|
|
938
|
+
await saveResults(event.result); // Peut throw
|
|
939
|
+
});
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
### 2. Nettoyage des Listeners
|
|
943
|
+
|
|
944
|
+
```typescript
|
|
945
|
+
// ✅ Bon - détacher quand fini
|
|
946
|
+
class WorkflowMonitor {
|
|
947
|
+
private handler: EventHandler<WorkflowCompleteEvent>;
|
|
948
|
+
|
|
949
|
+
start(emitter: SocietyEventEmitter) {
|
|
950
|
+
this.handler = (event) => this.handle(event);
|
|
951
|
+
emitter.on('workflow:complete', this.handler);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
stop(emitter: SocietyEventEmitter) {
|
|
955
|
+
emitter.off('workflow:complete', this.handler);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
### 3. Corrélation des Événements
|
|
961
|
+
|
|
962
|
+
```typescript
|
|
963
|
+
// ✅ Bon - utiliser correlationId
|
|
964
|
+
const correlationId = generateId();
|
|
965
|
+
|
|
966
|
+
emitter.setCorrelationId(correlationId);
|
|
967
|
+
|
|
968
|
+
// Tous les événements auront le même correlationId
|
|
969
|
+
await workflow.execute(input);
|
|
970
|
+
|
|
971
|
+
// Récupérer tous les événements liés
|
|
972
|
+
const related = emitter.getHistory().filter((e) => e.correlationId === correlationId);
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
### 4. Performance
|
|
976
|
+
|
|
977
|
+
```typescript
|
|
978
|
+
// ✅ Bon - handlers légers
|
|
979
|
+
emitter.on('progress', (event) => {
|
|
980
|
+
// Rapide
|
|
981
|
+
progressBar.update(event.percent);
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// ❌ Mauvais - handlers lourds
|
|
985
|
+
emitter.on('progress', async (event) => {
|
|
986
|
+
// Lent - bloque l'émission
|
|
987
|
+
await heavyDatabaseOperation(event);
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// ✅ Mieux - async mais non-bloquant
|
|
991
|
+
emitter.on('progress', (event) => {
|
|
992
|
+
// Fire and forget
|
|
993
|
+
heavyDatabaseOperation(event).catch(console.error);
|
|
994
|
+
});
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
## API Reference
|
|
998
|
+
|
|
999
|
+
### `SocietyEventEmitter`
|
|
1000
|
+
|
|
1001
|
+
**Méthodes:**
|
|
1002
|
+
|
|
1003
|
+
- `on<K>(type: K, handler: EventHandler<T>): this` - Écouter un événement
|
|
1004
|
+
- `once<K>(type: K, handler: EventHandler<T>): this` - Écouter une fois
|
|
1005
|
+
- `off<K>(type: K, handler: EventHandler<T>): this` - Détacher un handler
|
|
1006
|
+
- `emit(event: SocietyEvent): void` - Émettre un événement
|
|
1007
|
+
- `enableHistory(maxSize?: number): this` - Activer l'historique
|
|
1008
|
+
- `disableHistory(): this` - Désactiver l'historique
|
|
1009
|
+
- `getHistory(): SocietyEvent[]` - Récupérer l'historique
|
|
1010
|
+
- `clearHistory(): void` - Vider l'historique
|
|
1011
|
+
- `removeAllListeners(type?: string): this` - Détacher tous les handlers
|
|
1012
|
+
|
|
1013
|
+
### `ProgressTracker`
|
|
1014
|
+
|
|
1015
|
+
**Méthodes:**
|
|
1016
|
+
|
|
1017
|
+
- `start(id: string, config: ProgressConfig): void` - Démarrer le tracking
|
|
1018
|
+
- `updateProgress(id: string, update: ProgressUpdate): void` - Mettre à jour
|
|
1019
|
+
- `complete(id: string): void` - Compléter
|
|
1020
|
+
- `fail(id: string, error: Error): void` - Marquer comme échoué
|
|
1021
|
+
|
|
1022
|
+
### `FilteredEventEmitter`
|
|
1023
|
+
|
|
1024
|
+
**Constructeur:**
|
|
1025
|
+
|
|
1026
|
+
- `new FilteredEventEmitter(source: SocietyEventEmitter, filter: EventFilter<SocietyEvent>)`
|
|
1027
|
+
|
|
1028
|
+
### `EventLogger`
|
|
1029
|
+
|
|
1030
|
+
**Constructeur:**
|
|
1031
|
+
|
|
1032
|
+
- `new EventLogger(emitter: SocietyEventEmitter, options: EventLoggerOptions)`
|
|
1033
|
+
|
|
1034
|
+
### `EventAggregator`
|
|
1035
|
+
|
|
1036
|
+
**Méthodes:**
|
|
1037
|
+
|
|
1038
|
+
- `startAggregation(config: AggregationConfig): void` - Démarrer l'agrégation
|
|
1039
|
+
- `stopAggregation(): void` - Arrêter
|
|
1040
|
+
- `getSummary(): EventSummary` - Récupérer le résumé
|
|
1041
|
+
|
|
1042
|
+
## Voir Aussi
|
|
1043
|
+
|
|
1044
|
+
- [Architecture](./architecture.md) - Concepts de base
|
|
1045
|
+
- [Workflows](./workflows.md) - Intégration avec les workflows
|
|
1046
|
+
- [Metrics & Observability](./metrics-observability.md) - Métriques et monitoring
|
|
1047
|
+
- [Advanced Features](./advanced.md) - Fonctionnalités avancées
|