@ai.ntellect/core 0.4.1 → 0.6.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 (125) hide show
  1. package/.mocharc.json +1 -1
  2. package/README.md +311 -272
  3. package/dist/graph/controller.js +63 -0
  4. package/dist/graph/engine.js +563 -0
  5. package/dist/index.js +6 -6
  6. package/dist/memory/adapters/meilisearch/index.js +249 -0
  7. package/dist/memory/adapters/redis/index.js +96 -0
  8. package/dist/memory/index.js +9 -0
  9. package/dist/services/agenda.js +115 -0
  10. package/dist/services/embedding.js +40 -0
  11. package/dist/services/queue.js +99 -103
  12. package/dist/test/graph/controller.test.js +170 -0
  13. package/dist/test/graph/engine.test.js +465 -0
  14. package/dist/test/memory/adapters/meilisearch.test.js +250 -0
  15. package/dist/test/memory/adapters/redis.test.js +143 -0
  16. package/dist/test/memory/base.test.js +209 -0
  17. package/dist/test/services/agenda.test.js +230 -0
  18. package/dist/test/services/queue.test.js +258 -0
  19. package/dist/types/index.js +2 -0
  20. package/dist/utils/generate-object.js +32 -11
  21. package/dist/utils/inject-actions.js +2 -2
  22. package/dist/utils/queue-item-transformer.js +2 -2
  23. package/dist/utils/state-manager.js +20 -0
  24. package/graph/controller.ts +60 -0
  25. package/graph/engine.ts +709 -0
  26. package/index.ts +7 -7
  27. package/interfaces/index.ts +119 -0
  28. package/memory/adapters/meilisearch/index.ts +286 -0
  29. package/memory/adapters/redis/index.ts +103 -0
  30. package/memory/index.ts +22 -0
  31. package/package.json +9 -2
  32. package/services/agenda.ts +118 -0
  33. package/services/embedding.ts +26 -0
  34. package/services/queue.ts +5 -32
  35. package/test/.env.test +4 -0
  36. package/test/graph/controller.test.ts +186 -0
  37. package/test/graph/engine.test.ts +563 -0
  38. package/test/memory/adapters/meilisearch.test.ts +297 -0
  39. package/test/memory/adapters/redis.test.ts +160 -0
  40. package/test/memory/base.test.ts +229 -0
  41. package/test/services/agenda.test.ts +280 -0
  42. package/test/services/queue.test.ts +286 -44
  43. package/tsconfig.json +10 -9
  44. package/types/index.ts +270 -0
  45. package/utils/generate-object.js +111 -0
  46. package/utils/generate-object.ts +24 -12
  47. package/utils/header-builder.js +34 -0
  48. package/utils/inject-actions.js +16 -0
  49. package/utils/inject-actions.ts +3 -3
  50. package/utils/queue-item-transformer.js +24 -0
  51. package/utils/queue-item-transformer.ts +8 -11
  52. package/utils/sanitize-results.js +60 -0
  53. package/utils/schema-generator.js +46 -0
  54. package/utils/state-manager.js +20 -0
  55. package/utils/state-manager.ts +30 -0
  56. package/.nvmrc +0 -1
  57. package/README.FR.md +0 -365
  58. package/agent/index.ts +0 -244
  59. package/agent/tools/get-rss.ts +0 -64
  60. package/bull.ts +0 -5
  61. package/dist/agent/index.d.ts +0 -38
  62. package/dist/agent/index.js +0 -143
  63. package/dist/agent/tools/get-rss.d.ts +0 -16
  64. package/dist/agent/tools/get-rss.js +0 -62
  65. package/dist/bull.d.ts +0 -1
  66. package/dist/bull.js +0 -9
  67. package/dist/examples/index.d.ts +0 -2
  68. package/dist/examples/index.js +0 -89
  69. package/dist/index.d.ts +0 -7
  70. package/dist/llm/interpreter/context.d.ts +0 -15
  71. package/dist/llm/interpreter/context.js +0 -89
  72. package/dist/llm/interpreter/index.d.ts +0 -21
  73. package/dist/llm/interpreter/index.js +0 -87
  74. package/dist/llm/memory-manager/context.d.ts +0 -2
  75. package/dist/llm/memory-manager/context.js +0 -22
  76. package/dist/llm/memory-manager/index.d.ts +0 -17
  77. package/dist/llm/memory-manager/index.js +0 -107
  78. package/dist/llm/orchestrator/context.d.ts +0 -2
  79. package/dist/llm/orchestrator/context.js +0 -23
  80. package/dist/llm/orchestrator/index.d.ts +0 -44
  81. package/dist/llm/orchestrator/index.js +0 -139
  82. package/dist/llm/orchestrator/types.d.ts +0 -12
  83. package/dist/memory/cache.d.ts +0 -22
  84. package/dist/memory/cache.js +0 -165
  85. package/dist/memory/persistent.d.ts +0 -57
  86. package/dist/memory/persistent.js +0 -189
  87. package/dist/services/queue.d.ts +0 -13
  88. package/dist/services/redis-cache.d.ts +0 -37
  89. package/dist/services/redis-cache.js +0 -93
  90. package/dist/services/scheduler.d.ts +0 -40
  91. package/dist/services/scheduler.js +0 -99
  92. package/dist/services/telegram-monitor.d.ts +0 -0
  93. package/dist/services/telegram-monitor.js +0 -118
  94. package/dist/t.d.ts +0 -46
  95. package/dist/t.js +0 -102
  96. package/dist/test.d.ts +0 -0
  97. package/dist/test.js +0 -438
  98. package/dist/types.d.ts +0 -258
  99. package/dist/types.js +0 -22
  100. package/dist/utils/generate-object.d.ts +0 -12
  101. package/dist/utils/header-builder.d.ts +0 -11
  102. package/dist/utils/inject-actions.d.ts +0 -2
  103. package/dist/utils/queue-item-transformer.d.ts +0 -7
  104. package/dist/utils/sanitize-results.d.ts +0 -17
  105. package/dist/utils/schema-generator.d.ts +0 -16
  106. package/examples/index.ts +0 -103
  107. package/llm/interpreter/context.ts +0 -101
  108. package/llm/interpreter/index.ts +0 -136
  109. package/llm/memory-manager/context.ts +0 -21
  110. package/llm/memory-manager/index.ts +0 -163
  111. package/llm/orchestrator/context.ts +0 -22
  112. package/llm/orchestrator/index.ts +0 -232
  113. package/llm/orchestrator/types.ts +0 -14
  114. package/memory/cache.ts +0 -221
  115. package/memory/persistent.ts +0 -265
  116. package/services/redis-cache.ts +0 -128
  117. package/services/scheduler.ts +0 -128
  118. package/services/telegram-monitor.ts +0 -138
  119. package/t.py +0 -79
  120. package/t.spec +0 -38
  121. package/t.ts +0 -133
  122. package/test/llm/orchestrator.test.ts +0 -47
  123. package/test/llm/synthesizer.test.ts +0 -31
  124. package/types.ts +0 -288
  125. /package/dist/{llm/orchestrator/types.js → interfaces/index.js} +0 -0
