@ai.ntellect/core 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/create-llm-to-select-multiple-graph copy.ts +243 -0
  2. package/create-llm-to-select-multiple-graph.ts +148 -0
  3. package/dist/create-llm-to-select-multiple-graph copy.js +201 -0
  4. package/dist/create-llm-to-select-multiple-graph.js +142 -0
  5. package/dist/graph/controller.js +6 -6
  6. package/dist/graph/engine.js +198 -135
  7. package/dist/index copy.js +76 -0
  8. package/dist/utils/setup-graphs.js +28 -0
  9. package/dist/utils/stringifiy-zod-schema.js +41 -0
  10. package/graph/controller.ts +11 -9
  11. package/graph/engine.ts +244 -166
  12. package/index copy.ts +81 -0
  13. package/index.ts +1 -1
  14. package/package.json +1 -1
  15. package/test/graph/engine.test.ts +27 -44
  16. package/tsconfig.json +1 -1
  17. package/types/index.ts +11 -3
  18. package/utils/setup-graphs.ts +45 -0
  19. package/utils/stringifiy-zod-schema.ts +45 -0
  20. package/dist/test/graph/controller.test.js +0 -170
  21. package/dist/test/graph/engine.test.js +0 -465
  22. package/dist/test/memory/adapters/meilisearch.test.js +0 -250
  23. package/dist/test/memory/adapters/redis.test.js +0 -143
  24. package/dist/test/memory/base.test.js +0 -209
  25. package/dist/test/services/agenda.test.js +0 -230
  26. package/dist/test/services/queue.test.js +0 -258
  27. package/dist/utils/schema-generator.js +0 -46
  28. package/dist/utils/state-manager.js +0 -20
  29. package/utils/generate-object.js +0 -111
  30. package/utils/header-builder.js +0 -34
  31. package/utils/inject-actions.js +0 -16
  32. package/utils/queue-item-transformer.js +0 -24
  33. package/utils/sanitize-results.js +0 -60
  34. package/utils/schema-generator.js +0 -46
  35. package/utils/schema-generator.ts +0 -73
  36. package/utils/state-manager.js +0 -20
  37. package/utils/state-manager.ts +0 -30
package/graph/engine.ts CHANGED
@@ -1,11 +1,8 @@
1
1
  import { Persistence, RealTimeNotifier } from "@/interfaces";
2
- import { GraphDefinition, Node, NodeRelationship, SharedState } from "@/types";
3
- import { configDotenv } from "dotenv";
2
+ import { GraphDefinition, Node, SharedState } from "@/types";
4
3
  import EventEmitter from "events";
5
4
  import { z } from "zod";
6
5
 
