@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.
- package/dist/graph/controller.d.ts +4 -5
- package/dist/graph/controller.d.ts.map +1 -1
- package/dist/graph/controller.js +10 -10
- package/dist/graph/controller.js.map +1 -1
- package/dist/graph/event-manager.d.ts.map +1 -1
- package/dist/graph/event-manager.js +4 -4
- package/dist/graph/event-manager.js.map +1 -1
- package/dist/graph/index.d.ts +2 -12
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +26 -46
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/node.d.ts +1 -10
- package/dist/graph/node.d.ts.map +1 -1
- package/dist/graph/node.js +7 -36
- package/dist/graph/node.js.map +1 -1
- package/dist/graph/observer.d.ts +4 -0
- package/dist/graph/observer.d.ts.map +1 -1
- package/dist/graph/observer.js +27 -1
- package/dist/graph/observer.js.map +1 -1
- package/dist/modules/agent/agent.js +1 -1
- package/dist/modules/agent/agent.js.map +1 -1
- package/dist/modules/agent/generic-assistant.js +1 -1
- package/dist/modules/agent/generic-assistant.js.map +1 -1
- package/dist/modules/agent/generic-executor.js +1 -1
- package/dist/modules/agent/generic-executor.js.map +1 -1
- package/dist/modules/agent/llm-factory.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/graph/controller.ts +10 -11
- package/graph/event-manager.ts +2 -14
- package/graph/index.ts +29 -57
- package/graph/node.ts +5 -39
- package/graph/observer.ts +35 -5
- package/modules/agent/agent.ts +1 -1
- package/modules/agent/generic-assistant.ts +1 -1
- package/modules/agent/generic-executor.ts +1 -1
- package/package.json +1 -1
- package/test/graph/controller.test.ts +60 -15
- package/test/graph/index.test.ts +104 -109
- package/test/graph/node.test.ts +38 -233
- package/test/graph/observer.test.ts +1 -1
- 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
|
18
|
-
context.
|
19
|
-
|
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
|
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
|
45
|
-
|
46
|
-
|
47
|
-
{ prefix: "
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
});
|
package/test/graph/index.test.ts
CHANGED
@@ -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
|
-
|
169
|
-
|
170
|
-
|
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
|
185
|
-
name: "
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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
|
-
|
200
|
-
expect(
|
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
|
-
|
325
|
-
|
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(
|
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
|
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
|
-
|
346
|
-
|
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
|
-
|
361
|
-
|
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
|
-
|
381
|
-
value
|
382
|
-
|
383
|
-
|
384
|
-
context
|
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
|
-
|
395
|
-
"
|
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
|
-
|
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: "
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
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
|
-
|
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
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
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
|
683
|
-
|
684
|
-
);
|
678
|
+
await execution;
|
679
|
+
expect(graph.getContext().message).to.equal("Correlated events received");
|
685
680
|
});
|
686
681
|
});
|