@ai.ntellect/core 0.6.20 → 0.7.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 (41) hide show
  1. package/.mocharc.json +2 -1
  2. package/README.md +87 -148
  3. package/graph/controller.ts +1 -1
  4. package/graph/event-manager.ts +288 -0
  5. package/graph/index.ts +152 -384
  6. package/graph/logger.ts +70 -0
  7. package/graph/node.ts +398 -0
  8. package/graph/observer.ts +361 -0
  9. package/interfaces/index.ts +102 -1
  10. package/modules/agenda/index.ts +3 -16
  11. package/modules/embedding/index.ts +3 -3
  12. package/package.json +12 -20
  13. package/test/graph/index.test.ts +296 -154
  14. package/test/graph/observer.test.ts +398 -0
  15. package/test/modules/agenda/node-cron.test.ts +37 -16
  16. package/test/modules/memory/adapters/in-memory.test.ts +2 -2
  17. package/test/modules/memory/adapters/meilisearch.test.ts +28 -24
  18. package/test/modules/memory/base.test.ts +3 -3
  19. package/tsconfig.json +4 -2
  20. package/types/index.ts +23 -2
  21. package/utils/generate-action-schema.ts +8 -7
  22. package/.env.example +0 -2
  23. package/dist/graph/controller.js +0 -75
  24. package/dist/graph/index.js +0 -402
  25. package/dist/index.js +0 -41
  26. package/dist/interfaces/index.js +0 -17
  27. package/dist/modules/agenda/adapters/node-cron/index.js +0 -29
  28. package/dist/modules/agenda/index.js +0 -140
  29. package/dist/modules/embedding/adapters/ai/index.js +0 -57
  30. package/dist/modules/embedding/index.js +0 -59
  31. package/dist/modules/memory/adapters/in-memory/index.js +0 -210
  32. package/dist/modules/memory/adapters/meilisearch/index.js +0 -320
  33. package/dist/modules/memory/adapters/redis/index.js +0 -158
  34. package/dist/modules/memory/index.js +0 -103
  35. package/dist/types/index.js +0 -2
  36. package/dist/utils/generate-action-schema.js +0 -42
  37. package/dist/utils/header-builder.js +0 -34
  38. package/graph.ts +0 -74
  39. package/test/modules/embedding/ai.test.ts +0 -78
  40. package/test/modules/memory/adapters/redis.test.ts +0 -169
  41. package/test/services/agenda.test.ts +0 -279