7
- configDotenv();
8
-
9
6
  interface GraphOptions<T> {
10
7
  initialState?: SharedState<T>;
11
8
  schema?: z.ZodSchema<T>;
@@ -13,44 +10,43 @@ interface GraphOptions<T> {
13
10
  }
14
11
 
15
12
  /**
16
- * Represents a directed worflow structure capable of executing nodes in sequence or parallel.
17
- * The worflow can handle state management, event emissions, and conditional execution paths.
13
+ * Représente un workflow dirigé capable d’exécuter des noeuds en séquence ou en parallèle.
18
14
  *
19
- * @template T - The type of data stored in the worflow's context
15
+ * @template T - Le type de données stockées dans le contexte du workflow
20
16
  */
21
17
  export class GraphEngine<T> {
22
- /** Stores global context data accessible to all nodes */
18
+ /** Données globales accessibles à tous les nœuds */
23
19
  public globalContext: Map<string, any>;
24
20
 
25
- /** Event emitter for handling worflow-wide events */
21
+ /** Event emitter pour gérer les événements du workflow */
26
22
  private eventEmitter: EventEmitter;
27
23
 
28
- /** Map of all nodes in the worflow */
24
+ /** Map de tous les nœuds du workflow */
29
25
  public nodes: Map<string, Node<T>>;
30
26
 
31
- /** Set of nodes that have been executed */
27
+ /** Ensemble des nœuds déjà exécutés */
32
28
  public executedNodes: Set<string>;
33
29
 
34
- /** Name identifier for the worflow */
30
+ /** Nom du workflow */
35
31
  public name: string;
36
32
 
37
- /** Optional persistence layer for saving worflow state */
33
+ /** Couche de persistance optionnelle pour sauvegarder l'état du workflow */
38
34
  private persistence: Persistence<T> | null;
39
35
 
40
- /** Optional notifier for real-time updates */
36
+ /** Notifier en temps réel optionnel */
41
37
  private notifier: RealTimeNotifier | null;
42
38
 
39
+ /** Schéma global Zod pour valider l’état ou le contexte du workflow */
43
40
  private schema?: z.ZodSchema<T>;
44
41
 
42
+ /** État interne actuel du workflow */
45
43
  private currentState: SharedState<T>;
46
44
 
47
45
  /**
48
- * Creates a new Graph instance.
46
+ * Crée une nouvelle instance de GraphEngine.
49
47
  *
50
- * @param {GraphDefinition<T>} [definition] - Initial worflow structure and configuration
51
- * @param {Object} [config] - Additional configuration options
52
- * @param {boolean} [config.autoDetectCycles] - Whether to check for cycles during initialization
53
- * @throws {Error} If cycles are detected when autoDetectCycles is true
48
+ * @param {GraphDefinition<T>} [definition] - La définition initiale du workflow
49
+ * @param {GraphOptions<T>} [options] - Options de configuration
54
50
  */
55
51
  constructor(definition?: GraphDefinition<T>, options?: GraphOptions<T>) {
56
52
  this.name = definition?.name || "anonymous";
@@ -61,14 +57,14 @@ export class GraphEngine<T> {
61
57
  this.persistence = null;
62
58
  this.notifier = null;
63
59
  this.schema = options?.schema;
64
- this.currentState = { context: {} } as SharedState<T>;
60
+ this.currentState = {} as SharedState<T>;
65
61
 
66
62
  if (definition) {
67
63
  this.loadFromDefinition(definition);
68
64
  }
69
65
 
70
66
  if (options?.autoDetectCycles && this.checkForCycles()) {
71
- throw new Error("Cycle detected in the workflow");
67
+ throw new Error("Cycle détecté dans le workflow");
72
68
  }
73
69
 
74
70
  if (options?.initialState) {
@@ -77,68 +73,63 @@ export class GraphEngine<T> {
77
73
  }
78
74
 
79
75
  /**
80
- * Adds a value to the global context.
81
- * @param {string} key - The key to store the value under
82
- * @param {any} value - The value to store
76
+ * Ajoute un élément au contexte global.
77
+ * @param {string} key - La clé
78
+ * @param {any} value - La valeur
83
79
  */
84
80
  addToContext(key: string, value: any): void {
85
81
  this.globalContext.set(key, value);
86
82
  }
87
83
 
88
84
  /**
89
- * Retrieves a value from the global context.
90
- * @param {string} key - The key to retrieve
91
- * @returns {any} The stored value, or undefined if not found
85
+ * Récupère un élément du contexte global.
86
+ * @param {string} key - La clé
92
87
  */
93
88
  getContext(key: string): any {
94
89
  return this.globalContext.get(key);
95
90
  }
96
91
 
97
92
  /**
98
- * Removes a value from the global context.
99
- * @param {string} key - The key to remove
93
+ * Supprime un élément du contexte global.
94
+ * @param {string} key - La clé
100
95
  */
101
96
  removeFromContext(key: string): void {
102
97
  this.globalContext.delete(key);
103
98
  }
104
99
 
105
100
  /**
106
- * Sets the persistence layer for the worflow.
107
- * @param {Persistence<T>} persistence - The persistence implementation
101
+ * Définit la couche de persistance.
102
+ * @param {Persistence<T>} persistence
108
103
  */
109
104
  setPersistence(persistence: Persistence<T>): void {
110
105
  this.persistence = persistence;
111
106
  }
112
107
 
113
108
  /**
114
- * Sets the real-time notifier for the worflow.
115
- * @param {RealTimeNotifier} notifier - The notifier implementation
109
+ * Définit le notifier en temps réel.
110
+ * @param {RealTimeNotifier} notifier
116
111
  */
117
112
  setNotifier(notifier: RealTimeNotifier): void {
118
113
  this.notifier = notifier;
119
114
  }
120
115
 
121
116
  /**
122
- * Loads a worflow structure from a definition object.
117
+ * Charge un workflow à partir d'une définition.
123
118
  * @private
124
- * @param {GraphDefinition<T>} definition - The worflow definition
119
+ * @param {GraphDefinition<T>} definition
125
120
  */
126
121
  private loadFromDefinition(definition: GraphDefinition<T>): void {
127
122
  Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
128
- this.addNode(nodeConfig, {
129
- condition: nodeConfig.condition,
130
- relationships: nodeConfig.relationships,
131
- });
123
+ this.addNode(nodeConfig);
132
124
  });
133
125
  }
134
126
 
135
127
  /**
136
- * Recursively checks if a node is part of a cycle.
137
- * @private
138
- * @param {string} nodeName - The name of the node to check
139
- * @param {Set<string>} visited - Set of visited nodes
140
- * @param {Set<string>} recStack - Set of nodes in the current recursion stack
141
- * @returns {boolean} True if a cycle is detected, false otherwise
128
+ * Vérifie récursivement s’il existe un cycle dans le workflow.
129
+ * @param {string} nodeName
130
+ * @param {Set<string>} visited
131
+ * @param {Set<string>} recStack
132
+ * @returns {boolean}
142
133
  */
143
134
  private isCyclic(
144
135
  nodeName: string,
@@ -169,8 +160,8 @@ export class GraphEngine<T> {
169
160
  }
170
161
 
171
162
  /**
172
- * Checks if the worflow contains any cycles.
173
- * @returns {boolean} True if cycles are detected, false otherwise
163
+ * Vérifie si le workflow contient des cycles.
164
+ * @returns {boolean}
174
165
  */
175
166
  public checkForCycles(): boolean {
176
167
  const visited = new Set<string>();
@@ -185,30 +176,18 @@ export class GraphEngine<T> {
185
176
  }
186
177
 
187
178
  /**
188
- * Adds a new node to the worflow.
189
- * @param {Node<T>} node - The node to add
190
- * @param {Object} options - Node configuration options
191
- * @param {Function} [options.condition] - Condition function for node execution
192
- * @param {string[]} [options.relations] - Array of relations node names
193
- * @param {string[]} [options.events] - Array of event names to listen for
179
+ * Ajoute un nouveau nœud au workflow.
180
+ * @param {Node<T>} node
194
181
  */
195
- addNode(
196
- node: Node<T>,
197
- {
198
- condition,
199
- relationships,
200
- events,
201
- }: {
202
- condition?: (state: SharedState<T>) => boolean;
203
- relationships?: NodeRelationship[];
204
- events?: string[];
182
+ addNode(node: Node<T>): void {
183
+ if (node.relationships) {
184
+ node.relationships.forEach((relationship) => {
185
+ this.nodes.get(relationship.name)?.relationships?.push(relationship);
186
+ });
205
187
  }
206
- ): void {
207
- node.relationships = relationships;
208
- node.condition = condition;
209
188
 
210
- if (events) {
211
- events.forEach((event) => {
189
+ if (node.events) {
190
+ node.events.forEach((event) => {
212
191
  this.eventEmitter.on(event, async (data) => {
213
192
  const state = data.state || {};
214
193
  await this.execute(state, node.name);
@@ -220,19 +199,19 @@ export class GraphEngine<T> {
220
199
  }
221
200
 
222
201
  /**
223
- * Emits an event to the worflow's event emitter.
224
- * @param {string} eventName - Name of the event to emit
225
- * @param {any} data - Data to pass with the event
202
+ * Émet un événement sur l'event emitter du workflow.
203
+ * @param {string} eventName
204
+ * @param {any} data
226
205
  */
227
206
  public emit(eventName: string, data: any): void {
228
207
  this.eventEmitter.emit(eventName, data);
229
208
  }
230
209
 
231
210
  /**
232
- * Adds a subworflow as a node in the current worflow.
233
- * @param {Graph<T>} subGraph - The subworflow to add
234
- * @param {string} entryNode - The entry node name in the subworflow
235
- * @param {string} name - The name for the subworflow node
211
+ * Ajoute un sous-graph (GraphEngine) comme un nœud dans le workflow courant.
212
+ * @param {GraphEngine<T>} subGraph
213
+ * @param {string} entryNode - Le nom du nœud de démarrage dans le sous-graph
214
+ * @param {string} name - Le nom symbolique à donner au sous-graph
236
215
  */
237
216
  addSubGraph(subGraph: GraphEngine<T>, entryNode: string, name: string): void {
238
217
  const subGraphNode: Node<T> = {
@@ -246,25 +225,26 @@ export class GraphEngine<T> {
246
225
  }
247
226
 
248
227
  /**
249
- * Executes the worflow starting from a specific node.
250
- * @param {SharedState<T>} state - The initial state
251
- * @param {string} startNode - The name of the starting node
252
- * @param {Function} [onStream] - Callback for streaming state updates
253
- * @param {Function} [onError] - Callback for handling errors
228
+ * Exécute le workflow à partir d’un nœud donné.
229
+ * @param {SharedState<T>} state
230
+ * @param {string} startNode
231
+ * @param {(state: SharedState<T>) => void} [onStream] - Callback sur l’évolution de l’état
232
+ * @param {(error: Error, nodeName: string, state: SharedState<T>) => void} [onError] - Callback sur erreur
254
233
  */
255
234
  async execute(
256
235
  state: SharedState<T>,
257
236
  startNode: string,
258
- onStream?: (state: SharedState<T>) => void,
237
+ onStream?: (graph: GraphEngine<T>) => void,
259
238
  onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
260
239
  ): Promise<SharedState<T>> {
261
240
  try {
241
+ // Valide l'état initial via le schéma global (si défini)
262
242
  if (this.schema) {
263
243
  try {
264
- this.schema.parse(state.context);
244
+ this.schema.parse(state);
265
245
  } catch (error) {
266
246
  const validationError = new Error(
267
- `Initial state validation failed: ${
247
+ `Échec de la validation de l'état initial: ${
268
248
  error instanceof Error ? error.message : error
269
249
  }`
270
250
  );
@@ -279,8 +259,11 @@ export class GraphEngine<T> {
279
259
  while (currentNodeName) {
280
260
  this.executedNodes.add(currentNodeName);
281
261
  const currentNode = this.nodes.get(currentNodeName);
282
- if (!currentNode) throw new Error(`Node ${currentNodeName} not found.`);
262
+ if (!currentNode) {
263
+ throw new Error(`Nœud ${currentNodeName} introuvable.`);
264
+ }
283
265
 
266
+ // Vérification de condition (si présente)
284
267
  if (
285
268
  currentNode.condition &&
286
269
  !currentNode.condition(this.currentState)
@@ -289,6 +272,7 @@ export class GraphEngine<T> {
289
272
  }
290
273
 
291
274
  try {
275
+ // Notifier : début d'exécution du nœud
292
276
  if (this.notifier) {
293
277
  this.notifier.notify("nodeExecutionStarted", {
294
278
  workflow: this.name,
@@ -304,9 +288,10 @@ export class GraphEngine<T> {
304
288
 
305
289
  if (newState) {
306
290
  this.setState(newState);
307
- if (onStream) onStream(this.currentState);
291
+ if (onStream) onStream(this);
308
292
  }
309
293
 
294
+ // Sauvegarde via la persistence (optionnel)
310
295
  if (this.persistence) {
311
296
  await this.persistence.saveState(
312
297
  this.name,
@@ -315,6 +300,7 @@ export class GraphEngine<T> {
315
300
  );
316
301
  }
317
302
 
303
+ // Notifier : fin d'exécution du nœud
318
304
  if (this.notifier) {
319
305
  await this.notifier.notify("nodeExecutionCompleted", {
320
306
  workflow: this.name,
@@ -323,8 +309,9 @@ export class GraphEngine<T> {
323
309
  });
324
310
  }
325
311
  } catch (error) {
326
- if (onError)
312
+ if (onError) {
327
313
  onError(error as Error, currentNodeName, this.currentState);
314
+ }
328
315
  if (this.notifier) {
329
316
  this.notifier.notify("nodeExecutionFailed", {
330
317
  workflow: this.name,
@@ -336,15 +323,19 @@ export class GraphEngine<T> {
336
323
  break;
337
324
  }
338
325
 
326
+ // Gestion des relations (branchements)
339
327
  const relationsNodes = currentNode.relationships || [];
340
328
  if (relationsNodes.length > 1) {
329
+ // Exécution parallèle des branches
341
330
  await Promise.all(
342
331
  relationsNodes.map((relation) =>
343
332
  this.execute(this.currentState, relation.name, onStream, onError)
344
333
  )
345
334
  );
335
+ // Après exécution en parallèle, on arrête la boucle
346
336
  break;
347
337
  } else {
338
+ // Cas normal : un seul chemin
348
339
  currentNodeName = relationsNodes[0]?.name || "";
349
340
  }
350
341
  }
@@ -359,18 +350,16 @@ export class GraphEngine<T> {
359
350
  }
360
351
 
361
352
  /**
362
- * Executes multiple nodes in parallel with a concurrency limit.
363
- * @param {SharedState<T>} state - The shared state
364
- * @param {string[]} nodeNames - Array of node names to execute
365
- * @param {number} [concurrencyLimit=5] - Maximum number of concurrent executions
366
- * @param {Function} [onStream] - Callback for streaming state updates
367
- * @param {Function} [onError] - Callback for handling errors
353
+ * Exécute plusieurs nœuds en parallèle au sein du même workflow, avec une limite de concurrence.
354
+ * @param {SharedState<T>} state
355
+ * @param {string[]} nodeNames
356
+ * @param {number} [concurrencyLimit=5]
368
357
  */
369
358
  async executeParallel(
370
359
  state: SharedState<T>,
371
360
  nodeNames: string[],
372
361
  concurrencyLimit: number = 5,
373
- onStream?: (state: SharedState<T>) => void,
362
+ onStream?: (graph: GraphEngine<T>) => void,
374
363
  onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
375
364
  ): Promise<void> {
376
365
  const executeWithLimit = async (nodeName: string) => {
@@ -388,8 +377,8 @@ export class GraphEngine<T> {
388
377
  }
389
378
 
390
379
  /**
391
- * Updates the worflow structure with a new definition.
392
- * @param {GraphDefinition<T>} definition - The new worflow definition
380
+ * Met à jour le workflow avec une nouvelle définition (mise à jour des nœuds existants ou ajout de nouveaux).
381
+ * @param {GraphDefinition<T>} definition
393
382
  */
394
383
  updateGraph(definition: GraphDefinition<T>): void {
395
384
  Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
@@ -398,18 +387,16 @@ export class GraphEngine<T> {
398
387
  existingNode.relationships =
399
388
  nodeConfig.relationships || existingNode.relationships;
400
389
  existingNode.condition = nodeConfig.condition || existingNode.condition;
390
+ existingNode.events = nodeConfig.events || existingNode.events;
401
391
  } else {
402
- this.addNode(nodeConfig, {
403
- condition: nodeConfig.condition,
404
- relationships: nodeConfig.relationships,
405
- });
392
+ this.addNode(nodeConfig);
406
393
  }
407
394
  });
408
395
  }
409
396
 
410
397
  /**
411
- * Replace the worflow with a new definition.
412
- * @param {GraphDefinition<T>} definition - The new worflow definition
398
+ * Remplace complètement le workflow par une nouvelle définition.
399
+ * @param {GraphDefinition<T>} definition
413
400
  */
414
401
  replaceGraph(definition: GraphDefinition<T>): void {
415
402
  this.nodes.clear();
@@ -417,14 +404,9 @@ export class GraphEngine<T> {
417
404
  }
418
405
 
419
406
  /**
420
- * Generates a visual representation of the worflow using Mermaid diagram syntax.
421
- * The diagram shows all nodes and their connections, with special highlighting for:
422
- * - Entry nodes (green)
423
- * - Event nodes (yellow)
424
- * - Conditional nodes (orange)
425
- *
426
- * @param {string} [title] - Optional title for the diagram
427
- * @returns {string} Mermaid diagram syntax representing the worflow
407
+ * Génère un diagramme Mermaid pour visualiser le workflow.
408
+ * @param {string} [title]
409
+ * @returns {string}
428
410
  */
429
411
  generateMermaidDiagram(title?: string): string {
430
412
  const lines: string[] = ["flowchart TD"];
@@ -433,48 +415,46 @@ export class GraphEngine<T> {
433
415
  lines.push(` subgraph ${title}`);
434
416
  }
435
417
 
436
- // Add nodes with styling
418
+ // Ajout des nœuds
437
419
  this.nodes.forEach((node, nodeName) => {
438
420
  const hasEvents = node.events && node.events.length > 0;
439
421
  const hasCondition = !!node.condition;
440
422
 
441
- // Style nodes based on their properties
423
+ // Style selon les propriétés
442
424
  let style = "";
443
425
  if (hasEvents) {
444
- style = "style " + nodeName + " fill:#FFD700,stroke:#DAA520"; // Yellow for event nodes
426
+ style = "style " + nodeName + " fill:#FFD700,stroke:#DAA520"; // Jaune pour event
445
427
  } else if (hasCondition) {
446
- style = "style " + nodeName + " fill:#FFA500,stroke:#FF8C00"; // Orange for conditional nodes
428
+ style = "style " + nodeName + " fill:#FFA500,stroke:#FF8C00"; // Orange pour condition
447
429
  }
448
430
 
449
- // Add node definition
450
431
  lines.push(` ${nodeName}[${nodeName}]`);
451
432
  if (style) {
452
433
  lines.push(` ${style}`);
453
434
  }
454
435
  });
455
436
 
456
- // Add connections
437
+ // Ajout des connexions
457
438
  this.nodes.forEach((node, nodeName) => {
458
439
  if (node.relationships) {
459
440
  node.relationships.forEach((relationsNode) => {
460
441
  let connectionStyle = "";
461
442
  if (node.condition) {
462
- connectionStyle = "---|condition|"; // Add label for conditional connections
443
+ connectionStyle = "---|condition|";
463
444
  } else {
464
- connectionStyle = "-->"; // Normal connection
445
+ connectionStyle = "-->";
465
446
  }
466
447
  lines.push(` ${nodeName} ${connectionStyle} ${relationsNode}`);
467
448
  });
468
449
  }
469
450
 
470
- // Add event connections if any
451
+ // Gestion des events
471
452
  if (node.events && node.events.length > 0) {
472
453
  node.events.forEach((event: string) => {
473
454
  const eventNodeId = `${event}_event`;
474
455
  lines.push(` ${eventNodeId}((${event})):::event`);
475
456
  lines.push(` ${eventNodeId} -.->|trigger| ${nodeName}`);
476
457
  });
477
- // Add style class for event nodes
478
458
  lines.push(" classDef event fill:#FFD700,stroke:#DAA520");
479
459
  }
480
460
  });
@@ -487,26 +467,29 @@ export class GraphEngine<T> {
487
467
  }
488
468
 
489
469
  /**
490
- * Renders the worflow visualization using Mermaid syntax.
491
- * This method can be used to visualize the worflow structure in supported environments.
492
- *
493
- * @param {string} [title] - Optional title for the visualization
470
+ * Affiche le diagramme Mermaid dans la console.
471
+ * @param {string} [title]
494
472
  */
495
473
  visualize(title?: string): void {
496
474
  const diagram = this.generateMermaidDiagram(title);
497
475
  console.log(
498
- "To visualize this worflow, use a Mermaid-compatible renderer with this syntax:"
476
+ "Pour visualiser ce workflow, utilisez un rendu compatible Mermaid avec la syntaxe suivante :"
499
477
  );
500
478
  console.log("\n```mermaid");
501
479
  console.log(diagram);
502
480
  console.log("```\n");
503
481
  }
504
482
 
505
- exportGraphToJson<T>(worflow: GraphDefinition<T>): string {
483
+ /**
484
+ * Exporte la définition du workflow au format JSON (pour debug ou documentation).
485
+ * @param {GraphDefinition<T>} workflow
486
+ * @returns {string} JSON string
487
+ */
488
+ exportGraphToJson(workflow: GraphDefinition<T>): string {
506
489
  const result = {
507
- worflowName: worflow.name,
508
- entryNode: worflow.entryNode,
509
- nodes: Object.entries(worflow.nodes).reduce((acc, [key, node]) => {
490
+ workflowName: workflow.name,
491
+ entryNode: workflow.entryNode,
492
+ nodes: Object.entries(workflow.nodes).reduce((acc, [key, node]) => {
510
493
  acc[key] = {
511
494
  name: node.name,
512
495
  description: node.description || "No description provided",
@@ -521,10 +504,8 @@ export class GraphEngine<T> {
521
504
  }
522
505
 
523
506
  /**
524
- * Generates a visual representation of the workflow schema.
525
- * Displays the structure of the data expected for each node.
526
- *
527
- * @returns {string} A formatted string describing the workflow schema
507
+ * Génère une représentation textuelle (console) du schéma du workflow.
508
+ * @returns {string}
528
509
  */
529
510
  visualizeSchema(): string {
530
511
  const output: string[] = [];
@@ -532,6 +513,7 @@ export class GraphEngine<T> {
532
513
  output.push(`📋 Graph: ${this.name}`);
533
514
  output.push("=".repeat(50));
534
515
 
516
+ // Schéma global
535
517
  if (this.schema) {
536
518
  output.push("🔷 Global Schema:");
537
519
  output.push("-".repeat(30));
@@ -547,6 +529,7 @@ export class GraphEngine<T> {
547
529
  output.push("");
548
530
  }
549
531
 
532
+ // Détails des nœuds
550
533
  output.push("🔷 Nodes:");
551
534
  output.push("-".repeat(30));
552
535
 
@@ -557,7 +540,8 @@ export class GraphEngine<T> {
557
540
  );
558
541
 
559
542
  if (node.relationships && node.relationships.length > 0) {
560
- output.push(`Next nodes: ${node.relationships.join(", ")}`);
543
+ const rels = node.relationships.map((r) => r.name).join(", ");
544
+ output.push(`Next nodes: ${rels}`);
561
545
  }
562
546
 
563
547
  output.push("");
@@ -567,7 +551,10 @@ export class GraphEngine<T> {
567
551
  }
568
552
 
569
553
  /**
570
- * Recursively describes a Zod type.
554
+ * Décrit récursivement un type Zod pour l'affichage.
555
+ * @param {z.ZodType} type
556
+ * @param {number} indent
557
+ * @returns {string}
571
558
  */
572
559
  public describeZodType(type: z.ZodType, indent: number = 0): string {
573
560
  const padding = " ".repeat(indent);
@@ -623,38 +610,35 @@ export class GraphEngine<T> {
623
610
  }
624
611
 
625
612
  /**
626
- * Updates the state of a node.
627
- * @param {SharedState<T>} state - The current state
628
- * @param {Partial<T>} updates - The updates to apply
629
- * @returns {SharedState<T>} The updated state
613
+ * Met à jour le contexte du workflow pour un nœud, en renvoyant un nouvel état.
614
+ * @param {SharedState<T>} state
615
+ * @param {Partial<T>} updates
616
+ * @returns {SharedState<T>}
630
617
  */
631
618
  protected updateNodeState(state: SharedState<T>, updates: Partial<T>) {
632
619
  return {
633
620
  ...state,
634
- context: {
635
- ...(state.context || {}),
636
- ...updates,
637
- },
621
+ ...updates,
638
622
  };
639
623
  }
640
624
 
641
625
  /**
642
- * Retrieves the current state of the workflow.
643
- * @returns {SharedState<T>} The current state
626
+ * Récupère l'état courant du workflow.
627
+ * @returns {SharedState<T>}
644
628
  */
645
629
  public getState(): SharedState<T> {
646
630
  return this.currentState;
647
631
  }
648
632
 
649
633
  /**
650
- * Sets the state of the workflow.
651
- * @param {Partial<SharedState<T>>} state - The new state
634
+ * Définit le nouvel état courant du workflow et met à jour le contexte global.
635
+ * @param {Partial<SharedState<T>>} state
652
636
  */
653
637
  public setState(state: Partial<SharedState<T>>): void {
654
638
  this.currentState = this.mergeStates(this.currentState, state);
655
639
 
656
- if (state.context) {
657
- Object.entries(state.context).forEach(([key, value]) => {
640
+ if (state) {
641
+ Object.entries(state).forEach(([key, value]) => {
658
642
  this.globalContext.set(key, value);
659
643
  });
660
644
  }
@@ -664,17 +648,17 @@ export class GraphEngine<T> {
664
648
  if (node) {
665
649
  node.state = {
666
650
  ...(node.state || {}),
667
- ...(state.context || {}),
651
+ ...(state || {}),
668
652
  };
669
653
  }
670
654
  }
671
655
  }
672
656
 
673
657
  /**
674
- * Merges two states.
675
- * @param {SharedState<T>} currentState - The current state
676
- * @param {Partial<SharedState<T>>} newState - The new state
677
- * @returns {SharedState<T>} The merged state
658
+ * Fusionne deux états.
659
+ * @param {SharedState<T>} currentState
660
+ * @param {Partial<SharedState<T>>} newState
661
+ * @returns {SharedState<T>}
678
662
  */
679
663
  private mergeStates(
680
664
  currentState: SharedState<T>,
@@ -682,28 +666,122 @@ export class GraphEngine<T> {
682
666
  ): SharedState<T> {
683
667
  return {
684
668
  ...currentState,
685
- context: {
686
- ...(currentState.context || {}),
687
- ...(newState.context || {}),
688
- },
669
+ ...(newState || {}),
689
670
  };
690
671
  }
691
672
 
692
673
  /**
693
- * Updates the state of the workflow.
694
- * @param {Partial<SharedState<T>>} updates - The updates to apply
695
- * @returns {SharedState<T>} The updated state
674
+ * Met à jour l'état courant et le renvoie.
675
+ * @param {Partial<T>} updates
676
+ * @returns {SharedState<T>}
696
677
  */
697
- public updateState(updates: Partial<SharedState<T>>): SharedState<T> {
678
+ public updateState(updates: Partial<T>): SharedState<T> {
698
679
  const currentState = this.getState();
699
- const newState = {
680
+ const newState: SharedState<T> = {
700
681
  ...currentState,
701
- context: {
702
- ...currentState.context,
703
- ...(updates.context || {}),
704
- },
682
+ ...updates,
705
683
  };
706
684
  this.setState(newState);
707
685
  return newState;
708
686
  }
687
+
688
+ /* =============================================
689
+ = MÉTHODES STATIQUES POUR PLUSIEURS GRAPHES =
690
+ ============================================= */
691
+
692
+ /**
693
+ * Exécute plusieurs GraphEngine en **séquence** (l'un après l'autre).
694
+ * @param graphs Liste des graphes à exécuter
695
+ * @param startNodes Noms des nœuds de départ correspondants
696
+ * @param initialStates États initiaux correspondants
697
+ * @param onStream Callback d'avancement
698
+ * @param onError Callback d'erreur
699
+ * @returns Tableau des états finaux de chaque graphe
700
+ */
701
+ public static async executeGraphsInSequence<U>(
702
+ graphs: GraphEngine<U>[],
703
+ startNodes: string[],
704
+ initialStates: SharedState<U>[],
705
+ onStream?: (graph: GraphEngine<U>) => void,
706
+ onError?: (error: Error, nodeName: string, state: SharedState<U>) => void
707
+ ): Promise<SharedState<U>[]> {
708
+ const finalStates: SharedState<U>[] = [];
709
+
710
+ for (let i = 0; i < graphs.length; i++) {
711
+ const graph = graphs[i];
712
+ const startNode = startNodes[i];
713
+ const initialState = initialStates[i];
714
+ const result = await graph.execute(
715
+ initialState,
716
+ startNode,
717
+ onStream,
718
+ onError
719
+ );
720
+ finalStates.push(result);
721
+ }
722
+
723
+ return finalStates;
724
+ }
725
+
726
+ /**
727
+ * Exécute plusieurs GraphEngine en **parallèle** (sans limite de concurrence).
728
+ * @param graphs Liste des graphes
729
+ * @param startNodes Noms des nœuds de départ
730
+ * @param initialStates États initiaux
731
+ * @param onStream Callback d'avancement
732
+ * @param onError Callback d'erreur
733
+ * @returns Tableau des états finaux de chaque graphe
734
+ */
735
+ public static async executeGraphsInParallel<U>(
736
+ graphs: GraphEngine<U>[],
737
+ startNodes: string[],
738
+ initialStates: SharedState<U>[],
739
+ onStream?: (graph: GraphEngine<U>) => void,
740
+ onError?: (error: Error, nodeName: string, state: SharedState<U>) => void
741
+ ): Promise<SharedState<U>[]> {
742
+ const promises = graphs.map((graph, index) =>
743
+ graph.execute(initialStates[index], startNodes[index], onStream, onError)
744
+ );
745
+ return Promise.all(promises);
746
+ }
747
+
748
+ /**
749
+ * Exécute plusieurs GraphEngine en parallèle **avec une limite de concurrence**.
750
+ * @param graphs Liste des graphes
751
+ * @param startNodes Noms des nœuds de départ
752
+ * @param initialStates États initiaux
753
+ * @param concurrencyLimit Limite de concurrence
754
+ * @param onStream Callback d'avancement
755
+ * @param onError Callback d'erreur
756
+ * @returns Tableau des états finaux de chaque graphe
757
+ */
758
+ public static async executeGraphsWithConcurrencyLimit<U>(
759
+ graphs: GraphEngine<U>[],
760
+ startNodes: string[],
761
+ initialStates: SharedState<U>[],
762
+ concurrencyLimit: number,
763
+ onStream?: (graph: GraphEngine<U>) => void,
764
+ onError?: (error: Error, nodeName: string, state: SharedState<U>) => void
765
+ ): Promise<SharedState<U>[]> {
766
+ const results: SharedState<U>[] = [];
767
+
768
+ for (let i = 0; i < graphs.length; i += concurrencyLimit) {
769
+ const chunkGraphs = graphs.slice(i, i + concurrencyLimit);
770
+ const chunkStartNodes = startNodes.slice(i, i + concurrencyLimit);
771
+ const chunkInitialStates = initialStates.slice(i, i + concurrencyLimit);
772
+
773
+ const chunkPromises = chunkGraphs.map((graph, index) => {
774
+ return graph.execute(
775
+ chunkInitialStates[index],
776
+ chunkStartNodes[index],
777
+ onStream,
778
+ onError
779
+ );
780
+ });
781
+ const chunkResults = await Promise.all(chunkPromises);
782
+ results.push(...chunkResults);
783
+ }
784
+
785
+ return results;
786
+ }
709
787
  }