@ai.ntellect/core 0.7.7 → 1.0.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.
Files changed (111) hide show
  1. package/README.md +158 -81
  2. package/index.ts +462 -22
  3. package/package copy.json +21 -0
  4. package/package.json +9 -44
  5. package/tsconfig.json +108 -22
  6. package/types.ts +62 -0
  7. package/utils/executor.ts +42 -0
  8. package/.mocharc.json +0 -5
  9. package/dist/graph/controller.d.ts +0 -31
  10. package/dist/graph/controller.d.ts.map +0 -1
  11. package/dist/graph/controller.js +0 -71
  12. package/dist/graph/controller.js.map +0 -1
  13. package/dist/graph/event-manager.d.ts +0 -92
  14. package/dist/graph/event-manager.d.ts.map +0 -1
  15. package/dist/graph/event-manager.js +0 -244
  16. package/dist/graph/event-manager.js.map +0 -1
  17. package/dist/graph/index.d.ts +0 -159
  18. package/dist/graph/index.d.ts.map +0 -1
  19. package/dist/graph/index.js +0 -303
  20. package/dist/graph/index.js.map +0 -1
  21. package/dist/graph/logger.d.ts +0 -46
  22. package/dist/graph/logger.d.ts.map +0 -1
  23. package/dist/graph/logger.js +0 -69
  24. package/dist/graph/logger.js.map +0 -1
  25. package/dist/graph/node.d.ts +0 -92
  26. package/dist/graph/node.d.ts.map +0 -1
  27. package/dist/graph/node.js +0 -249
  28. package/dist/graph/node.js.map +0 -1
  29. package/dist/graph/observer.d.ts +0 -113
  30. package/dist/graph/observer.d.ts.map +0 -1
  31. package/dist/graph/observer.js +0 -198
  32. package/dist/graph/observer.js.map +0 -1
  33. package/dist/index.d.ts +0 -26
  34. package/dist/index.d.ts.map +0 -1
  35. package/dist/index.js +0 -42
  36. package/dist/index.js.map +0 -1
  37. package/dist/interfaces/index.d.ts +0 -447
  38. package/dist/interfaces/index.d.ts.map +0 -1
  39. package/dist/interfaces/index.js +0 -75
  40. package/dist/interfaces/index.js.map +0 -1
  41. package/dist/modules/agenda/adapters/node-cron/index.d.ts +0 -17
  42. package/dist/modules/agenda/adapters/node-cron/index.d.ts.map +0 -1
  43. package/dist/modules/agenda/adapters/node-cron/index.js +0 -30
  44. package/dist/modules/agenda/adapters/node-cron/index.js.map +0 -1
  45. package/dist/modules/agenda/index.d.ts +0 -63
  46. package/dist/modules/agenda/index.d.ts.map +0 -1
  47. package/dist/modules/agenda/index.js +0 -141
  48. package/dist/modules/agenda/index.js.map +0 -1
  49. package/dist/modules/embedding/adapters/ai/index.d.ts +0 -29
  50. package/dist/modules/embedding/adapters/ai/index.d.ts.map +0 -1
  51. package/dist/modules/embedding/adapters/ai/index.js +0 -58
  52. package/dist/modules/embedding/adapters/ai/index.js.map +0 -1
  53. package/dist/modules/embedding/index.d.ts +0 -36
  54. package/dist/modules/embedding/index.d.ts.map +0 -1
  55. package/dist/modules/embedding/index.js +0 -60
  56. package/dist/modules/embedding/index.js.map +0 -1
  57. package/dist/modules/memory/adapters/in-memory/index.d.ts +0 -120
  58. package/dist/modules/memory/adapters/in-memory/index.d.ts.map +0 -1
  59. package/dist/modules/memory/adapters/in-memory/index.js +0 -211
  60. package/dist/modules/memory/adapters/in-memory/index.js.map +0 -1
  61. package/dist/modules/memory/adapters/meilisearch/index.d.ts +0 -110
  62. package/dist/modules/memory/adapters/meilisearch/index.d.ts.map +0 -1
  63. package/dist/modules/memory/adapters/meilisearch/index.js +0 -321
  64. package/dist/modules/memory/adapters/meilisearch/index.js.map +0 -1
  65. package/dist/modules/memory/adapters/redis/index.d.ts +0 -82
  66. package/dist/modules/memory/adapters/redis/index.d.ts.map +0 -1
  67. package/dist/modules/memory/adapters/redis/index.js +0 -159
  68. package/dist/modules/memory/adapters/redis/index.js.map +0 -1
  69. package/dist/modules/memory/index.d.ts +0 -67
  70. package/dist/modules/memory/index.d.ts.map +0 -1
  71. package/dist/modules/memory/index.js +0 -104
  72. package/dist/modules/memory/index.js.map +0 -1
  73. package/dist/types/index.d.ts +0 -166
  74. package/dist/types/index.d.ts.map +0 -1
  75. package/dist/types/index.js +0 -3
  76. package/dist/types/index.js.map +0 -1
  77. package/dist/utils/generate-action-schema.d.ts +0 -5
  78. package/dist/utils/generate-action-schema.d.ts.map +0 -1
  79. package/dist/utils/generate-action-schema.js +0 -44
  80. package/dist/utils/generate-action-schema.js.map +0 -1
  81. package/dist/utils/header-builder.d.ts +0 -12
  82. package/dist/utils/header-builder.d.ts.map +0 -1
  83. package/dist/utils/header-builder.js +0 -35
  84. package/dist/utils/header-builder.js.map +0 -1
  85. package/graph/controller.ts +0 -74
  86. package/graph/event-manager.ts +0 -295
  87. package/graph/index.ts +0 -397
  88. package/graph/logger.ts +0 -70
  89. package/graph/node.ts +0 -305
  90. package/graph/observer.ts +0 -368
  91. package/interfaces/index.ts +0 -545
  92. package/modules/agenda/adapters/node-cron/index.ts +0 -25
  93. package/modules/agenda/index.ts +0 -146
  94. package/modules/embedding/adapters/ai/index.ts +0 -42
  95. package/modules/embedding/index.ts +0 -45
  96. package/modules/memory/adapters/in-memory/index.ts +0 -207
  97. package/modules/memory/adapters/meilisearch/index.ts +0 -361
  98. package/modules/memory/adapters/redis/index.ts +0 -164
  99. package/modules/memory/index.ts +0 -93
  100. package/test/graph/controller.test.ts +0 -187
  101. package/test/graph/event-manager.test.ts +0 -72
  102. package/test/graph/index.test.ts +0 -768
  103. package/test/graph/node.test.ts +0 -510
  104. package/test/graph/observer.test.ts +0 -398
  105. package/test/modules/agenda/node-cron.test.ts +0 -307
  106. package/test/modules/memory/adapters/in-memory.test.ts +0 -153
  107. package/test/modules/memory/adapters/meilisearch.test.ts +0 -287
  108. package/test/modules/memory/base.test.ts +0 -230
  109. package/types/index.ts +0 -184
  110. package/utils/generate-action-schema.ts +0 -46
  111. package/utils/header-builder.ts +0 -40