@@ -0,0 +1,297 @@
1
+ import { BaseMemoryService } from "@/interfaces";
2
+ import { MeilisearchAdapter } from "@/memory/adapters/meilisearch";
3
+ import { BaseMemoryType } from "@/types";
4
+ import { expect } from "chai";
5
+ import dotenv from "dotenv";
6
+
7
+ // Load environment variables
8
+ dotenv.config();
9
+
10
+ describe("MeilisearchAdapter", () => {
11
+ let meilisearchAdapter: MeilisearchAdapter;
12
+ let mockBaseMemoryService: BaseMemoryService;
13
+ const TEST_ROOM_ID = "test-room";
14
+
15
+ const testMemory: BaseMemoryType = {
16
+ id: "test-id",
17
+ data: "test data",
18
+ query: "test query",
19
+ embedding: [0.1, 0.2, 0.3],
20
+ roomId: "test-room",
21
+ createdAt: new Date(),
22
+ };
23
+
24
+ beforeEach(() => {
25
+ // Use real Meilisearch if environment variables are set, otherwise mock
26
+ if (process.env.MEILISEARCH_HOST && process.env.MEILISEARCH_API_KEY) {
27
+ // Real Meilisearch configuration
28
+ // console.log("Real Meilisearch configuration");
29
+ meilisearchAdapter = new MeilisearchAdapter(
30
+ {
31
+ host: process.env.MEILISEARCH_HOST,
32
+ apiKey: process.env.MEILISEARCH_API_KEY,
33
+ searchableAttributes: ["content"],
34
+ sortableAttributes: ["createdAt"],
35
+ },
36
+ mockBaseMemoryService
37
+ );
38
+ } else {
39
+ // Mock fetch implementation
40
+ // console.log("Mock Meilisearch configuration");
41
+ global.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
42
+ const url = input.toString();
43
+
44
+ // Mock for index check/creation
45
+ if (url.includes("/indexes")) {
46
+ if (init?.method === "POST") {
47
+ return new Response(JSON.stringify({ taskUid: 1 }));
48
+ }
49
+ if (url.endsWith("/indexes")) {
50
+ return new Response(JSON.stringify({ results: [] }));
51
+ }
52
+ // Mock for specific index check
53
+ if (url.includes(`/indexes/${TEST_ROOM_ID}`)) {
54
+ return new Response(
55
+ JSON.stringify({
56
+ uid: TEST_ROOM_ID,
57
+ primaryKey: "id",
58
+ })
59
+ );
60
+ }
61
+ if (url.includes("/indexes/memories")) {
62
+ return new Response(
63
+ JSON.stringify({
64
+ uid: "memories",
65
+ primaryKey: "id",
66
+ })
67
+ );
68
+ }
69
+ }
70
+
71
+ // Mock for settings
72
+ if (url.includes("/settings")) {
73
+ return new Response(JSON.stringify({ acknowledged: true }));
74
+ }
75
+
76
+ // Mock for documents
77
+ if (url.includes("/documents")) {
78
+ if (init?.method === "POST") {
79
+ return new Response(JSON.stringify({ taskUid: 2 }));
80
+ }
81
+ if (init?.method === "DELETE") {
82
+ return new Response(JSON.stringify({ taskUid: 3 }));
83
+ }
84
+ return new Response(JSON.stringify([testMemory]));
85
+ }
86
+
87
+ return new Response(JSON.stringify({}));
88
+ };
89
+
90
+ mockBaseMemoryService = {
91
+ initializeConnection: async () => {},
92
+ createMemory: async () => {},
93
+ getMemoryById: async () => testMemory,
94
+ getMemoryByIndex: async () => [testMemory],
95
+ getAllMemories: async () => [testMemory],
96
+ clearMemoryById: async () => {},
97
+ clearAllMemories: async () => {},
98
+ };
99
+
100
+ meilisearchAdapter = new MeilisearchAdapter(
101
+ {
102
+ host: "http://localhost:7700",
103
+ apiKey: "aSampleMasterKey",
104
+ searchableAttributes: ["content"],
105
+ sortableAttributes: ["createdAt"],
106
+ },
107
+ mockBaseMemoryService
108
+ );
109
+ }
110
+ });
111
+
112
+ describe("Initialization", () => {
113
+ it("should initialize storage", async () => {
114
+ await expect(meilisearchAdapter.init()).to.not.throw;
115
+ });
116
+ });
117
+
118
+ describe("Memory Operations", () => {
119
+ beforeEach(async () => {
120
+ // Reset fetch mock for each test
121
+ if (!process.env.MEILISEARCH_HOST) {
122
+ global.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
123
+ const url = input.toString();
124
+
125
+ // Mock for index check/creation
126
+ if (url.includes("/indexes")) {
127
+ if (init?.method === "POST") {
128
+ return new Response(JSON.stringify({ taskUid: 1 }));
129
+ }
130
+ if (url.endsWith("/indexes")) {
131
+ return new Response(JSON.stringify({ results: [] }));
132
+ }
133
+ // Mock for specific index check
134
+ if (url.includes(`/indexes/${TEST_ROOM_ID}`)) {
135
+ return new Response(
136
+ JSON.stringify({
137
+ uid: TEST_ROOM_ID,
138
+ primaryKey: "id",
139
+ })
140
+ );
141
+ }
142
+ if (url.includes("/indexes/memories")) {
143
+ return new Response(
144
+ JSON.stringify({
145
+ uid: "memories",
146
+ primaryKey: "id",
147
+ })
148
+ );
149
+ }
150
+ }
151
+
152
+ // Mock for settings
153
+ if (url.includes("/settings")) {
154
+ return new Response(JSON.stringify({ acknowledged: true }));
155
+ }
156
+
157
+ // Mock for documents
158
+ if (url.includes("/documents")) {
159
+ if (init?.method === "POST") {
160
+ return new Response(JSON.stringify({ taskUid: 2 }));
161
+ }
162
+ if (init?.method === "DELETE") {
163
+ return new Response(JSON.stringify({ taskUid: 3 }));
164
+ }
165
+ return new Response(JSON.stringify([testMemory]));
166
+ }
167
+
168
+ return new Response(JSON.stringify({}));
169
+ };
170
+ }
171
+
172
+ try {
173
+ await meilisearchAdapter.init();
174
+ await meilisearchAdapter.initializeStorage(TEST_ROOM_ID);
175
+ } catch (error) {
176
+ console.error("Failed to initialize:", error);
177
+ throw error;
178
+ }
179
+ });
180
+
181
+ it("should create memory", async () => {
182
+ const result = await meilisearchAdapter.createMemory({
183
+ data: "test data",
184
+ query: "test query",
185
+ roomId: TEST_ROOM_ID,
186
+ });
187
+
188
+ expect(result).to.exist;
189
+ expect(result?.data).to.equal("test data");
190
+ expect(result?.embedding).to.be.null;
191
+ });
192
+
193
+ it("should search memories", async () => {
194
+ const results = await meilisearchAdapter.getMemoryByIndex("test", {
195
+ roomId: TEST_ROOM_ID,
196
+ limit: 10,
197
+ });
198
+
199
+ expect(results).to.be.an("array");
200
+ if (results.length > 0) {
201
+ const result = results[0];
202
+ if (result) {
203
+ result.createdAt = new Date(result.createdAt);
204
+ }
205
+ expect(result).to.deep.equal(testMemory);
206
+ }
207
+ });
208
+
209
+ it("should handle memory retrieval by ID", async () => {
210
+ global.fetch = async (input: RequestInfo | URL) => {
211
+ const url = input.toString();
212
+ if (url.includes(`/indexes/${TEST_ROOM_ID}/documents/test-id`)) {
213
+ return new Response(
214
+ JSON.stringify({
215
+ ...testMemory,
216
+ createdAt: testMemory.createdAt.toISOString(),
217
+ })
218
+ );
219
+ }
220
+ return new Response(JSON.stringify({}));
221
+ };
222
+
223
+ const result = await meilisearchAdapter.getMemoryById(
224
+ "test-id",
225
+ TEST_ROOM_ID
226
+ );
227
+ if (result) {
228
+ result.createdAt = new Date(result.createdAt);
229
+ }
230
+ expect(result).to.deep.equal(testMemory);
231
+ });
232
+
233
+ it("should handle non-existent memory", async () => {
234
+ global.fetch = async (): Promise<Response> => {
235
+ throw new Error("Not found");
236
+ };
237
+
238
+ const result = await meilisearchAdapter.getMemoryById(
239
+ "non-existent",
240
+ TEST_ROOM_ID
241
+ );
242
+ expect(result).to.be.null;
243
+ });
244
+
245
+ it("should clear all memories", async () => {
246
+ await expect(meilisearchAdapter.clearAllMemories()).to.not.throw;
247
+ });
248
+
249
+ it("should not create duplicate memory with same data", async () => {
250
+ // Create first memory
251
+ const firstMemory = await meilisearchAdapter.createMemory({
252
+ data: "test data",
253
+ query: "test query",
254
+ roomId: TEST_ROOM_ID,
255
+ });
256
+
257
+ // Try to create second memory with same data
258
+ const secondMemory = await meilisearchAdapter.createMemory({
259
+ data: "test data",
260
+ query: "test query",
261
+ roomId: TEST_ROOM_ID,
262
+ });
263
+
264
+ expect(secondMemory).to.exist;
265
+ expect(secondMemory?.id).to.equal(firstMemory?.id);
266
+ expect(secondMemory?.data).to.equal(firstMemory?.data);
267
+ expect(secondMemory?.query).to.equal(firstMemory?.query);
268
+ expect(secondMemory?.roomId).to.equal(firstMemory?.roomId);
269
+ });
270
+
271
+ it("should initialize storage", async () => {
272
+ global.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
273
+ const url = input.toString();
274
+
275
+ // Mock pour la vérification de l'existence de l'index
276
+ if (url.includes(`/indexes/${TEST_ROOM_ID}`)) {
277
+ return new Response(
278
+ JSON.stringify({
279
+ uid: TEST_ROOM_ID,
280
+ primaryKey: "id",
281
+ })
282
+ );
283
+ }
284
+
285
+ // Mock pour les settings
286
+ if (url.includes("/settings")) {
287
+ return new Response(JSON.stringify({ acknowledged: true }));
288
+ }
289
+
290
+ return new Response(JSON.stringify({}));
291
+ };
292
+
293
+ await expect(meilisearchAdapter.initializeStorage(TEST_ROOM_ID)).to.not
294
+ .throw;
295
+ });
296
+ });
297
+ });
@@ -0,0 +1,160 @@
1
+ import { BaseMemoryService } from "@/interfaces";
2
+ import { RedisAdapter } from "@/memory/adapters/redis";
3
+ import { BaseMemoryType } from "@/types";
4
+ import { expect } from "chai";
5
+ import dotenv from "dotenv";
6
+ import Redis from "ioredis";
7
+
8
+ // Load environment variables
9
+ dotenv.config();
10
+
11
+ describe("RedisAdapter", () => {
12
+ before(function () {
13
+ this.timeout(15000);
14
+ });
15
+
16
+ let redisAdapter: RedisAdapter;
17
+ let mockBaseMemoryService: BaseMemoryService;
18
+ let redisClient: Redis | null = null;
19
+ const fixedDate = new Date("2025-01-30T07:43:50.626Z");
20
+
21
+ const testMemory: BaseMemoryType = {
22
+ id: "test-id",
23
+ data: "test data",
24
+ query: "test query",
25
+ embedding: [0.1, 0.2, 0.3],
26
+ roomId: "test-room",
27
+ createdAt: fixedDate,
28
+ };
29
+
30
+ beforeEach(async () => {
31
+ mockBaseMemoryService = {
32
+ initializeConnection: async () => {},
33
+ createMemory: async () => {},
34
+ getMemoryById: async () => testMemory,
35
+ getMemoryByIndex: async () => [testMemory],
36
+ getAllMemories: async () => [testMemory],
37
+ clearMemoryById: async () => {},
38
+ clearAllMemories: async () => {},
39
+ };
40
+
41
+ // Use real Redis if environment variables are set, otherwise mock
42
+ if (process.env.REDIS_URL) {
43
+ redisClient = new Redis(process.env.REDIS_URL);
44
+ redisAdapter = new RedisAdapter(process.env.REDIS_URL, {
45
+ cachePrefix: "test-prefix",
46
+ cacheTTL: 3600,
47
+ });
48
+ } else {
49
+ // Mock Redis implementation
50
+ const mockRedis = {
51
+ connect: async () => {},
52
+ disconnect: async () => {},
53
+ set: async (key: string, value: string) => "OK",
54
+ get: async (key: string) => {
55
+ if (key.includes("test-id")) {
56
+ return JSON.stringify({
57
+ ...testMemory,
58
+ createdAt: fixedDate.toISOString(),
59
+ });
60
+ }
61
+ return null;
62
+ },
63
+ keys: async (pattern: string) => {
64
+ return [`${pattern}test-id`];
65
+ },
66
+ mget: async (keys: string[]) => {
67
+ return keys.map(() =>
68
+ JSON.stringify({
69
+ ...testMemory,
70
+ createdAt: fixedDate.toISOString(),
71
+ })
72
+ );
73
+ },
74
+ del: async () => 1,
75
+ flushall: async () => "OK",
76
+ quit: async () => {},
77
+ };
78
+
79
+ redisAdapter = new RedisAdapter(mockRedis as any, {
80
+ cachePrefix: "test-prefix",
81
+ cacheTTL: 3600,
82
+ });
83
+ }
84
+
85
+ await redisAdapter.initializeConnection();
86
+ });
87
+
88
+ afterEach(async () => {
89
+ if (redisClient) {
90
+ await redisClient.quit();
91
+ redisClient = null;
92
+ }
93
+ // @ts-ignore pour éviter l'erreur de typage
94
+ await redisAdapter?.quit?.();
95
+ });
96
+
97
+ describe("Initialization", () => {
98
+ it("should initialize storage", async () => {
99
+ await expect(redisAdapter.initializeConnection()).to.not.throw;
100
+ });
101
+ });
102
+
103
+ describe("Memory Operations", () => {
104
+ const TEST_ROOM_ID = "test-room";
105
+
106
+ it("should create memory", async () => {
107
+ await expect(
108
+ redisAdapter.createMemory({
109
+ data: "test data",
110
+ query: "test query",
111
+ roomId: TEST_ROOM_ID,
112
+ id: "test-id",
113
+ embedding: [0.1, 0.2, 0.3],
114
+ createdAt: fixedDate,
115
+ })
116
+ ).to.not.throw;
117
+ });
118
+
119
+ it("should get memory by ID", async () => {
120
+ const result = await redisAdapter.getMemoryById("test-id", TEST_ROOM_ID);
121
+ if (result) {
122
+ result.createdAt = new Date(result.createdAt);
123
+ }
124
+ expect(result).to.deep.equal({
125
+ ...testMemory,
126
+ createdAt: testMemory.createdAt,
127
+ });
128
+ });
129
+
130
+ it("should get memories by index", async () => {
131
+ const results = await redisAdapter.getMemoryByIndex("test", {
132
+ roomId: TEST_ROOM_ID,
133
+ limit: 10,
134
+ });
135
+
136
+ expect(results).to.be.an("array");
137
+ if (results[0]) {
138
+ results[0].createdAt = new Date(results[0].createdAt);
139
+ }
140
+ expect(results[0]).to.deep.equal(testMemory);
141
+ });
142
+
143
+ it("should get all memories", async () => {
144
+ const results = await redisAdapter.getAllMemories();
145
+ expect(results).to.be.an("array");
146
+ if (results[0]) {
147
+ results[0].createdAt = new Date(results[0].createdAt);
148
+ }
149
+ expect(results[0]).to.deep.equal(testMemory);
150
+ });
151
+
152
+ it("should clear memory by ID", async () => {
153
+ await expect(redisAdapter.clearMemoryById("test-id")).to.not.throw;
154
+ });
155
+
156
+ it("should clear all memories", async () => {
157
+ await expect(redisAdapter.clearAllMemories()).to.not.throw;
158
+ });
159
+ });
160
+ });
@@ -0,0 +1,229 @@
1
+ import { BaseMemoryService } from "@/interfaces";
2
+ import { BaseMemory } from "@/memory";
3
+ import { BaseMemoryType, CreateMemoryInput } from "@/types";
4
+ import { expect } from "chai";
5
+
6
+ /**
7
+ * Test suite for the BaseMemory service
8
+ * This suite tests the memory management system that handles storage and retrieval of memory entries
9
+ */
10
+
11
+ // Classe concrète pour tester BaseMemory
12
+ class TestMemory extends BaseMemory {
13
+ async init(): Promise<void> {
14
+ await this.cacheService.initializeConnection();
15
+ }
16
+
17
+ async createMemory(
18
+ input: CreateMemoryInput & { embedding?: number[] }
19
+ ): Promise<BaseMemoryType | undefined> {
20
+ const memory: BaseMemoryType = {
21
+ id: crypto.randomUUID(),
22
+ data: input.data,
23
+ query: input.query,
24
+ embedding: input.embedding || null,
25
+ roomId: input.roomId,
26
+ createdAt: new Date(),
27
+ };
28
+ await this.cacheService.createMemory(memory, input.ttl);
29
+ return memory;
30
+ }
31
+
32
+ async getMemoryById(
33
+ id: string,
34
+ roomId: string
35
+ ): Promise<BaseMemoryType | null> {
36
+ return this.cacheService.getMemoryById(id);
37
+ }
38
+
39
+ async getMemoryByIndex(
40
+ query: string,
41
+ options: { roomId: string; limit?: number }
42
+ ): Promise<BaseMemoryType[]> {
43
+ return this.cacheService.getMemoryByIndex(query, options);
44
+ }
45
+
46
+ async getAllMemories(roomId: string): Promise<BaseMemoryType[]> {
47
+ return this.cacheService.getAllMemories();
48
+ }
49
+
50
+ async clearMemoryById(id: string, roomId: string): Promise<void> {
51
+ await this.cacheService.clearMemoryById(id);
52
+ }
53
+
54
+ async clearAllMemories(): Promise<void> {
55
+ await this.cacheService.clearAllMemories();
56
+ }
57
+ }
58
+
59
+ describe("BaseMemory", () => {
60
+ let memory: TestMemory;
61
+ let mockMemoryService: BaseMemoryService;
62
+ const TEST_ROOM_ID = "test-room";
63
+
64
+ // Mock data for testing
65
+ const testMemory: BaseMemoryType = {
66
+ id: "test-id",
67
+ data: "test data",
68
+ query: "test query",
69
+ embedding: [0.1, 0.2, 0.3],
70
+ roomId: "test-room",
71
+ createdAt: new Date(),
72
+ };
73
+
74
+ beforeEach(() => {
75
+ // Create mock implementation of BaseMemoryService
76
+ mockMemoryService = {
77
+ initializeConnection: async () => Promise.resolve(),
78
+ createMemory: async (memory: BaseMemoryType) => Promise.resolve(),
79
+ getMemoryById: async (id: string) => Promise.resolve(testMemory),
80
+ getMemoryByIndex: async (query: string, options: any) =>
81
+ Promise.resolve([testMemory]),
82
+ getAllMemories: async () => Promise.resolve([testMemory]),
83
+ clearMemoryById: async (id: string) => Promise.resolve(),
84
+ clearAllMemories: async () => Promise.resolve(),
85
+ };
86
+
87
+ memory = new TestMemory(mockMemoryService);
88
+ });
89
+
90
+ describe("Initialization", () => {
91
+ it("should initialize the memory service", async () => {
92
+ let initCalled = false;
93
+ mockMemoryService.initializeConnection = async () => {
94
+ initCalled = true;
95
+ };
96
+
97
+ await memory.init();
98
+ expect(initCalled).to.be.true;
99
+ });
100
+ });
101
+
102
+ describe("Memory Creation", () => {
103
+ it("should create a new memory entry", async () => {
104
+ const input = {
105
+ data: "test data",
106
+ query: "test query",
107
+ roomId: "test-room",
108
+ ttl: 3600,
109
+ };
110
+
111
+ const result = await memory.createMemory(input);
112
+
113
+ expect(result).to.exist;
114
+ expect(result?.data).to.equal(input.data);
115
+ expect(result?.query).to.equal(input.query);
116
+ expect(result?.roomId).to.equal(input.roomId);
117
+ expect(result?.id).to.be.a("string");
118
+ });
119
+
120
+ it("should create memory with embedding", async () => {
121
+ const input = {
122
+ data: "test data",
123
+ query: "test query",
124
+ roomId: "test-room",
125
+ embedding: [0.1, 0.2, 0.3],
126
+ };
127
+
128
+ const result = await memory.createMemory(input);
129
+
130
+ expect(result?.embedding).to.deep.equal(input.embedding);
131
+ });
132
+ });
133
+
134
+ describe("Memory Retrieval", () => {
135
+ it("should retrieve memory by ID", async () => {
136
+ const result = await memory.getMemoryById("test-id", TEST_ROOM_ID);
137
+ expect(result).to.deep.equal(testMemory);
138
+ });
139
+
140
+ it("should retrieve memories by index", async () => {
141
+ const results = await memory.getMemoryByIndex("test query", {
142
+ roomId: "test-room",
143
+ limit: 10,
144
+ });
145
+
146
+ expect(results).to.be.an("array");
147
+ expect(results[0]).to.deep.equal(testMemory);
148
+ });
149
+
150
+ it("should retrieve all memories", async () => {
151
+ const results = await memory.getAllMemories(TEST_ROOM_ID);
152
+ expect(results).to.be.an("array");
153
+ });
154
+ });
155
+
156
+ describe("Memory Clearing", () => {
157
+ it("should clear memory by ID", async () => {
158
+ await memory.clearMemoryById("test-id", TEST_ROOM_ID);
159
+ });
160
+
161
+ it("should clear all memories", async () => {
162
+ await memory.clearAllMemories();
163
+ });
164
+ });
165
+
166
+ describe("Error Handling", () => {
167
+ it("should handle errors during memory creation", async () => {
168
+ mockMemoryService.createMemory = async () => {
169
+ throw new Error("Creation failed");
170
+ };
171
+
172
+ try {
173
+ await memory.createMemory({
174
+ data: "test",
175
+ query: "test",
176
+ roomId: "test",
177
+ });
178
+ expect.fail("Should have thrown an error");
179
+ } catch (error) {
180
+ expect(error).to.be.instanceOf(Error);
181
+ expect((error as Error).message).to.equal("Creation failed");
182
+ }
183
+ });
184
+
185
+ it("should handle errors during memory retrieval", async () => {
186
+ mockMemoryService.getMemoryById = async () => {
187
+ throw new Error("Retrieval failed");
188
+ };
189
+
190
+ try {
191
+ await memory.getMemoryById("test-id", TEST_ROOM_ID);
192
+ expect.fail("Should have thrown an error");
193
+ } catch (error) {
194
+ expect(error).to.be.instanceOf(Error);
195
+ expect((error as Error).message).to.equal("Retrieval failed");
196
+ }
197
+ });
198
+ });
199
+
200
+ describe("Edge Cases", () => {
201
+ it("should handle undefined embedding", async () => {
202
+ const input = {
203
+ data: "test data",
204
+ query: "test query",
205
+ roomId: "test-room",
206
+ embedding: undefined,
207
+ };
208
+
209
+ const result = await memory.createMemory(input);
210
+ expect(result?.embedding).to.be.null;
211
+ });
212
+
213
+ it("should handle empty query results", async () => {
214
+ mockMemoryService.getMemoryByIndex = async () => [];
215
+
216
+ const results = await memory.getMemoryByIndex("nonexistent", {
217
+ roomId: "test-room",
218
+ });
219
+ expect(results).to.be.an("array").that.is.empty;
220
+ });
221
+
222
+ it("should handle non-existent memory ID", async () => {
223
+ mockMemoryService.getMemoryById = async () => null;
224
+
225
+ const result = await memory.getMemoryById("nonexistent", TEST_ROOM_ID);
226
+ expect(result).to.be.null;
227
+ });
228
+ });
229
+ });