package/graph.ts DELETED
@@ -1,74 +0,0 @@
1
- import { Node } from "types";
2
- import { z } from "zod";
3
- import { GraphController, GraphFlow } from "./index";
4
-
5
- // 🏗 Définition des schémas pour chaque graphe
6
- const schemaA = z.object({
7
- input: z.string(),
8
- result: z.string().optional(),
9
- });
10
-
11
- const schemaB = z.object({
12
- number: z.number(),
13
- result: z.number().optional(),
14
- });
15
-
16
- // 🔹 **Graph A** : Convertit une chaîne en majuscules
17
- const processText: Node<typeof schemaA> = {
18
- name: "processText",
19
- execute: async (context) => {
20
- context.result = context.input.toUpperCase();
21
- console.log("📢 Graphe A : Texte transformé →", context.result);
22
- },
23
- };
24
-
25
- // 🔹 **Graph B** : Multiplie un nombre par 10
26
- const multiplyNumber: Node<typeof schemaB> = {
27
- name: "multiplyNumber",
28
- execute: async (context) => {
29
- context.result = context.number * 10;
30
- console.log("🔢 Graphe B : Nombre multiplié →", context.result);
31
- },
32
- };
33
-
34
- // 🔗 **Création des graphes**
35
- const graphA = new GraphFlow("GraphA", {
36
- name: "GraphA",
37
- nodes: [processText],
38
- context: { input: "" },
39
- schema: schemaA,
40
- });
41
-
42
- const graphB = new GraphFlow("GraphB", {
43
- name: "GraphB",
44
- nodes: [multiplyNumber],
45
- context: { number: 0 },
46
- schema: schemaB,
47
- });
48
-
49
- (async () => {
50
- try {
51
- console.log("🚀 **Exécution Séquentielle** des graphes...");
52
- const sequentialResults = await GraphController.executeSequential(
53
- [graphA, graphB],
54
- ["processText", "multiplyNumber"],
55
- [{ input: "hello world" }, { number: 5 }]
56
- );
57
-
58
- console.log("🟢 **Résultats Séquentiels :**", sequentialResults);
59
-
60
- console.log(
61
- "\n⚡ **Exécution Parallèle** avec limitation de concurrence..."
62
- );
63
- const parallelResults = await GraphController.executeParallel(
64
- [graphA, graphB],
65
- ["processText", "multiplyNumber"],
66
- 1, // ⚠️ Limite de concurrence (1 à la fois)
67
- [{ input: "parallel execution" }, { number: 7 }]
68
- );
69
-
70
- console.log("🟢 **Résultats Parallèles :**", parallelResults);
71
- } catch (error) {
72
- console.error("❌ Erreur lors de l’exécution :", error);
73
- }
74
- })();
@@ -1,78 +0,0 @@
1
- import { openai } from "@ai-sdk/openai";
2
- import { expect } from "chai";
3
- import { Embedding } from "../../../modules/embedding";
4
- import { AIEmbeddingAdapter } from "../../../modules/embedding/adapters/ai";
5
-
6
- describe("EmbeddingModule", () => {
7
- let embeddingModule: Embedding;
8
-
9
- before(function () {
10
- this.timeout(10000);
11
- });
12
-
13
- beforeEach(() => {
14
- const model = openai.embedding("text-embedding-3-small");
15
- const embeddingModel = new AIEmbeddingAdapter(model);
16
- embeddingModule = new Embedding(embeddingModel);
17
- });
18
-
19
- it("should embed text", async function () {
20
- try {
21
- const embedding = await embeddingModule.embedText("Hello, world!");
22
- expect(embedding).to.be.an("array");
23
- expect(embedding.length).to.be.greaterThan(0);
24
- expect(embedding[0]).to.be.a("number");
25
- } catch (error) {
26
- console.error("Error in embedText:", error);
27
- throw error;
28
- }
29
- });
30
-
31
- it("should embed many texts", async function () {
32
- try {
33
- const embeddings = await embeddingModule.embedMany([
34
- "Hello, world!",
35
- "Another test text",
36
- ]);
37
- expect(embeddings).to.be.an("array");
38
- expect(embeddings.length).to.equal(2);
39
- expect(embeddings[0]).to.be.an("array");
40
- expect(embeddings[0][0]).to.be.a("number");
41
- } catch (error) {
42
- console.error("Error in embedMany:", error);
43
- throw error;
44
- }
45
- });
46
-
47
- it("should calculate similarity between two embeddings", () => {
48
- const embedding1 = [1, 2, 3];
49
- const embedding2 = [4, 5, 6];
50
- const similarity = embeddingModule.calculateSimilarity(
51
- embedding1,
52
- embedding2
53
- );
54
- expect(similarity).to.be.a("number");
55
- expect(similarity).to.be.within(0, 100);
56
- });
57
-
58
- it("should handle embedding errors gracefully", async function () {
59
- const mockEmbeddingAdapter = {
60
- embed: async () => {
61
- throw new Error("Mock embedding error");
62
- },
63
- embedMany: async () => {
64
- throw new Error("Mock embedding error");
65
- },
66
- };
67
-
68
- const mockEmbeddingModule = new Embedding(mockEmbeddingAdapter);
69
-
70
- try {
71
- await mockEmbeddingModule.embedText("test");
72
- expect.fail("Should have thrown an error");
73
- } catch (error) {
74
- expect(error).to.exist;
75
- expect((error as Error).message).to.equal("Mock embedding error");
76
- }
77
- });
78
- });
@@ -1,169 +0,0 @@
1
- import { expect } from "chai";
2
- import dotenv from "dotenv";
3
- import Redis from "ioredis";
4
- import { IMemoryAdapter } from "../../../interfaces";
5
- import { RedisAdapter } from "../../../memory/adapters/redis";
6
- import { BaseMemoryType } from "../../../types";
7
-
8
- // Load environment variables
9
- dotenv.config();
10
-
11
- describe("RedisAdapter", () => {
12
- before(function () {
13
- this.timeout(30000);
14
- });
15
-
16
- let redisAdapter: RedisAdapter;
17
- let mockAdapter: IMemoryAdapter;
18
- let redisClient: Redis | null = null;
19
- const fixedDate = new Date("2025-01-30T07:43:50.626Z");
20
- const fixedDateString = fixedDate.toISOString();
21
-
22
- const testMemory: BaseMemoryType = {
23
- id: "test-id",
24
- data: "test data",
25
- roomId: "test-room",
26
- createdAt: new Date(fixedDateString),
27
- };
28
-
29
- beforeEach(async function () {
30
- this.timeout(10000);
31
-
32
- try {
33
- mockAdapter = {
34
- init: async () => {},
35
- createMemory: async (input) => testMemory,
36
- getMemoryById: async () => testMemory,
37
- getMemoryByIndex: async () => [testMemory],
38
- getAllMemories: async () => [testMemory],
39
- clearMemoryById: async () => {},
40
- clearAllMemories: async () => {},
41
- };
42
-
43
- if (process.env.REDIS_URL) {
44
- redisClient = new Redis(process.env.REDIS_URL);
45
- redisAdapter = new RedisAdapter(process.env.REDIS_URL, {
46
- cachePrefix: "test-prefix",
47
- cacheTTL: 3600,
48
- });
49
- } else {
50
- const mockRedis = {
51
- connect: async () => Promise.resolve(),
52
- disconnect: async () => Promise.resolve(),
53
- set: async () => "OK",
54
- get: async (key: string) => {
55
- if (key.includes("test-id")) {
56
- return JSON.stringify({
57
- id: "test-id",
58
- data: "test data",
59
- embedding: null,
60
- roomId: "test-room",
61
- createdAt: fixedDateString,
62
- });
63
- }
64
- return null;
65
- },
66
- keys: async () => [`test-id`],
67
- mget: async (keys: string[]) =>
68
- keys.map(() =>
69
- JSON.stringify({
70
- id: "test-id",
71
- data: "test data",
72
- embedding: null,
73
- roomId: "test-room",
74
- createdAt: fixedDateString,
75
- })
76
- ),
77
- del: async () => 1,
78
- flushall: async () => "OK",
79
- quit: async () => Promise.resolve(),
80
- };
81
-
82
- redisAdapter = new RedisAdapter(mockRedis as any, {
83
- cachePrefix: "test-prefix",
84
- cacheTTL: 3600,
85
- });
86
- }
87
-
88
- await redisAdapter.init("test-room");
89
- } catch (error) {
90
- console.error("Error in beforeEach:", error);
91
- throw error;
92
- }
93
- });
94
-
95
- afterEach(async function () {
96
- this.timeout(5000);
97
- try {
98
- if (redisClient) {
99
- await redisClient.quit();
100
- redisClient = null;
101
- }
102
- if (redisAdapter) {
103
- await redisAdapter.quit();
104
- }
105
- } catch (error) {
106
- console.error("Error in afterEach:", error);
107
- }
108
- });
109
-
110
- describe("Initialization", () => {
111
- it("should initialize storage", async () => {
112
- await expect(redisAdapter.init("test-room")).to.not.throw;
113
- });
114
- });
115
-
116
- describe("Memory Operations", () => {
117
- const TEST_ROOM_ID = "test-room";
118
-
119
- it("should create memory", async () => {
120
- await expect(
121
- redisAdapter.createMemory({
122
- data: "test data",
123
- roomId: TEST_ROOM_ID,
124
- id: "test-id",
125
- embedding: [0.1, 0.2, 0.3],
126
- })
127
- ).to.not.throw;
128
- });
129
-
130
- it("should get memory by ID", async () => {
131
- const result = await redisAdapter.getMemoryById("test-id", TEST_ROOM_ID);
132
- if (result) {
133
- result.createdAt = new Date(fixedDateString);
134
- }
135
- expect(result).to.deep.equal(testMemory);
136
- });
137
-
138
- it("should get memories by index", async () => {
139
- const results = await redisAdapter.getMemoryByIndex("test", {
140
- roomId: TEST_ROOM_ID,
141
- limit: 10,
142
- });
143
-
144
- expect(results).to.be.an("array");
145
- if (results[0]) {
146
- results[0].createdAt = new Date(fixedDateString);
147
- }
148
- expect(results[0]).to.deep.equal(testMemory);
149
- });
150
-
151
- it("should get all memories", async () => {
152
- const results = await redisAdapter.getAllMemories(TEST_ROOM_ID);
153
- expect(results).to.be.an("array");
154
- if (results[0]) {
155
- results[0].createdAt = new Date(fixedDateString);
156
- }
157
- expect(results[0]).to.deep.equal(testMemory);
158
- });
159
-
160
- it("should clear memory by ID", async () => {
161
- await expect(redisAdapter.clearMemoryById("test-id", TEST_ROOM_ID)).to.not
162
- .throw;
163
- });
164
-
165
- it("should clear all memories", async () => {
166
- await expect(redisAdapter.clearAllMemories()).to.not.throw;
167
- });
168
- });
169
- });
@@ -1,279 +0,0 @@
1
- import { expect } from "chai";
2
- import sinon from "sinon";
3
- import { NodeCronAdapter } from "../../modules/agenda/adapters/cron/node-cron";
4
- import { Agenda } from "../../modules/agenda/agenda";
5
-
6
- before(function () {
7
- this.timeout(10000);
8
- });
9
-
10
- describe("Agenda Service", () => {
11
- let agenda: Agenda;
12
- const scheduledIds: string[] = []; // Track all scheduled request IDs
13
-
14
- beforeEach(() => {
15
- const cronService = new NodeCronAdapter();
16
- agenda = new Agenda(cronService);
17
- });
18
-
19
- afterEach(async () => {
20
- // Cancel all scheduled requests by their IDs
21
- scheduledIds.forEach((id) => agenda.cancelScheduledRequest(id));
22
- scheduledIds.length = 0; // Clear the array
23
-
24
- // Ensure all tasks are stopped
25
- await agenda.stop();
26
-
27
- await agenda.cancel({});
28
-
29
- await new Promise((resolve) => setTimeout(resolve, 100));
30
- });
31
-
32
- describe("Request Scheduling", () => {
33
- it("should schedule a new request and return an id", async () => {
34
- const request = {
35
- originalRequest: "test request",
36
- cronExpression: "0 0 * * *",
37
- };
38
-
39
- const id = await agenda.scheduleRequest(request);
40
- scheduledIds.push(id); // Track the ID
41
-
42
- expect(id).to.be.a("string");
43
- expect(agenda.getScheduledRequests()).to.have.lengthOf(1);
44
-
45
- const scheduledRequest = agenda.getScheduledRequests()[0];
46
- expect(scheduledRequest.originalRequest).to.equal(
47
- request.originalRequest
48
- );
49
- expect(scheduledRequest.cronExpression).to.equal(request.cronExpression);
50
- expect(scheduledRequest.isRecurring).to.be.false;
51
-
52
- agenda.cancelScheduledRequest(id);
53
- });
54
-
55
- it("should execute callbacks when scheduling and executing", async function () {
56
- this.timeout(5000);
57
-
58
- const onScheduledSpy = sinon.spy();
59
- const onExecutedSpy = sinon.spy();
60
-
61
- const request = {
62
- originalRequest: "test request",
63
- cronExpression: `${(new Date().getSeconds() + 1) % 60} * * * * *`,
64
- };
65
-
66
- const id = await agenda.scheduleRequest(request, {
67
- onScheduled: onScheduledSpy,
68
- onExecuted: onExecutedSpy,
69
- });
70
- scheduledIds.push(id);
71
-
72
- expect(onScheduledSpy.calledOnce).to.be.true;
73
-
74
- await new Promise<void>((resolve, reject) => {
75
- const timeout = setTimeout(() => {
76
- reject(new Error("Callback execution timeout"));
77
- }, 4000);
78
-
79
- const checkExecution = () => {
80
- if (onExecutedSpy.calledOnce) {
81
- clearTimeout(timeout);
82
- agenda.cancelScheduledRequest(id);
83
- resolve();
84
- return;
85
- }
86
- setTimeout(checkExecution, 100);
87
- };
88
- checkExecution();
89
- });
90
-
91
- expect(onExecutedSpy.calledOnce).to.be.true;
92
- });
93
- });
94
-
95
- describe("Request Management", () => {
96
- it("should cancel a scheduled request", async () => {
97
- const request = {
98
- originalRequest: "test request",
99
- cronExpression: "*/1 * * * *",
100
- };
101
-
102
- const id = await agenda.scheduleRequest(request);
103
- scheduledIds.push(id);
104
- expect(agenda.getScheduledRequests()).to.have.lengthOf(1);
105
-
106
- const cancelled = agenda.cancelScheduledRequest(id);
107
- expect(cancelled).to.be.true;
108
- expect(agenda.getScheduledRequests()).to.have.lengthOf(0);
109
- });
110
-
111
- it("should return false when cancelling non-existent request", () => {
112
- const cancelled = agenda.cancelScheduledRequest("non-existent-id");
113
- expect(cancelled).to.be.false;
114
- });
115
-
116
- it("should get all scheduled requests", async () => {
117
- const requests = [
118
- {
119
- originalRequest: "request 1",
120
- cronExpression: "*/1 * * * *",
121
- },
122
- {
123
- originalRequest: "request 2",
124
- cronExpression: "*/5 * * * *",
125
- },
126
- ];
127
-
128
- for (const request of requests) {
129
- const id = await agenda.scheduleRequest(request);
130
- scheduledIds.push(id);
131
- }
132
-
133
- const scheduledRequests = agenda.getScheduledRequests();
134
- expect(scheduledRequests).to.have.lengthOf(2);
135
- expect(scheduledRequests[0].originalRequest).to.equal("request 1");
136
- expect(scheduledRequests[1].originalRequest).to.equal("request 2");
137
- });
138
- });
139
-
140
- describe("Global Management", () => {
141
- it("should stop all scheduled requests", async () => {
142
- const requests = [
143
- {
144
- originalRequest: "request 1",
145
- cronExpression: "*/1 * * * *",
146
- },
147
- {
148
- originalRequest: "request 2",
149
- cronExpression: "*/5 * * * *",
150
- },
151
- ];
152
-
153
- for (const request of requests) {
154
- await agenda.scheduleRequest(request);
155
- }
156
-
157
- expect(agenda.getScheduledRequests()).to.have.lengthOf(2);
158
-
159
- agenda.stopAll();
160
- expect(agenda.getScheduledRequests()).to.have.lengthOf(0);
161
- });
162
- });
163
-
164
- describe("Error Handling", () => {
165
- it("should handle execution errors gracefully", async () => {
166
- const consoleSpy = sinon.spy(console, "error");
167
-
168
- const request = {
169
- originalRequest: "error request",
170
- cronExpression: "0 0 * * *",
171
- };
172
-
173
- const id = await agenda.scheduleRequest(request);
174
-
175
- // Wait for execution
176
- await new Promise((resolve) => setTimeout(resolve, 1100));
177
-
178
- expect(consoleSpy.called).to.be.false;
179
-
180
- agenda.cancelScheduledRequest(id);
181
- consoleSpy.restore();
182
- });
183
- });
184
-
185
- describe("Request Execution", () => {
186
- it("should execute non-recurring requests only once", async function () {
187
- this.timeout(5000);
188
- const onExecutedSpy = sinon.spy();
189
-
190
- const request = {
191
- originalRequest: "single execution",
192
- cronExpression: `${new Date().getSeconds() + 1} * * * * *`,
193
- };
194
-
195
- const id = await agenda.scheduleRequest(request, {
196
- onExecuted: onExecutedSpy,
197
- });
198
-
199
- try {
200
- await new Promise<void>((resolve, reject) => {
201
- const timeout = setTimeout(
202
- () => reject(new Error("Test timeout")),
203
- 4000
204
- );
205
- const checkExecution = () => {
206
- if (onExecutedSpy.calledOnce) {
207
- clearTimeout(timeout);
208
- resolve();
209
- return;
210
- }
211
- setTimeout(checkExecution, 100);
212
- };
213
- checkExecution();
214
- });
215
- } finally {
216
- agenda.cancelScheduledRequest(id);
217
- }
218
-
219
- expect(onExecutedSpy.calledOnce).to.be.true;
220
- expect(agenda.getScheduledRequests()).to.have.lengthOf(0);
221
- });
222
-
223
- it("should log execution status", async function () {
224
- this.timeout(10000);
225
- const consoleLogSpy = sinon.spy(console, "log");
226
-
227
- const request = {
228
- originalRequest: "test request",
229
- cronExpression: `${new Date().getSeconds() + 1} * * * * *`,
230
- };
231
-
232
- const id = await agenda.scheduleRequest(request);
233
-
234
- await new Promise<void>((resolve) => {
235
- const checkExecution = () => {
236
- if (
237
- consoleLogSpy.calledWith(`🔄 Executing scheduled request: ${id}`) &&
238
- consoleLogSpy.calledWith(
239
- `✅ Scheduled request executed successfully: ${id}`
240
- )
241
- ) {
242
- agenda.cancelScheduledRequest(id);
243
- resolve();
244
- return;
245
- }
246
- setTimeout(checkExecution, 100);
247
- };
248
- checkExecution();
249
- });
250
-
251
- expect(consoleLogSpy.calledWith(`🔄 Executing scheduled request: ${id}`))
252
- .to.be.true;
253
- expect(
254
- consoleLogSpy.calledWith(
255
- `✅ Scheduled request executed successfully: ${id}`
256
- )
257
- ).to.be.true;
258
-
259
- consoleLogSpy.restore();
260
- });
261
- });
262
- });
263
-
264
- let globalAgenda: Agenda;
265
- before(() => {
266
- const cronService = new NodeCronAdapter();
267
- globalAgenda = new Agenda(cronService);
268
- });
269
-
270
- after(async () => {
271
- if (globalAgenda) {
272
- globalAgenda.stopAll();
273
- await new Promise((resolve) => setTimeout(resolve, 100));
274
- }
275
-
276
- await globalAgenda.stop();
277
- await globalAgenda.cancel({});
278
- await new Promise((resolve) => setTimeout(resolve, 100));
279
- });