@@ -1,768 +0,0 @@
1
- import { expect, use } from "chai";
2
- import chaiAsPromised from "chai-as-promised";
3
- import EventEmitter from "events";
4
- import sinon from "sinon";
5
- import { z } from "zod";
6
- import { GraphController } from "../../graph/controller";
7
- import { GraphFlow } from "../../graph/index";
8
- import { NodeParams } from "../../graph/node";
9
- import { GraphContext, GraphDefinition, Node } from "../../types";
10
-
11
- use(chaiAsPromised);
12
-
13
- /**
14
- * Test schema definition using Zod for graph context validation
15
- * Defines a schema with:
16
- * - value: numeric value for tracking state changes
17
- * - counter: numeric value for tracking state changes
18
- * - message: string for tracking state changes
19
- * - eventPayload: optional object containing transaction metadata
20
- */
21
- const TestSchema = z.object({
22
- value: z.number().default(0),
23
- counter: z.number().default(0),
24
- message: z.string().default(""),
25
- eventPayload: z
26
- .object({
27
- transactionId: z.string().optional(),
28
- status: z.string().optional(),
29
- })
30
- .optional(),
31
- });
32
-
33
- type TestSchema = typeof TestSchema;
34
-
35
- /**
36
- * Test suite for the Graph Flow implementation
37
- * This suite validates the core functionality of the graph-based workflow system:
38
- * - Node execution and state management through context
39
- * - Event handling (emission, correlation, waiting)
40
- * - Error handling and retry mechanisms
41
- * - Input/Output validation using Zod schemas
42
- * - Complex workflows with multiple branches and conditions
43
- * - Parallel and sequential execution patterns
44
- *
45
- * The tests use a simple numeric value-based context to demonstrate state changes
46
- * and a transaction-based event payload for testing event correlation.
47
- */
48
- describe("GraphFlow", function () {
49
- let graph: GraphFlow<TestSchema>;
50
- let eventEmitter: EventEmitter;
51
-
52
- beforeEach(() => {
53
- eventEmitter = new EventEmitter();
54
- graph = new GraphFlow("TestGraph", {
55
- name: "TestGraph",
56
- nodes: [],
57
- context: { value: 0 },
58
- schema: TestSchema,
59
- eventEmitter: eventEmitter,
60
- });
61
- });
62
-
63
- /**
64
- * Tests basic node execution and context update functionality
65
- * Validates that:
66
- * - A node can be added to the graph
67
- * - The node's execute function is called
68
- * - The context is properly updated
69
- * - The updated context is accessible after execution
70
- */
71
- it("should execute a simple node and update the context", async function () {
72
- const simpleNode: Node<TestSchema> = {
73
- name: "simpleNode",
74
- execute: async (context) => {
75
- context.value = (context.value ?? 0) + 1;
76
- },
77
- next: [],
78
- };
79
-
80
- graph.addNode(simpleNode);
81
- await graph.execute("simpleNode");
82
-
83
- const context = graph.getContext();
84
- expect(context.value).to.equal(1);
85
- });
86
-
87
- /**
88
- * Tests event emission for node lifecycle events
89
- * Validates that the graph properly emits events for:
90
- * - Node execution start (nodeStarted)
91
- * - Node execution completion (nodeCompleted)
92
- * This is crucial for monitoring and debugging workflow execution
93
- */
94
- it("should trigger `nodeStarted` and `nodeCompleted` events", async function () {
95
- const nodeStartedSpy = sinon.spy();
96
- const nodeCompletedSpy = sinon.spy();
97
-
98
- graph.on("nodeStarted", nodeStartedSpy);
99
- graph.on("nodeCompleted", nodeCompletedSpy);
100
-
101
- const testNode: Node<TestSchema> = {
102
- name: "testNode",
103
- execute: async (context) => {
104
- context.value = (context.value ?? 0) + 1;
105
- },
106
- next: [],
107
- };
108
-
109
- graph.addNode(testNode);
110
- await graph.execute("testNode");
111
-
112
- expect(nodeStartedSpy.calledOnce).to.be.true;
113
- expect(nodeCompletedSpy.calledOnce).to.be.true;
114
- });
115
-
116
- /**
117
- * Tests error handling and error event emission
118
- * Validates that:
119
- * - Errors in node execution are properly caught
120
- * - The nodeError event is emitted
121
- * - The error message is preserved
122
- * This ensures robust error handling in the workflow
123
- */
124
- it("should handle errors and trigger `nodeError` event", async function () {
125
- const errorNode: Node<TestSchema> = {
126
- name: "errorNode",
127
- execute: async () => {
128
- throw new Error("Test error");
129
- },
130
- next: [],
131
- };
132
-
133
- graph.addNode(errorNode);
134
- const nodeErrorSpy = sinon.spy();
135
- graph.on("nodeError", nodeErrorSpy);
136
-
137
- try {
138
- await graph.execute("errorNode");
139
- } catch (error) {
140
- expect((error as Error).message).to.equal("Test error");
141
- }
142
-
143
- expect(nodeErrorSpy.calledOnce).to.be.true;
144
- });
145
-
146
- /**
147
- * Tests context validation using Zod schema
148
- * Validates that:
149
- * - Invalid context values are rejected
150
- * - Proper error messages are generated
151
- * - Type safety is maintained during execution
152
- * This ensures data integrity throughout the workflow
153
- */
154
- it("should validate context with Zod", async function () {
155
- const invalidContext = { value: "invalid_string" };
156
-
157
- try {
158
- const simpleNode: Node<TestSchema> = {
159
- name: "simpleNode",
160
- execute: async (context) => {
161
- context.value = (context.value ?? 0) + 1;
162
- },
163
- next: [],
164
- };
165
-
166
- graph.addNode(simpleNode);
167
- await graph.execute("simpleNode", invalidContext as any);
168
- } catch (error) {
169
- expect((error as Error & { errors: any[] }).errors[0].message).to.include(
170
- "Expected number"
171
- );
172
- }
173
- });
174
-
175
- /**
176
- * Tests node execution with input/output validation
177
- * Demonstrates:
178
- * - Input parameter validation
179
- * - Output state validation
180
- * - Integration between node execution and validation
181
- * Ensures type safety and data consistency in node interactions
182
- */
183
- it("should execute a node with validated params and outputs", async function () {
184
- const paramNode: Node<TestSchema, { increment: number }> = {
185
- name: "paramNode",
186
- params: z.object({
187
- increment: z.number(),
188
- }),
189
- execute: async (context, params?: { increment: number }) => {
190
- if (!params) throw new Error("params required");
191
- context.value = (context.value ?? 0) + params.increment;
192
- },
193
- next: [],
194
- };
195
-
196
- graph.addNode(paramNode);
197
- await graph.execute("paramNode", { increment: 5 });
198
-
199
- const context = graph.getContext();
200
- expect(context.value).to.equal(5);
201
- });
202
-
203
- /**
204
- * Tests conditional node execution
205
- * Validates that:
206
- * - Nodes can have conditional execution logic
207
- * - Conditions are evaluated against current context
208
- * - Nodes are skipped when conditions are not met
209
- * This enables dynamic workflow paths based on state
210
- */
211
- it("should not execute a node when condition is false", async function () {
212
- const conditionalNode: Node<TestSchema> = {
213
- name: "conditionalNode",
214
- condition: (context) => (context.value ?? 0) > 0,
215
- execute: async (context) => {
216
- context.value = (context.value ?? 0) + 10;
217
- },
218
- next: [],
219
- };
220
-
221
- graph.addNode(conditionalNode);
222
- await graph.execute("conditionalNode");
223
-
224
- const context = graph.getContext();
225
- expect(context.value).to.equal(0);
226
- });
227
-
228
- /**
229
- * Tests node retry functionality
230
- * Validates the retry mechanism:
231
- * - Maximum attempt limits
232
- * - Retry delays
233
- * - Success after retry
234
- * - Context preservation between attempts
235
- * Essential for handling transient failures in workflows
236
- */
237
- it("should retry a node execution when it fails", async () => {
238
- let attempts = 0;
239
- const retryNode: Node<TestSchema> = {
240
- name: "retryNode",
241
- execute: async (context) => {
242
- attempts++;
243
- if (attempts < 3) {
244
- throw new Error("Temporary failure");
245
- }
246
- context.value = 42;
247
- },
248
- retry: {
249
- maxAttempts: 3,
250
- delay: 100,
251
- },
252
- };
253
-
254
- const graph = new GraphFlow("test", {
255
- name: "test",
256
- schema: TestSchema,
257
- context: { value: 0 },
258
- nodes: [retryNode],
259
- });
260
-
261
- await graph.execute("retryNode");
262
- expect(attempts).to.equal(3);
263
- expect(graph.getContext().value).to.equal(42);
264
- });
265
-
266
- /**
267
- * Tests node removal functionality
268
- */
269
- it("should remove a node from the graph", function () {
270
- const testNode: Node<TestSchema> = {
271
- name: "testNode",
272
- execute: async () => {},
273
- };
274
- graph.addNode(testNode);
275
- graph.removeNode("testNode");
276
-
277
- expect(graph.getNodes().length).to.equal(0);
278
- });
279
-
280
- /**
281
- * Tests graph reloading functionality
282
- */
283
- it("should clear and reload the graph using `load`", function () {
284
- const nodeA: Node<TestSchema> = {
285
- name: "A",
286
- execute: async () => {},
287
- };
288
- const nodeB: Node<TestSchema> = {
289
- name: "B",
290
- execute: async () => {},
291
- };
292
-
293
- const newDefinition: GraphDefinition<TestSchema> = {
294
- name: "TestGraph",
295
- entryNode: "A",
296
- nodes: [nodeA, nodeB],
297
- context: { value: 0 },
298
- schema: TestSchema,
299
- };
300
-
301
- graph.load(newDefinition);
302
- expect(graph.getNodes().length).to.equal(2);
303
- expect(graph.getNodes().map((n) => n.name)).to.include.members(["A", "B"]);
304
- });
305
-
306
- /**
307
- * Tests input validation error handling
308
- */
309
- it("should throw error when node input validation fails", async () => {
310
- const node: Node<TestSchema> = {
311
- name: "test",
312
- params: z.object({
313
- value: z.number().min(0),
314
- }),
315
- execute: async (context, params) => {
316
- if (!params) throw new Error("params required");
317
- context.value = params.value;
318
- },
319
- };
320
-
321
- const graph = new GraphFlow("test", {
322
- name: "test",
323
- schema: TestSchema,
324
- context: { value: 0 },
325
- nodes: [node],
326
- });
327
-
328
- try {
329
- await graph.execute("test", { value: -1 });
330
- expect.fail("Should have thrown an error");
331
- } catch (error: any) {
332
- expect(error.message).to.include("Number must be greater than or equal");
333
- }
334
- });
335
- /**
336
- * Tests successful input/output validation flow
337
- */
338
- it("should successfully validate both params and outputs", async function () {
339
- const graph = new GraphFlow("test", {
340
- name: "test",
341
- nodes: [
342
- {
343
- name: "validatedNode",
344
- params: z.object({
345
- increment: z.number().min(0).max(5),
346
- }),
347
- execute: async (
348
- context: GraphContext<TestSchema>,
349
- params?: NodeParams
350
- ) => {
351
- if (!params) throw new Error("params required");
352
- context.value = (context.value ?? 0) + params.increment;
353
- },
354
- },
355
- ],
356
- schema: TestSchema,
357
- context: { value: 0, counter: 0, message: "" },
358
- });
359
-
360
- // Test avec valeur valide
361
- await graph.execute("validatedNode", { increment: 3 });
362
- expect(graph.getContext().value).to.equal(3);
363
-
364
- // Test avec valeur invalide
365
- await expect(
366
- graph.execute("validatedNode", { increment: 10 })
367
- ).to.be.rejectedWith("Number must be less than or equal to 5");
368
- });
369
-
370
- /**
371
- * Tests handling of missing required params
372
- */
373
- it("should throw error when required params are missing", async function () {
374
- const graph = new GraphFlow("test", {
375
- name: "test",
376
- nodes: [
377
- {
378
- name: "requiredInputNode",
379
- params: z.object({
380
- value: z.number(),
381
- }),
382
- execute: async (
383
- context: GraphContext<TestSchema>,
384
- params?: NodeParams
385
- ) => {
386
- context.counter = params?.value || 0;
387
- },
388
- },
389
- ],
390
- schema: TestSchema,
391
- context: { value: 0, counter: 0, message: "" },
392
- });
393
-
394
- await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
395
- "Params required for node"
396
- );
397
- });
398
-
399
- /**
400
- * Tests complex workflow execution with multiple branches
401
- * Demonstrates:
402
- * - Multiple execution paths
403
- * - Node chaining
404
- * - Parallel branch execution
405
- * - Context accumulation across branches
406
- * This validates the graph's ability to handle complex business processes
407
- */
408
- it("should execute a complex workflow with multiple nodes and accumulate the value", async function () {
409
- const nodeA: Node<TestSchema> = {
410
- name: "nodeA",
411
- execute: async (context) => {
412
- context.value = (context.value ?? 0) + 1;
413
- },
414
- next: ["nodeB1", "nodeB2"],
415
- };
416
-
417
- const nodeB1: Node<TestSchema> = {
418
- name: "nodeB1",
419
- execute: async (context) => {
420
- context.value = (context.value ?? 0) * 2;
421
- },
422
- next: ["nodeC"],
423
- };
424
-
425
- const nodeB2: Node<TestSchema> = {
426
- name: "nodeB2",
427
- execute: async (context) => {
428
- context.value = (context.value ?? 0) + 3;
429
- },
430
- next: ["nodeC"],
431
- };
432
-
433
- const nodeC: Node<TestSchema> = {
434
- name: "nodeC",
435
- execute: async (context) => {
436
- context.value = (context.value ?? 0) + 5;
437
- },
438
- };
439
-
440
- [nodeA, nodeB1, nodeB2, nodeC].forEach((node) => graph.addNode(node));
441
-
442
- await graph.execute("nodeA");
443
- expect(graph.getContext().value).to.equal(15);
444
- });
445
-
446
- /**
447
- * Tests conditional branching in workflows
448
- */
449
- it("should execute different branches based on conditions", async function () {
450
- const startNode: Node<TestSchema> = {
451
- name: "start",
452
- execute: async (context) => {
453
- context.value = (context.value ?? 0) + 5;
454
- },
455
- next: ["end"],
456
- };
457
-
458
- const endNode: Node<TestSchema> = {
459
- name: "end",
460
- execute: async (context) => {
461
- if ((context.value ?? 0) < 10) {
462
- context.value = (context.value ?? 0) * 2;
463
- } else {
464
- context.value = (context.value ?? 0) + 1;
465
- }
466
- },
467
- };
468
-
469
- [startNode, endNode].forEach((node) => graph.addNode(node));
470
-
471
- await graph.execute("start");
472
- expect(graph.getContext().value).to.equal(10);
473
- });
474
-
475
- /**
476
- * Tests parallel workflow execution using GraphController
477
- * Validates:
478
- * - Multiple graph execution in parallel
479
- * - Independent context maintenance
480
- * - Proper result aggregation
481
- * - Concurrency control
482
- * Essential for scaling workflow processing
483
- */
484
- it("should handle parallel workflows using GraphController", async function () {
485
- // Graph 1
486
- const graph1 = new GraphFlow("Graph1", {
487
- name: "Graph1",
488
- nodes: [],
489
- context: { value: 0 },
490
- schema: TestSchema,
491
- });
492
-
493
- const processNode1: Node<TestSchema> = {
494
- name: "process1",
495
- execute: async (context) => {
496
- context.value = 1;
497
- },
498
- next: ["finalize1"],
499
- };
500
-
501
- const finalizeNode1: Node<TestSchema> = {
502
- name: "finalize1",
503
- execute: async (context) => {
504
- context.value = (context.value ?? 0) * 2;
505
- },
506
- };
507
-
508
- // Graph 2
509
- const graph2 = new GraphFlow("Graph2", {
510
- name: "Graph2",
511
- nodes: [],
512
- context: { value: 0 },
513
- schema: TestSchema,
514
- });
515
-
516
- const processNode2: Node<TestSchema> = {
517
- name: "process2",
518
- execute: async (context) => {
519
- context.value = 2;
520
- },
521
- next: ["finalize2"],
522
- };
523
-
524
- const finalizeNode2: Node<TestSchema> = {
525
- name: "finalize2",
526
- execute: async (context) => {
527
- context.value = (context.value ?? 0) + 3;
528
- },
529
- };
530
-
531
- graph1.addNode(processNode1);
532
- graph1.addNode(finalizeNode1);
533
- graph2.addNode(processNode2);
534
- graph2.addNode(finalizeNode2);
535
-
536
- const results = await GraphController.executeParallel(
537
- [graph1, graph2],
538
- ["process1", "process2"],
539
- 2,
540
- [{}, {}]
541
- );
542
-
543
- expect(results[0].value).to.equal(2); // Graph1: 1 * 2
544
- expect(results[1].value).to.equal(5); // Graph2: 2 + 3
545
- });
546
-
547
- /**
548
- * Tests sequential workflow execution using GraphController
549
- */
550
- it("should handle sequential workflows using GraphController", async function () {
551
- // Graph 1
552
- const graph1 = new GraphFlow("Graph1", {
553
- name: "Graph1",
554
- nodes: [],
555
- context: { value: 1 },
556
- schema: TestSchema,
557
- });
558
-
559
- const startNode1: Node<TestSchema> = {
560
- name: "start1",
561
- execute: async (context) => {
562
- context.value = (context.value ?? 0) * 2;
563
- },
564
- };
565
-
566
- // Graph 2
567
- const graph2 = new GraphFlow("Graph2", {
568
- name: "Graph2",
569
- nodes: [],
570
- context: { value: 3 },
571
- schema: TestSchema,
572
- });
573
-
574
- const startNode2: Node<TestSchema> = {
575
- name: "start2",
576
- execute: async (context) => {
577
- context.value = (context.value ?? 0) + 2;
578
- },
579
- };
580
-
581
- graph1.addNode(startNode1);
582
- graph2.addNode(startNode2);
583
-
584
- const results = await GraphController.executeSequential(
585
- [graph1, graph2],
586
- ["start1", "start2"],
587
- [{}, {}]
588
- );
589
-
590
- expect(results[0].value).to.equal(2); // Graph1: 1 * 2
591
- expect(results[1].value).to.equal(5); // Graph2: 3 + 2
592
- });
593
-
594
- /**
595
- * Tests event correlation functionality
596
- * Demonstrates:
597
- * - Event correlation based on transaction ID
598
- * - Timeout handling
599
- * - Multiple event synchronization
600
- * - Context updates after correlation
601
- * Critical for integrating with external event sources
602
- */
603
- it("should handle correlated events correctly", async function () {
604
- this.timeout(10000);
605
- const graph = new GraphFlow("test", {
606
- name: "test",
607
- nodes: [],
608
- context: { value: 0 },
609
- schema: TestSchema,
610
- eventEmitter: new EventEmitter(),
611
- });
612
-
613
- let eventsReceived = 0;
614
- const node = {
615
- name: "testNode",
616
- waitForEvents: {
617
- events: ["eventA", "eventB"],
618
- timeout: 5000,
619
- strategy: "all" as const,
620
- },
621
- execute: async (context: GraphContext<typeof TestSchema>) => {
622
- eventsReceived = 2;
623
- context.value = 42;
624
- },
625
- };
626
-
627
- graph.addNode(node);
628
-
629
- graph.execute("testNode");
630
-
631
- await new Promise((resolve) => setTimeout(resolve, 500));
632
-
633
- await graph.emit("eventA", { eventPayload: { status: "A" } });
634
- await new Promise((resolve) => setTimeout(resolve, 100));
635
- await graph.emit("eventB", { eventPayload: { status: "B" } });
636
-
637
- await new Promise((resolve) => setTimeout(resolve, 100));
638
-
639
- expect(eventsReceived).to.equal(2);
640
- expect(graph.getContext().value).to.equal(42);
641
- });
642
-
643
- /**
644
- * Tests multiple event waiting functionality
645
- */
646
- it("should wait for multiple events before continuing", async function () {
647
- this.timeout(10000);
648
- const graph = new GraphFlow("test", {
649
- name: "test",
650
- nodes: [],
651
- context: { value: 0 },
652
- schema: TestSchema,
653
- eventEmitter: new EventEmitter(),
654
- });
655
-
656
- const node = {
657
- name: "testNode",
658
- waitForEvents: {
659
- events: ["event1", "event2"],
660
- timeout: 5000,
661
- strategy: "all" as const,
662
- },
663
- execute: async (context: GraphContext<typeof TestSchema>) => {
664
- context.value = 42; // Ajouter une modification du contexte
665
- },
666
- };
667
-
668
- graph.addNode(node);
669
- graph.execute("testNode");
670
-
671
- await new Promise((resolve) => setTimeout(resolve, 500));
672
- await graph.emit("event1", { eventPayload: { status: "1" } });
673
- await new Promise((resolve) => setTimeout(resolve, 100));
674
- await graph.emit("event2", { eventPayload: { status: "2" } });
675
- expect(graph.getContext().value).to.equal(42);
676
- });
677
-
678
- /**
679
- * Tests single event waiting functionality
680
- */
681
- it("should wait for a single event before continuing", async function () {
682
- this.timeout(5000);
683
-
684
- const waitingNode: Node<TestSchema> = {
685
- name: "waitingNode",
686
- execute: async (context: GraphContext<typeof TestSchema>) => {
687
- context.value = 1;
688
- },
689
- waitForEvent: true,
690
- next: ["finalNode"],
691
- };
692
-
693
- const finalNode: Node<TestSchema> = {
694
- name: "finalNode",
695
- execute: async (context: GraphContext<typeof TestSchema>) => {
696
- context.value = (context.value ?? 0) + 5;
697
- },
698
- };
699
-
700
- [waitingNode, finalNode].forEach((node) => graph.addNode(node));
701
-
702
- const resultPromise = graph.execute("waitingNode");
703
-
704
- // Wait a bit to ensure the node is ready
705
- await new Promise((resolve) => setTimeout(resolve, 500));
706
-
707
- // Emit the event
708
- await graph.emit("someEvent");
709
-
710
- const result = await resultPromise;
711
- expect(result.value).to.equal(6); // 1 (waitingNode) + 5 (finalNode)
712
- });
713
-
714
- // Test de validation des paramètres
715
- it("should successfully validate params", async () => {
716
- const graph = new GraphFlow("test", {
717
- name: "test",
718
- nodes: [
719
- {
720
- name: "validationNode",
721
- params: z.object({
722
- value: z.number().max(10),
723
- }),
724
- execute: async (
725
- context: GraphContext<TestSchema>,
726
- params?: NodeParams
727
- ) => {
728
- context.counter = params?.value || 0;
729
- },
730
- },
731
- ],
732
- schema: TestSchema,
733
- context: { value: 0, counter: 0, message: "" },
734
- });
735
-
736
- // Test avec valeur invalide
737
- await expect(
738
- graph.execute("validationNode", { value: 20 })
739
- ).to.be.rejectedWith("Number must be less than or equal to 10");
740
- });
741
-
742
- // Test des paramètres requis
743
- it("should throw error when required params are missing", async () => {
744
- const graph = new GraphFlow("test", {
745
- name: "test",
746
- nodes: [
747
- {
748
- name: "requiredInputNode",
749
- params: z.object({
750
- value: z.number(),
751
- }),
752
- execute: async (
753
- context: GraphContext<TestSchema>,
754
- params?: NodeParams
755
- ) => {
756
- context.counter = params?.value || 0;
757
- },
758
- },
759
- ],
760
- schema: TestSchema,
761
- context: { value: 0, counter: 0, message: "" },
762
- });
763
-
764
- await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
765
- "Params required for node"
766
- );
767
- });
768
- });