memories-lite 0.9.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/MEMORIES.md +39 -0
- package/README.md +221 -0
- package/TECHNICAL.md +135 -0
- package/dist/config/defaults.d.ts +2 -0
- package/dist/config/defaults.js +61 -0
- package/dist/config/manager.d.ts +4 -0
- package/dist/config/manager.js +121 -0
- package/dist/embeddings/base.d.ts +4 -0
- package/dist/embeddings/base.js +2 -0
- package/dist/embeddings/google.d.ts +10 -0
- package/dist/embeddings/google.js +28 -0
- package/dist/embeddings/openai.d.ts +10 -0
- package/dist/embeddings/openai.js +31 -0
- package/dist/graphs/configs.d.ts +14 -0
- package/dist/graphs/configs.js +19 -0
- package/dist/graphs/tools.d.ts +271 -0
- package/dist/graphs/tools.js +220 -0
- package/dist/graphs/utils.d.ts +9 -0
- package/dist/graphs/utils.js +105 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +30 -0
- package/dist/llms/base.d.ts +16 -0
- package/dist/llms/base.js +2 -0
- package/dist/llms/google.d.ts +11 -0
- package/dist/llms/google.js +44 -0
- package/dist/llms/openai.d.ts +9 -0
- package/dist/llms/openai.js +73 -0
- package/dist/llms/openai_structured.d.ts +11 -0
- package/dist/llms/openai_structured.js +72 -0
- package/dist/memory/index.d.ts +42 -0
- package/dist/memory/index.js +499 -0
- package/dist/memory/memory.types.d.ts +23 -0
- package/dist/memory/memory.types.js +2 -0
- package/dist/prompts/index.d.ts +102 -0
- package/dist/prompts/index.js +233 -0
- package/dist/storage/DummyHistoryManager.d.ts +7 -0
- package/dist/storage/DummyHistoryManager.js +19 -0
- package/dist/storage/MemoryHistoryManager.d.ts +8 -0
- package/dist/storage/MemoryHistoryManager.js +36 -0
- package/dist/storage/base.d.ts +6 -0
- package/dist/storage/base.js +2 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.js +19 -0
- package/dist/types/index.d.ts +1071 -0
- package/dist/types/index.js +100 -0
- package/dist/utils/bm25.d.ts +13 -0
- package/dist/utils/bm25.js +51 -0
- package/dist/utils/factory.d.ts +13 -0
- package/dist/utils/factory.js +49 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +9 -0
- package/dist/utils/memory.d.ts +3 -0
- package/dist/utils/memory.js +44 -0
- package/dist/utils/telemetry.d.ts +11 -0
- package/dist/utils/telemetry.js +74 -0
- package/dist/utils/telemetry.types.d.ts +27 -0
- package/dist/utils/telemetry.types.js +2 -0
- package/dist/vectorstores/base.d.ts +11 -0
- package/dist/vectorstores/base.js +2 -0
- package/dist/vectorstores/lite.d.ts +40 -0
- package/dist/vectorstores/lite.js +319 -0
- package/dist/vectorstores/llm.d.ts +31 -0
- package/dist/vectorstores/llm.js +88 -0
- package/jest.config.js +22 -0
- package/memories-lite.db +0 -0
- package/package.json +38 -0
- package/src/config/defaults.ts +61 -0
- package/src/config/manager.ts +132 -0
- package/src/embeddings/base.ts +4 -0
- package/src/embeddings/google.ts +32 -0
- package/src/embeddings/openai.ts +33 -0
- package/src/graphs/configs.ts +30 -0
- package/src/graphs/tools.ts +267 -0
- package/src/graphs/utils.ts +114 -0
- package/src/index.ts +14 -0
- package/src/llms/base.ts +20 -0
- package/src/llms/google.ts +56 -0
- package/src/llms/openai.ts +85 -0
- package/src/llms/openai_structured.ts +82 -0
- package/src/memory/index.ts +723 -0
- package/src/memory/memory.types.ts +27 -0
- package/src/prompts/index.ts +268 -0
- package/src/storage/DummyHistoryManager.ts +27 -0
- package/src/storage/MemoryHistoryManager.ts +58 -0
- package/src/storage/base.ts +14 -0
- package/src/storage/index.ts +3 -0
- package/src/types/index.ts +243 -0
- package/src/utils/bm25.ts +64 -0
- package/src/utils/factory.ts +59 -0
- package/src/utils/logger.ts +13 -0
- package/src/utils/memory.ts +48 -0
- package/src/utils/telemetry.ts +98 -0
- package/src/utils/telemetry.types.ts +34 -0
- package/src/vectorstores/base.ts +27 -0
- package/src/vectorstores/lite.ts +402 -0
- package/src/vectorstores/llm.ts +126 -0
- package/tests/lite.spec.ts +158 -0
- package/tests/memory.facts.test.ts +211 -0
- package/tests/memory.test.ts +406 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import {
|
|
4
|
+
MemoryConfig,
|
|
5
|
+
MemoryConfigSchema,
|
|
6
|
+
MemoryItem,
|
|
7
|
+
MemoryType,
|
|
8
|
+
Message,
|
|
9
|
+
SearchFilters,
|
|
10
|
+
SearchResult,
|
|
11
|
+
VectorStoreConfig,
|
|
12
|
+
} from "../types";
|
|
13
|
+
import {
|
|
14
|
+
EmbedderFactory,
|
|
15
|
+
LLMFactory,
|
|
16
|
+
HistoryManagerFactory,
|
|
17
|
+
} from "../utils/factory";
|
|
18
|
+
import {
|
|
19
|
+
FactRetrievalSchema_extended,
|
|
20
|
+
getFactRetrievalMessages,
|
|
21
|
+
getUpdateMemoryMessages,
|
|
22
|
+
MemoryUpdateSchema,
|
|
23
|
+
removeCodeBlocks,
|
|
24
|
+
} from "../prompts";
|
|
25
|
+
import { DummyHistoryManager } from "../storage/DummyHistoryManager";
|
|
26
|
+
import { Embedder } from "../embeddings/base";
|
|
27
|
+
import { LLM } from "../llms/base";
|
|
28
|
+
import { VectorStore } from "../vectorstores/base";
|
|
29
|
+
import { ConfigManager } from "../config/manager";
|
|
30
|
+
import {
|
|
31
|
+
AddMemoryOptions,
|
|
32
|
+
SearchMemoryOptions,
|
|
33
|
+
DeleteAllMemoryOptions,
|
|
34
|
+
GetAllMemoryOptions,
|
|
35
|
+
} from "./memory.types";
|
|
36
|
+
import { parse_vision_messages } from "../utils/memory";
|
|
37
|
+
import { HistoryManager } from "../storage/base";
|
|
38
|
+
import { captureClientEvent } from "../utils/telemetry";
|
|
39
|
+
import { LiteVectorStore } from "../vectorstores/lite";
|
|
40
|
+
import { zodResponseFormat } from "openai/helpers/zod";
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
export class MemoriesLite {
|
|
44
|
+
private config: MemoryConfig;
|
|
45
|
+
private customPrompt: string | undefined;
|
|
46
|
+
private embedder: Embedder;
|
|
47
|
+
private vectorStoreConfig: VectorStoreConfig;
|
|
48
|
+
private llm: LLM;
|
|
49
|
+
private db: HistoryManager;
|
|
50
|
+
private collectionName: string | undefined;
|
|
51
|
+
private apiVersion: string;
|
|
52
|
+
private graphMemory?: any;
|
|
53
|
+
private enableGraph: boolean;
|
|
54
|
+
telemetryId: string;
|
|
55
|
+
|
|
56
|
+
constructor(config: Partial<MemoryConfig> = {}) {
|
|
57
|
+
// Merge and validate config
|
|
58
|
+
this.config = ConfigManager.mergeConfig(config);
|
|
59
|
+
|
|
60
|
+
this.customPrompt = this.config.customPrompt;
|
|
61
|
+
this.embedder = EmbedderFactory.create(
|
|
62
|
+
this.config.embedder.provider,
|
|
63
|
+
this.config.embedder.config,
|
|
64
|
+
);
|
|
65
|
+
//
|
|
66
|
+
// vectorStore.provider is "lite"
|
|
67
|
+
this.vectorStoreConfig = this.config.vectorStore.config;
|
|
68
|
+
this.llm = LLMFactory.create(
|
|
69
|
+
this.config.llm.provider,
|
|
70
|
+
this.config.llm.config,
|
|
71
|
+
);
|
|
72
|
+
if (this.config.disableHistory) {
|
|
73
|
+
this.db = new DummyHistoryManager();
|
|
74
|
+
} else {
|
|
75
|
+
const defaultConfig = {
|
|
76
|
+
provider: "sqlite",
|
|
77
|
+
config: {
|
|
78
|
+
historyDbPath: this.config.historyDbPath || ":memory:",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
this.db =
|
|
83
|
+
this.config.historyStore && !this.config.disableHistory
|
|
84
|
+
? HistoryManagerFactory.create(
|
|
85
|
+
this.config.historyStore.provider,
|
|
86
|
+
this.config.historyStore,
|
|
87
|
+
)
|
|
88
|
+
: HistoryManagerFactory.create("sqlite", defaultConfig);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.collectionName = this.config.vectorStore.config.collectionName;
|
|
92
|
+
this.apiVersion = this.config.version || "v1.0";
|
|
93
|
+
this.enableGraph = this.config.enableGraph || false;
|
|
94
|
+
this.telemetryId = "anonymous";
|
|
95
|
+
|
|
96
|
+
// Initialize graph memory if configured
|
|
97
|
+
if (this.enableGraph && this.config.graphStore) {
|
|
98
|
+
// this.graphMemory = new MemoryGraph(this.config);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Initialize telemetry if vector store is initialized
|
|
102
|
+
// this._initializeTelemetry();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private async _initializeTelemetry() {
|
|
106
|
+
try {
|
|
107
|
+
await this._getTelemetryId();
|
|
108
|
+
|
|
109
|
+
// Capture initialization event
|
|
110
|
+
await captureClientEvent("init", this, {
|
|
111
|
+
api_version: this.apiVersion,
|
|
112
|
+
client_type: "Memory",
|
|
113
|
+
collection_name: this.collectionName,
|
|
114
|
+
enable_graph: this.enableGraph,
|
|
115
|
+
});
|
|
116
|
+
} catch (error) {}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private async _getTelemetryId() {
|
|
120
|
+
try {
|
|
121
|
+
if (
|
|
122
|
+
!this.telemetryId ||
|
|
123
|
+
this.telemetryId === "anonymous" ||
|
|
124
|
+
this.telemetryId === "anonymous-supabase"
|
|
125
|
+
) {
|
|
126
|
+
// this.telemetryId = await this.vectorStore.getUserId();
|
|
127
|
+
throw new Error("Telemetry ID not found");
|
|
128
|
+
}
|
|
129
|
+
return this.telemetryId;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
this.telemetryId = "anonymous";
|
|
132
|
+
return this.telemetryId;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private async _captureEvent(methodName: string, additionalData = {}) {
|
|
137
|
+
try {
|
|
138
|
+
await this._getTelemetryId();
|
|
139
|
+
await captureClientEvent(methodName, this, {
|
|
140
|
+
...additionalData,
|
|
141
|
+
api_version: this.apiVersion,
|
|
142
|
+
collection_name: this.collectionName,
|
|
143
|
+
});
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(`Failed to capture ${methodName} event:`, error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private $t(text:string) {
|
|
150
|
+
// return text.replace(/<thinking>[\s\S]*?(?:<\/thinking>)/g,'').replace(/^<step.*$/g,'');
|
|
151
|
+
return text.replace(/<thinking>[\s\S]*?<\/thinking>/g,'').replace(/^<step.*$/gm,'').replace(/<memories>[\s\S]*?<\/memories>/g, '');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
private async addToVectorStore(
|
|
156
|
+
messages: Message[],
|
|
157
|
+
metadata: Record<string, any>,
|
|
158
|
+
userId: string,
|
|
159
|
+
filters: SearchFilters,
|
|
160
|
+
customFacts?: string,
|
|
161
|
+
): Promise<MemoryItem[]> {
|
|
162
|
+
|
|
163
|
+
const $t = this.$t;
|
|
164
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
165
|
+
const parsedMessages = messages.filter((m) => typeof m.content === 'string').map((m) => `${m.role=='user' ? '**USER**: ' : '**ASSISTANT**: '}${$t(m.content as string)}\n`).join("\n");
|
|
166
|
+
|
|
167
|
+
const [systemPrompt, userPrompt] = getFactRetrievalMessages(parsedMessages, customFacts||this.customPrompt);
|
|
168
|
+
|
|
169
|
+
const response = await this.llm.generateResponse(
|
|
170
|
+
[
|
|
171
|
+
{ role: "system", content: systemPrompt },
|
|
172
|
+
{ role: "user", content: userPrompt },
|
|
173
|
+
],
|
|
174
|
+
{...zodResponseFormat(FactRetrievalSchema_extended,"FactRetrieval")},[],false
|
|
175
|
+
);
|
|
176
|
+
const parsedResponse = (response:any) => {
|
|
177
|
+
try {
|
|
178
|
+
// structured output
|
|
179
|
+
if(typeof response === 'object') {
|
|
180
|
+
return response;
|
|
181
|
+
}
|
|
182
|
+
const cleanResponse = removeCodeBlocks(response as string);
|
|
183
|
+
return JSON.parse(cleanResponse);
|
|
184
|
+
} catch (e) {
|
|
185
|
+
console.error(
|
|
186
|
+
"Failed to parse facts from LLM response:",
|
|
187
|
+
response,
|
|
188
|
+
e,
|
|
189
|
+
response
|
|
190
|
+
);
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//
|
|
195
|
+
// can use native structured output
|
|
196
|
+
const facts = parsedResponse(response).facts?.filter((f:any) => !f.existing)||[];
|
|
197
|
+
|
|
198
|
+
// console.log("-- DBG extract:", userPrompt);
|
|
199
|
+
// console.log("-- DBG facts:", facts);
|
|
200
|
+
|
|
201
|
+
// Get embeddings for new facts
|
|
202
|
+
const newMessageEmbeddings: Record<string, number[]> = {};
|
|
203
|
+
const retrievedOldMemory: Array<{ id: string; text: string; type: string }> = [];
|
|
204
|
+
|
|
205
|
+
// Create embeddings and search for similar memories
|
|
206
|
+
for (const elem of facts) {
|
|
207
|
+
const fact = elem.fact;
|
|
208
|
+
const embedding = await this.embedder.embed(fact);
|
|
209
|
+
newMessageEmbeddings[fact] = embedding;
|
|
210
|
+
|
|
211
|
+
const existingMemories = await vectorStore.search(
|
|
212
|
+
embedding,
|
|
213
|
+
5,
|
|
214
|
+
filters,
|
|
215
|
+
);
|
|
216
|
+
for (const mem of existingMemories) {
|
|
217
|
+
retrievedOldMemory.push({ id: mem.id, text: mem.payload.data,type: mem.payload.type });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// console.log("-- DBG old memories:", retrievedOldMemory);
|
|
222
|
+
// Remove duplicates from old memories
|
|
223
|
+
const uniqueOldMemories = retrievedOldMemory.filter(
|
|
224
|
+
(mem, index) =>
|
|
225
|
+
retrievedOldMemory.findIndex((m) => m.id === mem.id) === index,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Create UUID mapping for handling UUID hallucinations
|
|
229
|
+
const tempUuidMapping: Record<string, string> = {};
|
|
230
|
+
uniqueOldMemories.forEach((item, idx) => {
|
|
231
|
+
tempUuidMapping[String(idx)] = item.id;
|
|
232
|
+
uniqueOldMemories[idx].id = String(idx);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Get memory update decisions
|
|
236
|
+
const updatePrompt = getUpdateMemoryMessages(uniqueOldMemories, facts);
|
|
237
|
+
|
|
238
|
+
const updateResponse = await this.llm.generateResponse(
|
|
239
|
+
[{ role: "user", content: updatePrompt }],
|
|
240
|
+
{...zodResponseFormat(MemoryUpdateSchema,"Memory")},[],false,
|
|
241
|
+
);
|
|
242
|
+
// console.log("-- DBG merge:", updatePrompt);
|
|
243
|
+
|
|
244
|
+
const memoryActions: any[] = parsedResponse(updateResponse).memory || [];
|
|
245
|
+
|
|
246
|
+
// Process memory actions
|
|
247
|
+
const results: MemoryItem[] = [];
|
|
248
|
+
for (const action of memoryActions) {
|
|
249
|
+
if(action.reason === "undefined") {
|
|
250
|
+
console.log(`-- ⛔ LLM Error: ${action.event}, ${action.type}, "${action.text}"`);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
console.log(`-- DBG memory action: ${action.event}, ${action.type}, "${action.text}", why: "${action.reason}"`);
|
|
254
|
+
try {
|
|
255
|
+
switch (action.event) {
|
|
256
|
+
case "ADD": {
|
|
257
|
+
if(!action.type) {
|
|
258
|
+
// log error
|
|
259
|
+
console.error("Type is mandatory to manage memories:", action);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
metadata.type = action.type;
|
|
263
|
+
const memoryId = await this.createMemory(
|
|
264
|
+
action.text,
|
|
265
|
+
newMessageEmbeddings,
|
|
266
|
+
metadata,
|
|
267
|
+
userId,
|
|
268
|
+
);
|
|
269
|
+
results.push({
|
|
270
|
+
id: memoryId,
|
|
271
|
+
memory: action.text,
|
|
272
|
+
type: action.type,
|
|
273
|
+
metadata: { event: action.event },
|
|
274
|
+
});
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
case "UPDATE": {
|
|
278
|
+
const realMemoryId = tempUuidMapping[action.id];
|
|
279
|
+
const type = uniqueOldMemories[action.id].type as MemoryType;
|
|
280
|
+
await this.updateMemory(
|
|
281
|
+
realMemoryId,
|
|
282
|
+
action.text,
|
|
283
|
+
newMessageEmbeddings,
|
|
284
|
+
metadata,
|
|
285
|
+
userId,
|
|
286
|
+
);
|
|
287
|
+
results.push({
|
|
288
|
+
id: realMemoryId,
|
|
289
|
+
memory: action.text,
|
|
290
|
+
type,
|
|
291
|
+
metadata: {
|
|
292
|
+
event: action.event,
|
|
293
|
+
previousMemory: action.old_memory,
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case "DELETE": {
|
|
299
|
+
const realMemoryId = tempUuidMapping[action.id];
|
|
300
|
+
await this.deleteMemory(realMemoryId, userId);
|
|
301
|
+
results.push({
|
|
302
|
+
id: realMemoryId,
|
|
303
|
+
memory: action.text,
|
|
304
|
+
type: action.type,
|
|
305
|
+
metadata: { event: action.event },
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.error(`Error processing memory action: ${error}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return results;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
static fromConfig(configDict: Record<string, any>): MemoriesLite {
|
|
318
|
+
try {
|
|
319
|
+
const config = MemoryConfigSchema.parse(configDict);
|
|
320
|
+
return new MemoriesLite(config);
|
|
321
|
+
} catch (e) {
|
|
322
|
+
console.error("Configuration validation error:", e);
|
|
323
|
+
throw e;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async getVectorStore(userId: string): Promise<VectorStore> {
|
|
328
|
+
return LiteVectorStore.from(userId, this.vectorStoreConfig);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async capture(
|
|
332
|
+
messages: string | Message[],
|
|
333
|
+
userId: string,
|
|
334
|
+
config: AddMemoryOptions,
|
|
335
|
+
): Promise<SearchResult> {
|
|
336
|
+
// await this._captureEvent("add", {
|
|
337
|
+
// message_count: Array.isArray(messages) ? messages.length : 1,
|
|
338
|
+
// has_metadata: !!config.metadata,
|
|
339
|
+
// has_filters: !!config.filters,
|
|
340
|
+
// infer: config.infer,
|
|
341
|
+
// });
|
|
342
|
+
const {
|
|
343
|
+
agentId,
|
|
344
|
+
runId,
|
|
345
|
+
metadata = {},
|
|
346
|
+
filters = {},
|
|
347
|
+
infer = true,
|
|
348
|
+
customFacts
|
|
349
|
+
} = config;
|
|
350
|
+
|
|
351
|
+
if (agentId) filters.agentId = metadata.agentId = agentId;
|
|
352
|
+
if (runId) filters.runId = metadata.runId = runId;
|
|
353
|
+
|
|
354
|
+
if (!userId && !filters.agentId && !filters.runId) {
|
|
355
|
+
throw new Error(
|
|
356
|
+
"One of the filters: userId, agentId or runId is required!",
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const parsedMessages = Array.isArray(messages)
|
|
361
|
+
? (messages as Message[])
|
|
362
|
+
: [{ role: "user", content: messages }];
|
|
363
|
+
|
|
364
|
+
const final_parsedMessages = await parse_vision_messages(parsedMessages);
|
|
365
|
+
|
|
366
|
+
// Add to vector store
|
|
367
|
+
const vectorStoreResult = await this.addToVectorStore(
|
|
368
|
+
final_parsedMessages,
|
|
369
|
+
metadata,
|
|
370
|
+
userId,
|
|
371
|
+
filters,
|
|
372
|
+
customFacts,
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
// Add to graph store if available
|
|
376
|
+
let graphResult;
|
|
377
|
+
if (this.graphMemory) {
|
|
378
|
+
try {
|
|
379
|
+
graphResult = await this.graphMemory.add(
|
|
380
|
+
final_parsedMessages.map((m) => m.content).join("\n"),
|
|
381
|
+
filters,
|
|
382
|
+
);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.error("Error adding to graph memory:", error);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
results: vectorStoreResult,
|
|
390
|
+
relations: graphResult?.relations,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
async get(memoryId: string, userId: string): Promise<MemoryItem | null> {
|
|
396
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
397
|
+
|
|
398
|
+
const memory = await vectorStore.get(memoryId);
|
|
399
|
+
if (!memory) return null;
|
|
400
|
+
|
|
401
|
+
const filters = {
|
|
402
|
+
...(memory.payload.agentId && { agentId: memory.payload.agentId }),
|
|
403
|
+
...(memory.payload.runId && { runId: memory.payload.runId }),
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const memoryItem: MemoryItem = {
|
|
407
|
+
id: memory.id,
|
|
408
|
+
memory: memory.payload.data,
|
|
409
|
+
type: memory.payload.type,
|
|
410
|
+
hash: memory.payload.hash,
|
|
411
|
+
createdAt: memory.payload.createdAt,
|
|
412
|
+
updatedAt: memory.payload.updatedAt,
|
|
413
|
+
metadata: {},
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
// Add additional metadata
|
|
418
|
+
const excludedKeys = new Set([
|
|
419
|
+
"userId",
|
|
420
|
+
"agentId",
|
|
421
|
+
"runId",
|
|
422
|
+
"hash",
|
|
423
|
+
"data",
|
|
424
|
+
"createdAt",
|
|
425
|
+
"updatedAt",
|
|
426
|
+
]);
|
|
427
|
+
for (const [key, value] of Object.entries(memory.payload)) {
|
|
428
|
+
if (!excludedKeys.has(key)) {
|
|
429
|
+
memoryItem.metadata![key] = value;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return { ...memoryItem, ...filters };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async retrieve(
|
|
437
|
+
query: string,
|
|
438
|
+
userId: string,
|
|
439
|
+
config: SearchMemoryOptions,
|
|
440
|
+
): Promise<SearchResult> {
|
|
441
|
+
// await this._captureEvent("search", {
|
|
442
|
+
// query_length: query.length,
|
|
443
|
+
// limit: config.limit,
|
|
444
|
+
// has_filters: !!config.filters,
|
|
445
|
+
// });
|
|
446
|
+
const { agentId, runId, limit = 100, filters = {} } = config;
|
|
447
|
+
|
|
448
|
+
if (agentId) filters.agentId = agentId;
|
|
449
|
+
if (runId) filters.runId = runId;
|
|
450
|
+
|
|
451
|
+
if (!userId && !filters.agentId && !filters.runId) {
|
|
452
|
+
throw new Error(
|
|
453
|
+
"One of the filters: userId, agentId or runId is required!",
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
// Search vector store
|
|
461
|
+
const queryEmbedding = await this.embedder.embed(query);
|
|
462
|
+
const memories = await vectorStore.search(
|
|
463
|
+
queryEmbedding,
|
|
464
|
+
limit,
|
|
465
|
+
filters,
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
// Search graph store if available
|
|
470
|
+
let graphResults =[];
|
|
471
|
+
if (this.graphMemory) {
|
|
472
|
+
try {
|
|
473
|
+
graphResults = await this.graphMemory.search(query, filters);
|
|
474
|
+
} catch (error) {
|
|
475
|
+
console.error("Error searching graph memory:", error);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const excludedKeys = new Set([
|
|
480
|
+
"userId",
|
|
481
|
+
"agentId",
|
|
482
|
+
"runId",
|
|
483
|
+
"hash",
|
|
484
|
+
"data",
|
|
485
|
+
"createdAt",
|
|
486
|
+
"updatedAt",
|
|
487
|
+
]);
|
|
488
|
+
const results = memories.map((mem) => ({
|
|
489
|
+
id: mem.id,
|
|
490
|
+
memory: mem.payload.data,
|
|
491
|
+
hash: mem.payload.hash,
|
|
492
|
+
type: mem.payload.type,
|
|
493
|
+
createdAt: mem.payload.createdAt,
|
|
494
|
+
updatedAt: mem.payload.updatedAt,
|
|
495
|
+
score: mem.score,
|
|
496
|
+
metadata: Object.entries(mem.payload)
|
|
497
|
+
.filter(([key]) => !excludedKeys.has(key))
|
|
498
|
+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
|
499
|
+
...(mem.payload.agentId && { agentId: mem.payload.agentId }),
|
|
500
|
+
...(mem.payload.runId && { runId: mem.payload.runId }),
|
|
501
|
+
}));
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
results,
|
|
505
|
+
relations: graphResults,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async update(memoryId: string, data: string, userId: string): Promise<{ message: string }> {
|
|
510
|
+
// await this._captureEvent("update", { memory_id: memoryId });
|
|
511
|
+
const embedding = await this.embedder.embed(data);
|
|
512
|
+
await this.updateMemory(memoryId, data, { [data]: embedding }, {}, userId);
|
|
513
|
+
return { message: "Memory updated successfully!" };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async delete(memoryId: string, userId: string): Promise<{ message: string }> {
|
|
517
|
+
// await this._captureEvent("delete", { memory_id: memoryId });
|
|
518
|
+
await this.deleteMemory(memoryId, userId);
|
|
519
|
+
return { message: "Memory deleted successfully!" };
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async deleteAll(
|
|
523
|
+
userId: string,
|
|
524
|
+
config: DeleteAllMemoryOptions,
|
|
525
|
+
): Promise<{ message: string }> {
|
|
526
|
+
// await this._captureEvent("delete_all", {
|
|
527
|
+
// has_user_id: !!config.userId,
|
|
528
|
+
// has_agent_id: !!config.agentId,
|
|
529
|
+
// has_run_id: !!config.runId,
|
|
530
|
+
// });
|
|
531
|
+
const { agentId, runId } = config;
|
|
532
|
+
if (!userId) throw new Error("vector store instanceId is required");
|
|
533
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
534
|
+
|
|
535
|
+
const filters: SearchFilters = {};
|
|
536
|
+
if (agentId) filters.agentId = agentId;
|
|
537
|
+
if (runId) filters.runId = runId;
|
|
538
|
+
|
|
539
|
+
if (!Object.keys(filters).length) {
|
|
540
|
+
throw new Error(
|
|
541
|
+
"At least one filter is required to delete all memories. If you want to delete all memories, use the `reset()` method.",
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const [memories] = await vectorStore.list(filters);
|
|
546
|
+
for (const memory of memories) {
|
|
547
|
+
await this.deleteMemory(memory.id, userId!);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
return { message: "Memories deleted successfully!" };
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
//
|
|
554
|
+
// DEPRECATED: history must be user specific
|
|
555
|
+
async history(memoryId: string): Promise<any[]> {
|
|
556
|
+
return this.db.getHistory(memoryId);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
async reset(userId: string): Promise<void> {
|
|
560
|
+
// await this._captureEvent("reset");
|
|
561
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
562
|
+
await this.db.reset();
|
|
563
|
+
|
|
564
|
+
// Check provider before attempting deleteCol
|
|
565
|
+
await vectorStore.deleteCol();
|
|
566
|
+
|
|
567
|
+
if (this.graphMemory) {
|
|
568
|
+
await this.graphMemory.deleteAll({ userId: "default" }); // Assuming this is okay, or needs similar check?
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Re-initialize factories/clients based on the original config
|
|
572
|
+
this.embedder = EmbedderFactory.create(
|
|
573
|
+
this.config.embedder.provider,
|
|
574
|
+
this.config.embedder.config,
|
|
575
|
+
);
|
|
576
|
+
this.llm = LLMFactory.create(
|
|
577
|
+
this.config.llm.provider,
|
|
578
|
+
this.config.llm.config,
|
|
579
|
+
);
|
|
580
|
+
// Re-init DB if needed (though db.reset() likely handles its state)
|
|
581
|
+
// Re-init Graph if needed
|
|
582
|
+
|
|
583
|
+
// Re-initialize telemetry
|
|
584
|
+
// this._initializeTelemetry();
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
async getAll(userId: string, config: GetAllMemoryOptions): Promise<SearchResult> {
|
|
588
|
+
// await this._captureEvent("get_all", {
|
|
589
|
+
// limit: config.limit,
|
|
590
|
+
// has_agent_id: !!config.agentId,
|
|
591
|
+
// has_run_id: !!config.runId,
|
|
592
|
+
// });
|
|
593
|
+
const { agentId, runId, limit = 10, type } = config;
|
|
594
|
+
const vectorStore = await this.getVectorStore(userId!);
|
|
595
|
+
|
|
596
|
+
const filters: SearchFilters = {};
|
|
597
|
+
if (agentId) filters.agentId = agentId;
|
|
598
|
+
if (runId) filters.runId = runId;
|
|
599
|
+
if (type) filters.type = type;
|
|
600
|
+
const [memories] = await vectorStore.list(filters, limit);
|
|
601
|
+
|
|
602
|
+
const excludedKeys = new Set([
|
|
603
|
+
"userId",
|
|
604
|
+
"agentId",
|
|
605
|
+
"runId",
|
|
606
|
+
"hash",
|
|
607
|
+
"data",
|
|
608
|
+
"createdAt",
|
|
609
|
+
"updatedAt",
|
|
610
|
+
]);
|
|
611
|
+
const results = memories.map((mem) => ({
|
|
612
|
+
id: mem.id,
|
|
613
|
+
memory: mem.payload.data,
|
|
614
|
+
hash: mem.payload.hash,
|
|
615
|
+
type: mem.payload.type,
|
|
616
|
+
createdAt: mem.payload.createdAt,
|
|
617
|
+
updatedAt: mem.payload.updatedAt,
|
|
618
|
+
metadata: Object.entries(mem.payload)
|
|
619
|
+
.filter(([key]) => !excludedKeys.has(key))
|
|
620
|
+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
|
621
|
+
...(mem.payload.agentId && { agentId: mem.payload.agentId }),
|
|
622
|
+
...(mem.payload.runId && { runId: mem.payload.runId }),
|
|
623
|
+
}));
|
|
624
|
+
|
|
625
|
+
return { results };
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private async createMemory(
|
|
629
|
+
data: string,
|
|
630
|
+
existingEmbeddings: Record<string, number[]>,
|
|
631
|
+
metadata: Record<string, any>,
|
|
632
|
+
userId: string,
|
|
633
|
+
): Promise<string> {
|
|
634
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
635
|
+
const memoryId = uuidv4();
|
|
636
|
+
const embedding =
|
|
637
|
+
existingEmbeddings[data] || (await this.embedder.embed(data));
|
|
638
|
+
|
|
639
|
+
const memoryMetadata = {
|
|
640
|
+
...metadata,
|
|
641
|
+
data,
|
|
642
|
+
hash: createHash("md5").update(data).digest("hex"),
|
|
643
|
+
createdAt: new Date().toISOString(),
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
await vectorStore.insert([embedding], [memoryId], [memoryMetadata]);
|
|
647
|
+
await this.db.addHistory(
|
|
648
|
+
memoryId,
|
|
649
|
+
null,
|
|
650
|
+
data,
|
|
651
|
+
"ADD",
|
|
652
|
+
memoryMetadata.createdAt,
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
return memoryId;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
private async updateMemory(
|
|
659
|
+
memoryId: string,
|
|
660
|
+
data: string,
|
|
661
|
+
existingEmbeddings: Record<string, number[]>,
|
|
662
|
+
metadata: Record<string, any> = {},
|
|
663
|
+
userId: string,
|
|
664
|
+
): Promise<string> {
|
|
665
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
666
|
+
const existingMemory = await vectorStore.get(memoryId);
|
|
667
|
+
if (!existingMemory) {
|
|
668
|
+
throw new Error(`Memory with ID ${memoryId} not found`);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const prevValue = existingMemory.payload.data;
|
|
672
|
+
const embedding =
|
|
673
|
+
existingEmbeddings[data] || (await this.embedder.embed(data));
|
|
674
|
+
|
|
675
|
+
const newMetadata = {
|
|
676
|
+
...metadata,
|
|
677
|
+
data,
|
|
678
|
+
hash: createHash("md5").update(data).digest("hex"),
|
|
679
|
+
createdAt: existingMemory.payload.createdAt,
|
|
680
|
+
updatedAt: new Date().toISOString(),
|
|
681
|
+
...(existingMemory.payload.agentId && {
|
|
682
|
+
agentId: existingMemory.payload.agentId,
|
|
683
|
+
}),
|
|
684
|
+
...(existingMemory.payload.runId && {
|
|
685
|
+
runId: existingMemory.payload.runId,
|
|
686
|
+
}),
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
await vectorStore.update(memoryId, embedding, newMetadata);
|
|
690
|
+
await this.db.addHistory(
|
|
691
|
+
memoryId,
|
|
692
|
+
prevValue,
|
|
693
|
+
data,
|
|
694
|
+
"UPDATE",
|
|
695
|
+
newMetadata.createdAt,
|
|
696
|
+
newMetadata.updatedAt,
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
return memoryId;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private async deleteMemory(memoryId: string, userId: string): Promise<string> {
|
|
703
|
+
const vectorStore = await this.getVectorStore(userId);
|
|
704
|
+
const existingMemory = await vectorStore.get(memoryId);
|
|
705
|
+
if (!existingMemory) {
|
|
706
|
+
throw new Error(`Memory with ID ${memoryId} not found`);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const prevValue = existingMemory.payload.data;
|
|
710
|
+
await vectorStore.delete(memoryId);
|
|
711
|
+
await this.db.addHistory(
|
|
712
|
+
memoryId,
|
|
713
|
+
prevValue,
|
|
714
|
+
null,
|
|
715
|
+
"DELETE",
|
|
716
|
+
undefined,
|
|
717
|
+
undefined,
|
|
718
|
+
1,
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
return memoryId;
|
|
722
|
+
}
|
|
723
|
+
}
|