@ai.ntellect/core 0.6.17 → 0.6.19
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 -2
- package/README.md +123 -178
- package/dist/graph/controller.js +29 -6
- package/dist/graph/index.js +302 -62
- package/dist/index.js +21 -6
- package/dist/interfaces/index.js +15 -0
- package/dist/modules/agenda/adapters/node-cron/index.js +29 -0
- package/dist/modules/agenda/index.js +140 -0
- package/dist/{services/embedding.js → modules/embedding/adapters/ai/index.js} +24 -7
- package/dist/modules/embedding/index.js +59 -0
- package/dist/modules/memory/adapters/in-memory/index.js +210 -0
- package/dist/{memory → modules/memory}/adapters/meilisearch/index.js +97 -2
- package/dist/{memory → modules/memory}/adapters/redis/index.js +77 -15
- package/dist/modules/memory/index.js +103 -0
- package/dist/utils/{stringifiy-zod-schema.js → generate-action-schema.js} +5 -5
- package/graph/controller.ts +37 -13
- package/graph/index.ts +348 -73
- package/index.ts +24 -6
- package/interfaces/index.ts +346 -27
- package/modules/agenda/adapters/node-cron/index.ts +25 -0
- package/modules/agenda/index.ts +159 -0
- package/modules/embedding/adapters/ai/index.ts +42 -0
- package/modules/embedding/index.ts +45 -0
- package/modules/memory/adapters/in-memory/index.ts +203 -0
- package/{memory → modules/memory}/adapters/meilisearch/index.ts +114 -12
- package/modules/memory/adapters/redis/index.ts +164 -0
- package/modules/memory/index.ts +93 -0
- package/package.json +3 -1
- package/test/graph/index.test.ts +646 -0
- package/test/modules/agenda/node-cron.test.ts +286 -0
- package/test/modules/embedding/ai.test.ts +78 -0
- package/test/modules/memory/adapters/in-memory.test.ts +153 -0
- package/test/{memory → modules/memory}/adapters/meilisearch.test.ts +79 -75
- package/test/modules/memory/adapters/redis.test.ts +169 -0
- package/test/modules/memory/base.test.ts +230 -0
- package/test/services/agenda.test.ts +279 -280
- package/types/index.ts +82 -203
- package/utils/{stringifiy-zod-schema.ts → generate-action-schema.ts} +3 -3
- package/app/README.md +0 -36
- package/app/app/favicon.ico +0 -0
- package/app/app/globals.css +0 -21
- package/app/app/gun.ts +0 -0
- package/app/app/layout.tsx +0 -18
- package/app/app/page.tsx +0 -321
- package/app/eslint.config.mjs +0 -16
- package/app/next.config.ts +0 -7
- package/app/package-lock.json +0 -5912
- package/app/package.json +0 -31
- package/app/pnpm-lock.yaml +0 -4031
- package/app/postcss.config.mjs +0 -8
- package/app/public/file.svg +0 -1
- package/app/public/globe.svg +0 -1
- package/app/public/next.svg +0 -1
- package/app/public/vercel.svg +0 -1
- package/app/public/window.svg +0 -1
- package/app/tailwind.config.ts +0 -18
- package/app/tsconfig.json +0 -27
- package/dist/memory/index.js +0 -9
- package/dist/services/agenda.js +0 -115
- package/dist/services/queue.js +0 -142
- package/dist/utils/experimental-graph-rag.js +0 -152
- package/dist/utils/generate-object.js +0 -111
- package/dist/utils/inject-actions.js +0 -16
- package/dist/utils/queue-item-transformer.js +0 -24
- package/dist/utils/sanitize-results.js +0 -60
- package/memory/adapters/redis/index.ts +0 -103
- package/memory/index.ts +0 -22
- package/services/agenda.ts +0 -118
- package/services/embedding.ts +0 -26
- package/services/queue.ts +0 -145
- package/test/memory/adapters/redis.test.ts +0 -159
- package/test/memory/base.test.ts +0 -225
- package/test/services/queue.test.ts +0 -286
- package/utils/experimental-graph-rag.ts +0 -170
- package/utils/generate-object.ts +0 -117
- package/utils/inject-actions.ts +0 -19
- package/utils/queue-item-transformer.ts +0 -38
- package/utils/sanitize-results.ts +0 -66
package/test/memory/base.test.ts
DELETED
@@ -1,225 +0,0 @@
|
|
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
|
-
embedding: input.embedding || null,
|
24
|
-
roomId: input.roomId,
|
25
|
-
createdAt: new Date(),
|
26
|
-
};
|
27
|
-
await this.cacheService.createMemory(memory, input.ttl);
|
28
|
-
return memory;
|
29
|
-
}
|
30
|
-
|
31
|
-
async getMemoryById(
|
32
|
-
id: string,
|
33
|
-
roomId: string
|
34
|
-
): Promise<BaseMemoryType | null> {
|
35
|
-
return this.cacheService.getMemoryById(id);
|
36
|
-
}
|
37
|
-
|
38
|
-
async getMemoryByIndex(
|
39
|
-
query: string,
|
40
|
-
options: { roomId: string; limit?: number }
|
41
|
-
): Promise<BaseMemoryType[]> {
|
42
|
-
return this.cacheService.getMemoryByIndex(query, options);
|
43
|
-
}
|
44
|
-
|
45
|
-
async getAllMemories(roomId: string): Promise<BaseMemoryType[]> {
|
46
|
-
return this.cacheService.getAllMemories();
|
47
|
-
}
|
48
|
-
|
49
|
-
async clearMemoryById(id: string, roomId: string): Promise<void> {
|
50
|
-
await this.cacheService.clearMemoryById(id);
|
51
|
-
}
|
52
|
-
|
53
|
-
async clearAllMemories(): Promise<void> {
|
54
|
-
await this.cacheService.clearAllMemories();
|
55
|
-
}
|
56
|
-
}
|
57
|
-
|
58
|
-
describe("BaseMemory", () => {
|
59
|
-
let memory: TestMemory;
|
60
|
-
let mockMemoryService: BaseMemoryService;
|
61
|
-
const TEST_ROOM_ID = "test-room";
|
62
|
-
|
63
|
-
// Mock data for testing
|
64
|
-
const testMemory: BaseMemoryType = {
|
65
|
-
id: "test-id",
|
66
|
-
data: "test data",
|
67
|
-
embedding: [0.1, 0.2, 0.3],
|
68
|
-
roomId: "test-room",
|
69
|
-
createdAt: new Date(),
|
70
|
-
};
|
71
|
-
|
72
|
-
beforeEach(() => {
|
73
|
-
// Create mock implementation of BaseMemoryService
|
74
|
-
mockMemoryService = {
|
75
|
-
initializeConnection: async () => Promise.resolve(),
|
76
|
-
createMemory: async (memory: BaseMemoryType) => Promise.resolve(),
|
77
|
-
getMemoryById: async (id: string) => Promise.resolve(testMemory),
|
78
|
-
getMemoryByIndex: async (query: string, options: any) =>
|
79
|
-
Promise.resolve([testMemory]),
|
80
|
-
getAllMemories: async () => Promise.resolve([testMemory]),
|
81
|
-
clearMemoryById: async (id: string) => Promise.resolve(),
|
82
|
-
clearAllMemories: async () => Promise.resolve(),
|
83
|
-
};
|
84
|
-
|
85
|
-
memory = new TestMemory(mockMemoryService);
|
86
|
-
});
|
87
|
-
|
88
|
-
describe("Initialization", () => {
|
89
|
-
it("should initialize the memory service", async () => {
|
90
|
-
let initCalled = false;
|
91
|
-
mockMemoryService.initializeConnection = async () => {
|
92
|
-
initCalled = true;
|
93
|
-
};
|
94
|
-
|
95
|
-
await memory.init();
|
96
|
-
expect(initCalled).to.be.true;
|
97
|
-
});
|
98
|
-
});
|
99
|
-
|
100
|
-
describe("Memory Creation", () => {
|
101
|
-
it("should create a new memory entry", async () => {
|
102
|
-
const input = {
|
103
|
-
data: "test data",
|
104
|
-
query: "test query",
|
105
|
-
roomId: "test-room",
|
106
|
-
ttl: 3600,
|
107
|
-
};
|
108
|
-
|
109
|
-
const result = await memory.createMemory(input);
|
110
|
-
|
111
|
-
expect(result).to.exist;
|
112
|
-
expect(result?.data).to.equal(input.data);
|
113
|
-
expect(result?.roomId).to.equal(input.roomId);
|
114
|
-
expect(result?.id).to.be.a("string");
|
115
|
-
});
|
116
|
-
|
117
|
-
it("should create memory with embedding", async () => {
|
118
|
-
const input = {
|
119
|
-
data: "test data",
|
120
|
-
query: "test query",
|
121
|
-
roomId: "test-room",
|
122
|
-
embedding: [0.1, 0.2, 0.3],
|
123
|
-
};
|
124
|
-
|
125
|
-
const result = await memory.createMemory(input);
|
126
|
-
|
127
|
-
expect(result?.embedding).to.deep.equal(input.embedding);
|
128
|
-
});
|
129
|
-
});
|
130
|
-
|
131
|
-
describe("Memory Retrieval", () => {
|
132
|
-
it("should retrieve memory by ID", async () => {
|
133
|
-
const result = await memory.getMemoryById("test-id", TEST_ROOM_ID);
|
134
|
-
expect(result).to.deep.equal(testMemory);
|
135
|
-
});
|
136
|
-
|
137
|
-
it("should retrieve memories by index", async () => {
|
138
|
-
const results = await memory.getMemoryByIndex("test query", {
|
139
|
-
roomId: "test-room",
|
140
|
-
limit: 10,
|
141
|
-
});
|
142
|
-
|
143
|
-
expect(results).to.be.an("array");
|
144
|
-
expect(results[0]).to.deep.equal(testMemory);
|
145
|
-
});
|
146
|
-
|
147
|
-
it("should retrieve all memories", async () => {
|
148
|
-
const results = await memory.getAllMemories(TEST_ROOM_ID);
|
149
|
-
expect(results).to.be.an("array");
|
150
|
-
});
|
151
|
-
});
|
152
|
-
|
153
|
-
describe("Memory Clearing", () => {
|
154
|
-
it("should clear memory by ID", async () => {
|
155
|
-
await memory.clearMemoryById("test-id", TEST_ROOM_ID);
|
156
|
-
});
|
157
|
-
|
158
|
-
it("should clear all memories", async () => {
|
159
|
-
await memory.clearAllMemories();
|
160
|
-
});
|
161
|
-
});
|
162
|
-
|
163
|
-
describe("Error Handling", () => {
|
164
|
-
it("should handle errors during memory creation", async () => {
|
165
|
-
mockMemoryService.createMemory = async () => {
|
166
|
-
throw new Error("Creation failed");
|
167
|
-
};
|
168
|
-
|
169
|
-
try {
|
170
|
-
await memory.createMemory({
|
171
|
-
data: "test",
|
172
|
-
roomId: "test",
|
173
|
-
});
|
174
|
-
expect.fail("Should have thrown an error");
|
175
|
-
} catch (error) {
|
176
|
-
expect(error).to.be.instanceOf(Error);
|
177
|
-
expect((error as Error).message).to.equal("Creation failed");
|
178
|
-
}
|
179
|
-
});
|
180
|
-
|
181
|
-
it("should handle errors during memory retrieval", async () => {
|
182
|
-
mockMemoryService.getMemoryById = async () => {
|
183
|
-
throw new Error("Retrieval failed");
|
184
|
-
};
|
185
|
-
|
186
|
-
try {
|
187
|
-
await memory.getMemoryById("test-id", TEST_ROOM_ID);
|
188
|
-
expect.fail("Should have thrown an error");
|
189
|
-
} catch (error) {
|
190
|
-
expect(error).to.be.instanceOf(Error);
|
191
|
-
expect((error as Error).message).to.equal("Retrieval failed");
|
192
|
-
}
|
193
|
-
});
|
194
|
-
});
|
195
|
-
|
196
|
-
describe("Edge Cases", () => {
|
197
|
-
it("should handle undefined embedding", async () => {
|
198
|
-
const input = {
|
199
|
-
data: "test data",
|
200
|
-
query: "test query",
|
201
|
-
roomId: "test-room",
|
202
|
-
embedding: undefined,
|
203
|
-
};
|
204
|
-
|
205
|
-
const result = await memory.createMemory(input);
|
206
|
-
expect(result?.embedding).to.be.null;
|
207
|
-
});
|
208
|
-
|
209
|
-
it("should handle empty query results", async () => {
|
210
|
-
mockMemoryService.getMemoryByIndex = async () => [];
|
211
|
-
|
212
|
-
const results = await memory.getMemoryByIndex("nonexistent", {
|
213
|
-
roomId: "test-room",
|
214
|
-
});
|
215
|
-
expect(results).to.be.an("array").that.is.empty;
|
216
|
-
});
|
217
|
-
|
218
|
-
it("should handle non-existent memory ID", async () => {
|
219
|
-
mockMemoryService.getMemoryById = async () => null;
|
220
|
-
|
221
|
-
const result = await memory.getMemoryById("nonexistent", TEST_ROOM_ID);
|
222
|
-
expect(result).to.be.null;
|
223
|
-
});
|
224
|
-
});
|
225
|
-
});
|
@@ -1,286 +0,0 @@
|
|
1
|
-
import { Queue } from "../../services/queue";
|
2
|
-
import { ActionSchema, QueueCallbacks, QueueItem } from "../../types";
|
3
|
-
import { expect } from "chai";
|
4
|
-
import { z } from "zod";
|
5
|
-
|
6
|
-
describe("Queue", () => {
|
7
|
-
// Test actions setup
|
8
|
-
const testActions: ActionSchema[] = [
|
9
|
-
{
|
10
|
-
name: "action1",
|
11
|
-
description: "Test action 1",
|
12
|
-
parameters: z.object({}),
|
13
|
-
execute: async (params) => ({ success: true, params }),
|
14
|
-
},
|
15
|
-
{
|
16
|
-
name: "action2",
|
17
|
-
description: "Test action 2",
|
18
|
-
parameters: z.object({}),
|
19
|
-
execute: async (params) => ({ success: true, params }),
|
20
|
-
confirmation: {
|
21
|
-
requireConfirmation: true,
|
22
|
-
message: "Confirm action2?",
|
23
|
-
},
|
24
|
-
},
|
25
|
-
{
|
26
|
-
name: "actionWithError",
|
27
|
-
description: "Test error action",
|
28
|
-
parameters: z.object({}),
|
29
|
-
execute: async () => {
|
30
|
-
throw new Error("Test error");
|
31
|
-
},
|
32
|
-
},
|
33
|
-
];
|
34
|
-
|
35
|
-
let queue: Queue;
|
36
|
-
let callbacks: QueueCallbacks;
|
37
|
-
|
38
|
-
beforeEach(() => {
|
39
|
-
// Reset callbacks for each test
|
40
|
-
callbacks = {
|
41
|
-
onActionStart: () => {},
|
42
|
-
onActionComplete: () => {},
|
43
|
-
onQueueComplete: () => {},
|
44
|
-
onConfirmationRequired: async () => true,
|
45
|
-
};
|
46
|
-
queue = new Queue(testActions, callbacks);
|
47
|
-
});
|
48
|
-
|
49
|
-
describe("Queue Management", () => {
|
50
|
-
it("should add a single action to the queue", () => {
|
51
|
-
const action: QueueItem = {
|
52
|
-
name: "action1",
|
53
|
-
parameters: [{ name: "param1", value: "value1" }],
|
54
|
-
};
|
55
|
-
|
56
|
-
queue.add(action);
|
57
|
-
expect(queue["queue"]).to.have.lengthOf(1);
|
58
|
-
expect(queue["queue"][0]).to.deep.equal(action);
|
59
|
-
});
|
60
|
-
|
61
|
-
it("should add multiple actions to the queue", () => {
|
62
|
-
const actions: QueueItem[] = [
|
63
|
-
{
|
64
|
-
name: "action1",
|
65
|
-
parameters: [{ name: "param1", value: "value1" }],
|
66
|
-
},
|
67
|
-
{
|
68
|
-
name: "action2",
|
69
|
-
parameters: [{ name: "param2", value: "value2" }],
|
70
|
-
},
|
71
|
-
];
|
72
|
-
|
73
|
-
queue.add(actions);
|
74
|
-
expect(queue["queue"]).to.have.lengthOf(2);
|
75
|
-
expect(queue["queue"]).to.deep.equal(actions);
|
76
|
-
});
|
77
|
-
});
|
78
|
-
|
79
|
-
describe("Action Execution", () => {
|
80
|
-
it("should execute a single action successfully", async () => {
|
81
|
-
const action: QueueItem = {
|
82
|
-
name: "action1",
|
83
|
-
parameters: [{ name: "param1", value: "value1" }],
|
84
|
-
};
|
85
|
-
|
86
|
-
queue.add(action);
|
87
|
-
const results = await queue.execute();
|
88
|
-
if (!results) {
|
89
|
-
throw new Error("Results are undefined");
|
90
|
-
}
|
91
|
-
expect(results).to.not.be.undefined;
|
92
|
-
expect(results).to.have.lengthOf(1);
|
93
|
-
expect(results[0].name).to.equal("action1");
|
94
|
-
expect(results[0].error).to.be.null;
|
95
|
-
expect(results[0].result).to.deep.include({ success: true });
|
96
|
-
});
|
97
|
-
|
98
|
-
it("should handle action execution errors", async () => {
|
99
|
-
const action: QueueItem = {
|
100
|
-
name: "actionWithError",
|
101
|
-
parameters: [],
|
102
|
-
};
|
103
|
-
|
104
|
-
queue.add(action);
|
105
|
-
const results = await queue.execute();
|
106
|
-
if (!results) {
|
107
|
-
throw new Error("Results are undefined");
|
108
|
-
}
|
109
|
-
expect(results).to.not.be.undefined;
|
110
|
-
expect(results).to.have.lengthOf(1);
|
111
|
-
expect(results[0].name).to.equal("actionWithError");
|
112
|
-
expect(results[0].error).to.equal("Test error");
|
113
|
-
expect(results[0].result).to.be.null;
|
114
|
-
});
|
115
|
-
|
116
|
-
it("should respect confirmation requirements", async () => {
|
117
|
-
let confirmationCalled = false;
|
118
|
-
callbacks.onConfirmationRequired = async () => {
|
119
|
-
confirmationCalled = true;
|
120
|
-
return false; // Reject the confirmation
|
121
|
-
};
|
122
|
-
|
123
|
-
queue = new Queue(testActions, callbacks);
|
124
|
-
const action: QueueItem = {
|
125
|
-
name: "action2", // Action requiring confirmation
|
126
|
-
parameters: [],
|
127
|
-
};
|
128
|
-
|
129
|
-
queue.add(action);
|
130
|
-
const results = await queue.execute();
|
131
|
-
if (!results) {
|
132
|
-
throw new Error("Results are undefined");
|
133
|
-
}
|
134
|
-
expect(results).to.not.be.undefined;
|
135
|
-
expect(confirmationCalled).to.be.true;
|
136
|
-
expect(results[0].cancelled).to.be.true;
|
137
|
-
expect(results[0].error).to.equal("Action cancelled by user");
|
138
|
-
});
|
139
|
-
});
|
140
|
-
|
141
|
-
describe("Parameter Handling", () => {
|
142
|
-
it("should correctly format simple parameters", async () => {
|
143
|
-
const action: QueueItem = {
|
144
|
-
name: "action1",
|
145
|
-
parameters: [
|
146
|
-
{ name: "param1", value: "value1" },
|
147
|
-
{ name: "param2", value: "value2" },
|
148
|
-
],
|
149
|
-
};
|
150
|
-
|
151
|
-
queue.add(action);
|
152
|
-
const results = await queue.execute();
|
153
|
-
if (!results) {
|
154
|
-
throw new Error("Results are undefined");
|
155
|
-
}
|
156
|
-
expect(results).to.not.be.undefined;
|
157
|
-
expect(results[0].parameters).to.deep.equal({
|
158
|
-
param1: "value1",
|
159
|
-
param2: "value2",
|
160
|
-
});
|
161
|
-
});
|
162
|
-
|
163
|
-
it("should handle JSON stringified parameters", async () => {
|
164
|
-
const action: QueueItem = {
|
165
|
-
name: "action1",
|
166
|
-
parameters: [
|
167
|
-
{
|
168
|
-
name: "jsonParam",
|
169
|
-
value: JSON.stringify({ name: "test", value: "value" }),
|
170
|
-
},
|
171
|
-
],
|
172
|
-
};
|
173
|
-
|
174
|
-
queue.add(action);
|
175
|
-
const results = await queue.execute();
|
176
|
-
if (!results) {
|
177
|
-
throw new Error("Results are undefined");
|
178
|
-
}
|
179
|
-
expect(results).to.not.be.undefined;
|
180
|
-
expect(results[0].parameters).to.deep.equal({
|
181
|
-
test: "value",
|
182
|
-
});
|
183
|
-
});
|
184
|
-
});
|
185
|
-
|
186
|
-
describe("Queue Processing State", () => {
|
187
|
-
it("should prevent concurrent queue processing", async () => {
|
188
|
-
const action: QueueItem = {
|
189
|
-
name: "action1",
|
190
|
-
parameters: [],
|
191
|
-
};
|
192
|
-
|
193
|
-
queue.add(action);
|
194
|
-
|
195
|
-
// Start first execution
|
196
|
-
const firstExecution = queue.execute();
|
197
|
-
// Try to execute again while first execution is running
|
198
|
-
const secondExecution = queue.execute();
|
199
|
-
|
200
|
-
const [firstResults, secondResults] = await Promise.all([
|
201
|
-
firstExecution,
|
202
|
-
secondExecution,
|
203
|
-
]);
|
204
|
-
|
205
|
-
expect(firstResults).to.not.be.undefined;
|
206
|
-
expect(firstResults).to.have.lengthOf(1);
|
207
|
-
expect(secondResults).to.be.undefined;
|
208
|
-
});
|
209
|
-
|
210
|
-
it("should reset processing state after completion", async () => {
|
211
|
-
const action: QueueItem = {
|
212
|
-
name: "action1",
|
213
|
-
parameters: [],
|
214
|
-
};
|
215
|
-
|
216
|
-
queue.add(action);
|
217
|
-
const results = await queue.execute();
|
218
|
-
|
219
|
-
if (!results) {
|
220
|
-
throw new Error("Results are undefined");
|
221
|
-
}
|
222
|
-
expect(results).to.have.lengthOf(1);
|
223
|
-
|
224
|
-
// Verify that isProcessing is reset
|
225
|
-
expect(queue["isProcessing"]).to.be.false;
|
226
|
-
|
227
|
-
// Clear both queue and results before adding new action
|
228
|
-
queue["queue"] = [];
|
229
|
-
queue["results"] = [];
|
230
|
-
|
231
|
-
// Should be able to execute again
|
232
|
-
queue.add(action);
|
233
|
-
const secondResults = await queue.execute();
|
234
|
-
|
235
|
-
if (!secondResults) {
|
236
|
-
throw new Error("Second results are undefined");
|
237
|
-
}
|
238
|
-
expect(secondResults).to.have.lengthOf(1);
|
239
|
-
});
|
240
|
-
});
|
241
|
-
|
242
|
-
describe("Callback Handling", () => {
|
243
|
-
it("should trigger all callbacks in correct order", async () => {
|
244
|
-
const callbackOrder: string[] = [];
|
245
|
-
|
246
|
-
callbacks = {
|
247
|
-
onActionStart: () => callbackOrder.push("start"),
|
248
|
-
onActionComplete: () => callbackOrder.push("complete"),
|
249
|
-
onQueueComplete: () => callbackOrder.push("queueComplete"),
|
250
|
-
};
|
251
|
-
|
252
|
-
queue = new Queue(testActions, callbacks);
|
253
|
-
const action: QueueItem = {
|
254
|
-
name: "action1",
|
255
|
-
parameters: [],
|
256
|
-
};
|
257
|
-
|
258
|
-
queue.add(action);
|
259
|
-
await queue.execute();
|
260
|
-
|
261
|
-
expect(callbackOrder).to.deep.equal([
|
262
|
-
"start",
|
263
|
-
"complete",
|
264
|
-
"queueComplete",
|
265
|
-
]);
|
266
|
-
});
|
267
|
-
|
268
|
-
it("should handle missing callbacks gracefully", async () => {
|
269
|
-
queue = new Queue(testActions, {}); // No callbacks provided
|
270
|
-
const action: QueueItem = {
|
271
|
-
name: "action1",
|
272
|
-
parameters: [],
|
273
|
-
};
|
274
|
-
|
275
|
-
queue.add(action);
|
276
|
-
const results = await queue.execute();
|
277
|
-
|
278
|
-
if (!results) {
|
279
|
-
throw new Error("Results are undefined");
|
280
|
-
}
|
281
|
-
expect(results).to.not.be.undefined;
|
282
|
-
expect(results).to.have.lengthOf(1);
|
283
|
-
expect(results[0].error).to.be.null;
|
284
|
-
});
|
285
|
-
});
|
286
|
-
});
|
@@ -1,170 +0,0 @@
|
|
1
|
-
import { MeilisearchAdapter } from "../memory/adapters/meilisearch";
|
2
|
-
import { AIEmbeddingService } from "../services/embedding";
|
3
|
-
import { openai } from "@ai-sdk/openai";
|
4
|
-
import { generateObject } from "ai";
|
5
|
-
import { z } from "zod";
|
6
|
-
|
7
|
-
export const experimentalGraphRag = async (context: {
|
8
|
-
prompt: string;
|
9
|
-
results: any;
|
10
|
-
}) => {
|
11
|
-
if (!process.env.MEILISEARCH_API_KEY)
|
12
|
-
throw new Error("MEILISEARCH_API_KEY is not set");
|
13
|
-
if (!process.env.MEILISEARCH_HOST)
|
14
|
-
throw new Error("MEILISEARCH_HOST is not set");
|
15
|
-
|
16
|
-
const memoryManager = new MeilisearchAdapter({
|
17
|
-
apiKey: process.env.MEILISEARCH_API_KEY,
|
18
|
-
host: process.env.MEILISEARCH_HOST,
|
19
|
-
});
|
20
|
-
await memoryManager.init("nodes");
|
21
|
-
await memoryManager.init("edges");
|
22
|
-
const { existingNodes } = await retrieveExistingRelations(
|
23
|
-
memoryManager,
|
24
|
-
"nodes"
|
25
|
-
);
|
26
|
-
const prompt = `
|
27
|
-
User asked: ${context.prompt}
|
28
|
-
Results: ${JSON.stringify(context.results, null, 2)}
|
29
|
-
Existing nodes: ${JSON.stringify(existingNodes, null, 2)}
|
30
|
-
`;
|
31
|
-
console.log("🔍 Prompt:", prompt);
|
32
|
-
const llmMemory = await generateObject({
|
33
|
-
model: openai("gpt-4o"),
|
34
|
-
prompt,
|
35
|
-
schema: z.object({
|
36
|
-
nodes: z.array(
|
37
|
-
z.object({
|
38
|
-
name: z.string(), // Nom de l'entité (ex: Adresse, ETH, Transaction ID)
|
39
|
-
metadata: z.record(z.string(), z.any()), // Métadonnées associées
|
40
|
-
})
|
41
|
-
),
|
42
|
-
edges: z.array(
|
43
|
-
z.object({
|
44
|
-
source: z.string(), // ID de l'entité source
|
45
|
-
target: z.string(), // ID de l'entité cible
|
46
|
-
relation: z.string(), // Type de relation (ex: "sent", "received", "on_chain")
|
47
|
-
})
|
48
|
-
),
|
49
|
-
}),
|
50
|
-
system: `
|
51
|
-
You are an **AI memory manager** for a crypto wallet assistant.
|
52
|
-
|
53
|
-
## Rules:
|
54
|
-
- Nodes are entities like user, networks, tokens...etc
|
55
|
-
- Relations are edges like sent, uses, supported_on, loves, has_website...etc
|
56
|
-
- Ensure NO DUPLICATE RELATIONS.
|
57
|
-
- Standardize all relations using Cypher language.
|
58
|
-
|
59
|
-
Return the structured memory in JSON format, ensuring it follows the schema.
|
60
|
-
|
61
|
-
Generate structured graph data accordingly.
|
62
|
-
|
63
|
-
Format the output as a JSON object :
|
64
|
-
{
|
65
|
-
nodes: [
|
66
|
-
{
|
67
|
-
name: string,
|
68
|
-
metadata: Record<string, any>,
|
69
|
-
},
|
70
|
-
],
|
71
|
-
edges: [
|
72
|
-
{
|
73
|
-
source: string,
|
74
|
-
target: string,
|
75
|
-
relation: string,
|
76
|
-
},
|
77
|
-
],
|
78
|
-
}
|
79
|
-
`,
|
80
|
-
});
|
81
|
-
|
82
|
-
console.log("🔍 LLM memory (graph-based):");
|
83
|
-
console.log("Nodes:");
|
84
|
-
console.dir(llmMemory.object.nodes, { depth: null, colors: true });
|
85
|
-
console.log("Edges:");
|
86
|
-
console.dir(llmMemory.object.edges, { depth: null, colors: true });
|
87
|
-
|
88
|
-
const embeddingManager = new AIEmbeddingService(
|
89
|
-
openai.embedding("text-embedding-3-small")
|
90
|
-
);
|
91
|
-
const embedding = await embeddingManager.embedText(context.prompt);
|
92
|
-
let nodesNameToId: Record<string, string> = {};
|
93
|
-
for (const node of llmMemory.object.nodes) {
|
94
|
-
// Search for existing memory with same data and query
|
95
|
-
const searchResults = await memoryManager.search(node.name, "nodes", {
|
96
|
-
limit: 1,
|
97
|
-
});
|
98
|
-
const existingMemory = searchResults.find(
|
99
|
-
(result) =>
|
100
|
-
result.document.data.name === node.name &&
|
101
|
-
result.document.roomId === "nodes"
|
102
|
-
);
|
103
|
-
|
104
|
-
// If found, return existing memory
|
105
|
-
if (existingMemory) {
|
106
|
-
nodesNameToId[node.name] = existingMemory.document.id;
|
107
|
-
} else {
|
108
|
-
const nodesMemory = await memoryManager.createMemory({
|
109
|
-
data: node,
|
110
|
-
embedding,
|
111
|
-
roomId: "nodes",
|
112
|
-
});
|
113
|
-
nodesNameToId[node.name] = nodesMemory?.id || "";
|
114
|
-
}
|
115
|
-
}
|
116
|
-
for (const edge of llmMemory.object.edges) {
|
117
|
-
// Verify if source and target already exist in memory
|
118
|
-
const searchResults = await memoryManager.search(
|
119
|
-
nodesNameToId[edge.source],
|
120
|
-
"edges",
|
121
|
-
{
|
122
|
-
limit: 100,
|
123
|
-
}
|
124
|
-
);
|
125
|
-
const existingEdge = searchResults.find(
|
126
|
-
(result) =>
|
127
|
-
result.document.data.source === nodesNameToId[edge.source] &&
|
128
|
-
result.document.data.target === nodesNameToId[edge.target] &&
|
129
|
-
result.document.data.relation === edge.relation
|
130
|
-
);
|
131
|
-
if (existingEdge) {
|
132
|
-
} else {
|
133
|
-
await memoryManager.createMemory({
|
134
|
-
data: {
|
135
|
-
source: nodesNameToId[edge.source],
|
136
|
-
target: nodesNameToId[edge.target],
|
137
|
-
relation: edge.relation,
|
138
|
-
},
|
139
|
-
embedding,
|
140
|
-
roomId: "edges",
|
141
|
-
});
|
142
|
-
}
|
143
|
-
}
|
144
|
-
};
|
145
|
-
|
146
|
-
async function retrieveExistingRelations(
|
147
|
-
memoryManager: MeilisearchAdapter,
|
148
|
-
roomId: string
|
149
|
-
) {
|
150
|
-
const existingNodesMemories = await memoryManager.getAllMemories("nodes");
|
151
|
-
const existingEdgesMemories = await memoryManager.getAllMemories("edges");
|
152
|
-
let existingNodes: any[] = [];
|
153
|
-
let existingEdges: any[] = [];
|
154
|
-
|
155
|
-
if (existingNodesMemories.length > 0) {
|
156
|
-
existingNodes = existingNodesMemories.flatMap((memory) => {
|
157
|
-
return {
|
158
|
-
id: memory.id,
|
159
|
-
data: memory.data,
|
160
|
-
};
|
161
|
-
});
|
162
|
-
}
|
163
|
-
if (existingEdgesMemories.length > 0) {
|
164
|
-
existingEdges = existingEdgesMemories.flatMap(
|
165
|
-
(memory) => memory.data || []
|
166
|
-
);
|
167
|
-
}
|
168
|
-
|
169
|
-
return { existingNodes, existingEdges };
|
170
|
-
}
|