@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.
- package/.mocharc.json +1 -1
- package/README.md +311 -272
- package/dist/graph/controller.js +63 -0
- package/dist/graph/engine.js +563 -0
- package/dist/index.js +6 -6
- package/dist/memory/adapters/meilisearch/index.js +249 -0
- package/dist/memory/adapters/redis/index.js +96 -0
- package/dist/memory/index.js +9 -0
- package/dist/services/agenda.js +115 -0
- package/dist/services/embedding.js +40 -0
- package/dist/services/queue.js +99 -103
- package/dist/test/graph/controller.test.js +170 -0
- package/dist/test/graph/engine.test.js +465 -0
- package/dist/test/memory/adapters/meilisearch.test.js +250 -0
- package/dist/test/memory/adapters/redis.test.js +143 -0
- package/dist/test/memory/base.test.js +209 -0
- package/dist/test/services/agenda.test.js +230 -0
- package/dist/test/services/queue.test.js +258 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/generate-object.js +32 -11
- package/dist/utils/inject-actions.js +2 -2
- package/dist/utils/queue-item-transformer.js +2 -2
- package/dist/utils/state-manager.js +20 -0
- package/graph/controller.ts +60 -0
- package/graph/engine.ts +709 -0
- package/index.ts +7 -7
- package/interfaces/index.ts +119 -0
- package/memory/adapters/meilisearch/index.ts +286 -0
- package/memory/adapters/redis/index.ts +103 -0
- package/memory/index.ts +22 -0
- package/package.json +9 -2
- package/services/agenda.ts +118 -0
- package/services/embedding.ts +26 -0
- package/services/queue.ts +5 -32
- package/test/.env.test +4 -0
- package/test/graph/controller.test.ts +186 -0
- package/test/graph/engine.test.ts +563 -0
- package/test/memory/adapters/meilisearch.test.ts +297 -0
- package/test/memory/adapters/redis.test.ts +160 -0
- package/test/memory/base.test.ts +229 -0
- package/test/services/agenda.test.ts +280 -0
- package/test/services/queue.test.ts +286 -44
- package/tsconfig.json +10 -9
- package/types/index.ts +270 -0
- package/utils/generate-object.js +111 -0
- package/utils/generate-object.ts +24 -12
- package/utils/header-builder.js +34 -0
- package/utils/inject-actions.js +16 -0
- package/utils/inject-actions.ts +3 -3
- package/utils/queue-item-transformer.js +24 -0
- package/utils/queue-item-transformer.ts +8 -11
- package/utils/sanitize-results.js +60 -0
- package/utils/schema-generator.js +46 -0
- package/utils/state-manager.js +20 -0
- package/utils/state-manager.ts +30 -0
- package/.nvmrc +0 -1
- package/README.FR.md +0 -365
- package/agent/index.ts +0 -244
- package/agent/tools/get-rss.ts +0 -64
- package/bull.ts +0 -5
- package/dist/agent/index.d.ts +0 -38
- package/dist/agent/index.js +0 -143
- package/dist/agent/tools/get-rss.d.ts +0 -16
- package/dist/agent/tools/get-rss.js +0 -62
- package/dist/bull.d.ts +0 -1
- package/dist/bull.js +0 -9
- package/dist/examples/index.d.ts +0 -2
- package/dist/examples/index.js +0 -89
- package/dist/index.d.ts +0 -7
- package/dist/llm/interpreter/context.d.ts +0 -15
- package/dist/llm/interpreter/context.js +0 -89
- package/dist/llm/interpreter/index.d.ts +0 -21
- package/dist/llm/interpreter/index.js +0 -87
- package/dist/llm/memory-manager/context.d.ts +0 -2
- package/dist/llm/memory-manager/context.js +0 -22
- package/dist/llm/memory-manager/index.d.ts +0 -17
- package/dist/llm/memory-manager/index.js +0 -107
- package/dist/llm/orchestrator/context.d.ts +0 -2
- package/dist/llm/orchestrator/context.js +0 -23
- package/dist/llm/orchestrator/index.d.ts +0 -44
- package/dist/llm/orchestrator/index.js +0 -139
- package/dist/llm/orchestrator/types.d.ts +0 -12
- package/dist/memory/cache.d.ts +0 -22
- package/dist/memory/cache.js +0 -165
- package/dist/memory/persistent.d.ts +0 -57
- package/dist/memory/persistent.js +0 -189
- package/dist/services/queue.d.ts +0 -13
- package/dist/services/redis-cache.d.ts +0 -37
- package/dist/services/redis-cache.js +0 -93
- package/dist/services/scheduler.d.ts +0 -40
- package/dist/services/scheduler.js +0 -99
- package/dist/services/telegram-monitor.d.ts +0 -0
- package/dist/services/telegram-monitor.js +0 -118
- package/dist/t.d.ts +0 -46
- package/dist/t.js +0 -102
- package/dist/test.d.ts +0 -0
- package/dist/test.js +0 -438
- package/dist/types.d.ts +0 -258
- package/dist/types.js +0 -22
- package/dist/utils/generate-object.d.ts +0 -12
- package/dist/utils/header-builder.d.ts +0 -11
- package/dist/utils/inject-actions.d.ts +0 -2
- package/dist/utils/queue-item-transformer.d.ts +0 -7
- package/dist/utils/sanitize-results.d.ts +0 -17
- package/dist/utils/schema-generator.d.ts +0 -16
- package/examples/index.ts +0 -103
- package/llm/interpreter/context.ts +0 -101
- package/llm/interpreter/index.ts +0 -136
- package/llm/memory-manager/context.ts +0 -21
- package/llm/memory-manager/index.ts +0 -163
- package/llm/orchestrator/context.ts +0 -22
- package/llm/orchestrator/index.ts +0 -232
- package/llm/orchestrator/types.ts +0 -14
- package/memory/cache.ts +0 -221
- package/memory/persistent.ts +0 -265
- package/services/redis-cache.ts +0 -128
- package/services/scheduler.ts +0 -128
- package/services/telegram-monitor.ts +0 -138
- package/t.py +0 -79
- package/t.spec +0 -38
- package/t.ts +0 -133
- package/test/llm/orchestrator.test.ts +0 -47
- package/test/llm/synthesizer.test.ts +0 -31
- package/types.ts +0 -288
- /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
|
+
});
|