@ai.ntellect/core 0.8.2 → 0.8.3

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 (42) hide show
  1. package/dist/graph/controller.d.ts +4 -5
  2. package/dist/graph/controller.d.ts.map +1 -1
  3. package/dist/graph/controller.js +10 -10
  4. package/dist/graph/controller.js.map +1 -1
  5. package/dist/graph/event-manager.d.ts.map +1 -1
  6. package/dist/graph/event-manager.js +4 -4
  7. package/dist/graph/event-manager.js.map +1 -1
  8. package/dist/graph/index.d.ts +2 -12
  9. package/dist/graph/index.d.ts.map +1 -1
  10. package/dist/graph/index.js +26 -46
  11. package/dist/graph/index.js.map +1 -1
  12. package/dist/graph/node.d.ts +1 -10
  13. package/dist/graph/node.d.ts.map +1 -1
  14. package/dist/graph/node.js +7 -36
  15. package/dist/graph/node.js.map +1 -1
  16. package/dist/graph/observer.d.ts +4 -0
  17. package/dist/graph/observer.d.ts.map +1 -1
  18. package/dist/graph/observer.js +27 -1
  19. package/dist/graph/observer.js.map +1 -1
  20. package/dist/modules/agent/agent.js +1 -1
  21. package/dist/modules/agent/agent.js.map +1 -1
  22. package/dist/modules/agent/generic-assistant.js +1 -1
  23. package/dist/modules/agent/generic-assistant.js.map +1 -1
  24. package/dist/modules/agent/generic-executor.js +1 -1
  25. package/dist/modules/agent/generic-executor.js.map +1 -1
  26. package/dist/modules/agent/llm-factory.d.ts.map +1 -1
  27. package/dist/types/index.d.ts +1 -1
  28. package/dist/types/index.d.ts.map +1 -1
  29. package/graph/controller.ts +10 -11
  30. package/graph/event-manager.ts +2 -14
  31. package/graph/index.ts +29 -57
  32. package/graph/node.ts +5 -39
  33. package/graph/observer.ts +35 -5
  34. package/modules/agent/agent.ts +1 -1
  35. package/modules/agent/generic-assistant.ts +1 -1
  36. package/modules/agent/generic-executor.ts +1 -1
  37. package/package.json +1 -1
  38. package/test/graph/controller.test.ts +60 -15
  39. package/test/graph/index.test.ts +104 -109
  40. package/test/graph/node.test.ts +38 -233
  41. package/test/graph/observer.test.ts +1 -1
  42. package/types/index.ts +0 -1
@@ -2,21 +2,29 @@ import { expect } from "chai";
2
2
  import { z } from "zod";
3
3
  import { GraphController } from "../../graph/controller";
4
4
  import { GraphFlow } from "../../graph/index";
5
- import { GraphNodeConfig } from "../../types";
5
+ import { GraphContext, GraphNodeConfig } from "../../types";
6
6
 
7
7
  describe("GraphController", () => {
8
8
  const TestSchema = z.object({
9
9
  counter: z.number(),
10
10
  message: z.string(),
11
+ value: z.number().optional(),
12
+ prefix: z.string().optional(),
11
13
  });
12
14
 
13
15
  const createTestGraph = (name: string): GraphFlow<typeof TestSchema> => {
14
16
  const nodes: GraphNodeConfig<typeof TestSchema>[] = [
15
17
  {
16
18
  name: "start",
17
- execute: async (context, params) => {
18
- context.counter = params?.value ?? 0;
19
- context.message = params?.prefix ? `${params.prefix}-${name}` : name;
19
+ execute: async (context) => {
20
+ if (context.value !== undefined) {
21
+ context.counter = context.value;
22
+ }
23
+ if (context.prefix) {
24
+ context.message = `${context.prefix}-${name}`;
25
+ } else {
26
+ context.message = name;
27
+ }
20
28
  },
21
29
  },
22
30
  {
@@ -36,23 +44,21 @@ describe("GraphController", () => {
36
44
  };
37
45
 
38
46
  describe("Sequential Execution", () => {
39
- it("should execute graphs sequentially with different params and params", async () => {
47
+ it("should execute graphs sequentially with different contexts", async () => {
40
48
  const graph1 = createTestGraph("graph1");
41
49
  const graph2 = createTestGraph("graph2");
42
50
  const graph3 = createTestGraph("graph3");
43
51
 
44
- const params = [{ value: 10 }, { value: 20 }, { value: 30 }];
45
-
46
- const params2 = [
47
- { prefix: "test1" },
48
- { prefix: "test2" },
49
- { prefix: "test3" },
52
+ const contexts = [
53
+ { value: 10, prefix: "test1" },
54
+ { value: 20, prefix: "test2" },
55
+ { value: 30, prefix: "test3" },
50
56
  ];
51
57
 
52
58
  const results = await GraphController.executeSequential(
53
59
  [graph1, graph2, graph3],
54
60
  ["start", "start", "start"],
55
- params.map((value, i) => ({ ...value, prefix: params2[i].prefix }))
61
+ contexts
56
62
  );
57
63
 
58
64
  expect(results).to.have.length(3);
@@ -66,7 +72,7 @@ describe("GraphController", () => {
66
72
  expect(results[0].nodeName).to.equal("start");
67
73
  });
68
74
 
69
- it("should handle missing params and params gracefully", async () => {
75
+ it("should handle missing contexts gracefully", async () => {
70
76
  const graph1 = createTestGraph("graph1");
71
77
  const graph2 = createTestGraph("graph2");
72
78
 
@@ -89,7 +95,7 @@ describe("GraphController", () => {
89
95
  createTestGraph(`graph${i + 1}`)
90
96
  );
91
97
 
92
- const params = Array.from({ length: 5 }, (_, i) => ({
98
+ const contexts = Array.from({ length: 5 }, (_, i) => ({
93
99
  value: (i + 1) * 10,
94
100
  prefix: `test${i + 1}`,
95
101
  }));
@@ -106,7 +112,7 @@ describe("GraphController", () => {
106
112
  graphs,
107
113
  Array(5).fill("start"),
108
114
  2,
109
- params
115
+ contexts
110
116
  );
111
117
  const executionTime = Date.now() - startTime;
112
118
 
@@ -188,4 +194,43 @@ describe("GraphController", () => {
188
194
  ]);
189
195
  });
190
196
  });
197
+
198
+ it("should wait for correlated events", async function () {
199
+ const graph = new GraphFlow({
200
+ name: "test",
201
+ schema: TestSchema,
202
+ nodes: [
203
+ {
204
+ name: "correlatedEventsNode",
205
+ when: {
206
+ events: ["eventA", "eventB"],
207
+ timeout: 1000,
208
+ strategy: {
209
+ type: "correlate",
210
+ correlation: (events) => {
211
+ const eventA = events.find((e) => e.type === "eventA");
212
+ const eventB = events.find((e) => e.type === "eventB");
213
+ return eventA?.payload?.id === eventB?.payload?.id;
214
+ },
215
+ },
216
+ },
217
+ execute: async (context: GraphContext<typeof TestSchema>) => {
218
+ context.message = "Correlated events received";
219
+ },
220
+ },
221
+ ],
222
+ context: { value: 0, counter: 0, message: "" },
223
+ });
224
+
225
+ const execution = graph.execute("correlatedEventsNode");
226
+
227
+ // Émettre les événements corrélés
228
+ setTimeout(() => {
229
+ graph.emit("eventA", { id: "123", status: "completed" });
230
+ graph.emit("eventB", { id: "123", status: "available" });
231
+ }, 100);
232
+
233
+ await execution;
234
+ expect(graph.getContext().message).to.equal("Correlated events received");
235
+ });
191
236
  });
@@ -5,7 +5,6 @@ import sinon from "sinon";
5
5
  import { z } from "zod";
6
6
  import { GraphController } from "../../graph/controller";
7
7
  import { GraphFlow } from "../../graph/index";
8
- import { NodeParams } from "../../graph/node";
9
8
  import { GraphConfig, GraphContext, GraphNodeConfig } from "../../types";
10
9
 
11
10
  use(chaiAsPromised);
@@ -19,7 +18,7 @@ use(chaiAsPromised);
19
18
  * - eventPayload: optional object containing transaction metadata
20
19
  */
21
20
  const TestSchema = z.object({
22
- value: z.number().default(0),
21
+ value: z.number().min(0).default(0),
23
22
  counter: z.number().default(0),
24
23
  message: z.string().default(""),
25
24
  eventPayload: z
@@ -165,10 +164,9 @@ describe("GraphFlow", function () {
165
164
 
166
165
  graph.addNode(simpleNode);
167
166
  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
- );
167
+ expect.fail("Should have thrown an error");
168
+ } catch (error: any) {
169
+ expect(error.message).to.include("Expected number");
172
170
  }
173
171
  });
174
172
 
@@ -181,23 +179,22 @@ describe("GraphFlow", function () {
181
179
  * Ensures type safety and data consistency in node interactions
182
180
  */
183
181
  it("should execute a node with validated params and outputs", async function () {
184
- const paramNode: GraphNodeConfig<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 });
182
+ const graph = new GraphFlow({
183
+ name: "test",
184
+ schema: TestSchema,
185
+ nodes: [
186
+ {
187
+ name: "validatedNode",
188
+ execute: async (context: GraphContext<TestSchema>) => {
189
+ context.value = 5;
190
+ },
191
+ },
192
+ ],
193
+ context: { value: 0, counter: 0, message: "" },
194
+ });
198
195
 
199
- const context = graph.getContext();
200
- expect(context.value).to.equal(5);
196
+ await graph.execute("validatedNode");
197
+ expect(graph.getContext().value).to.equal(5);
201
198
  });
202
199
 
203
200
  /**
@@ -307,93 +304,107 @@ describe("GraphFlow", function () {
307
304
  * Tests input validation error handling
308
305
  */
309
306
  it("should throw error when node input validation fails", async () => {
310
- const node: GraphNodeConfig<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
307
  const graph = new GraphFlow({
322
308
  name: "test",
323
309
  schema: TestSchema,
324
- context: { value: 0 },
325
- nodes: [node],
310
+ nodes: [
311
+ {
312
+ name: "test",
313
+ execute: async (context: GraphContext<TestSchema>) => {
314
+ context.value = -1;
315
+ },
316
+ },
317
+ ],
318
+ context: { value: 0, counter: 0, message: "" },
326
319
  });
327
320
 
328
321
  try {
329
322
  await graph.execute("test", { value: -1 });
330
323
  expect.fail("Should have thrown an error");
331
324
  } catch (error: any) {
332
- expect(error.message).to.include("Number must be greater than or equal");
325
+ expect(error.message).to.include(
326
+ "Number must be greater than or equal to 0"
327
+ );
333
328
  }
334
329
  });
330
+
335
331
  /**
336
332
  * Tests successful input/output validation flow
337
333
  */
338
- it("should successfully validate both params and outputs", async function () {
334
+ it("should execute a node with validated context", async function () {
339
335
  const graph = new GraphFlow({
340
336
  name: "test",
341
337
  schema: TestSchema,
342
338
  nodes: [
343
339
  {
344
340
  name: "validatedNode",
345
- params: z.object({
346
- increment: z.number().min(0).max(5),
347
- }),
348
- execute: async (
349
- context: GraphContext<TestSchema>,
350
- params?: NodeParams
351
- ) => {
352
- if (!params) throw new Error("params required");
353
- context.value = (context.value ?? 0) + params.increment;
341
+ execute: async (context: GraphContext<TestSchema>) => {
342
+ context.value = 5;
354
343
  },
355
344
  },
356
345
  ],
357
346
  context: { value: 0, counter: 0, message: "" },
358
347
  });
359
348
 
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");
349
+ await graph.execute("validatedNode");
350
+ expect(graph.getContext().value).to.equal(5);
368
351
  });
369
352
 
370
- /**
371
- * Tests handling of missing required params
372
- */
373
- it("should throw error when required params are missing", async function () {
353
+ it("should throw error when required context values are missing", async function () {
374
354
  const graph = new GraphFlow({
375
355
  name: "test",
376
356
  schema: TestSchema,
377
357
  nodes: [
378
358
  {
379
359
  name: "requiredInputNode",
380
- params: z.object({
381
- value: z.number(),
382
- }),
383
- execute: async (
384
- context: GraphContext<TestSchema>,
385
- params?: NodeParams
386
- ) => {
387
- context.counter = params?.value || 0;
360
+ execute: async (context: GraphContext<TestSchema>) => {
361
+ if (context.value === undefined) {
362
+ throw new Error("Value is required");
363
+ }
364
+ context.counter = context.value;
388
365
  },
389
366
  },
390
367
  ],
391
368
  context: { value: 0, counter: 0, message: "" },
392
369
  });
393
370
 
394
- await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
395
- "Params required for node"
396
- );
371
+ try {
372
+ graph["context"].value = undefined;
373
+ await graph.execute("requiredInputNode");
374
+ throw new Error("Should have thrown an error");
375
+ } catch (error: any) {
376
+ expect(error.message).to.equal("Value is required");
377
+ }
378
+ });
379
+
380
+ it("should validate context against schema constraints", async () => {
381
+ const graph = new GraphFlow({
382
+ name: "test",
383
+ schema: TestSchema,
384
+ nodes: [
385
+ {
386
+ name: "validationNode",
387
+ execute: async (context: GraphContext<TestSchema>) => {
388
+ const newContext = { ...context, value: -1 };
389
+ const validationResult = TestSchema.safeParse(newContext);
390
+ if (!validationResult.success) {
391
+ throw new Error(validationResult.error.errors[0].message);
392
+ }
393
+ graph["context"] = newContext;
394
+ },
395
+ },
396
+ ],
397
+ context: { value: 0, counter: 0, message: "" },
398
+ });
399
+
400
+ try {
401
+ await graph.execute("validationNode");
402
+ throw new Error("Should have thrown an error");
403
+ } catch (error: any) {
404
+ expect(error.message).to.include(
405
+ "Number must be greater than or equal to 0"
406
+ );
407
+ }
397
408
  });
398
409
 
399
410
  /**
@@ -629,58 +640,42 @@ describe("GraphFlow", function () {
629
640
  expect(result.value).to.equal(6); // 1 (waitingNode) + 5 (finalNode)
630
641
  });
631
642
 
632
- // Test de validation des paramètres
633
- it("should successfully validate params", async () => {
643
+ it("should wait for correlated events", async function () {
634
644
  const graph = new GraphFlow({
635
645
  name: "test",
636
646
  schema: TestSchema,
637
647
  nodes: [
638
648
  {
639
- name: "validationNode",
640
- params: z.object({
641
- value: z.number().max(10),
642
- }),
643
- execute: async (
644
- context: GraphContext<TestSchema>,
645
- params?: NodeParams
646
- ) => {
647
- context.counter = params?.value || 0;
649
+ name: "correlatedEventsNode",
650
+ when: {
651
+ events: ["eventA", "eventB"],
652
+ timeout: 1000,
653
+ strategy: {
654
+ type: "correlate",
655
+ correlation: (events) => {
656
+ const eventA = events.find((e) => e.type === "eventA");
657
+ const eventB = events.find((e) => e.type === "eventB");
658
+ return eventA?.payload?.id === eventB?.payload?.id;
659
+ },
660
+ },
661
+ },
662
+ execute: async (context: GraphContext<TestSchema>) => {
663
+ context.message = "Correlated events received";
648
664
  },
649
665
  },
650
666
  ],
651
667
  context: { value: 0, counter: 0, message: "" },
652
668
  });
653
669
 
654
- // Test avec valeur invalide
655
- await expect(
656
- graph.execute("validationNode", { value: 20 })
657
- ).to.be.rejectedWith("Number must be less than or equal to 10");
658
- });
670
+ const execution = graph.execute("correlatedEventsNode");
659
671
 
660
- // Test des paramètres requis
661
- it("should throw error when required params are missing", async () => {
662
- const graph = new GraphFlow({
663
- name: "test",
664
- schema: TestSchema,
665
- nodes: [
666
- {
667
- name: "requiredInputNode",
668
- params: z.object({
669
- value: z.number(),
670
- }),
671
- execute: async (
672
- context: GraphContext<TestSchema>,
673
- params?: NodeParams
674
- ) => {
675
- context.counter = params?.value || 0;
676
- },
677
- },
678
- ],
679
- context: { value: 0, counter: 0, message: "" },
680
- });
672
+ // Émettre les événements corrélés
673
+ setTimeout(() => {
674
+ graph.emit("eventA", { id: "123", status: "completed" });
675
+ graph.emit("eventB", { id: "123", status: "available" });
676
+ }, 100);
681
677
 
682
- await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
683
- "Params required for node"
684
- );
678
+ await execution;
679
+ expect(graph.getContext().message).to.equal("Correlated events received");
685
680
  });
686
681
  });