@lov3kaizen/agentsea-memory 0.5.1

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +450 -0
  3. package/dist/chunk-GACX3FPR.js +1402 -0
  4. package/dist/chunk-M44NB53O.js +1226 -0
  5. package/dist/chunk-MQDWBPZU.js +972 -0
  6. package/dist/chunk-TPC7MYWK.js +1495 -0
  7. package/dist/chunk-XD2CQGSD.js +1540 -0
  8. package/dist/chunk-YI7RPDEV.js +1215 -0
  9. package/dist/core.types-lkxKv-bW.d.cts +242 -0
  10. package/dist/core.types-lkxKv-bW.d.ts +242 -0
  11. package/dist/debug/index.cjs +1248 -0
  12. package/dist/debug/index.d.cts +3 -0
  13. package/dist/debug/index.d.ts +3 -0
  14. package/dist/debug/index.js +20 -0
  15. package/dist/index-7SsAJ4et.d.ts +525 -0
  16. package/dist/index-BGxYqpFb.d.cts +601 -0
  17. package/dist/index-BX62efZu.d.ts +565 -0
  18. package/dist/index-Bbc3COw0.d.cts +748 -0
  19. package/dist/index-Bczz1Eyk.d.ts +637 -0
  20. package/dist/index-C7pEiT8L.d.cts +637 -0
  21. package/dist/index-CHetLTb0.d.ts +389 -0
  22. package/dist/index-CloeiFyx.d.ts +748 -0
  23. package/dist/index-DNOhq-3y.d.cts +525 -0
  24. package/dist/index-Da-M8FOV.d.cts +389 -0
  25. package/dist/index-Dy8UjRFz.d.cts +565 -0
  26. package/dist/index-aVcITW0B.d.ts +601 -0
  27. package/dist/index.cjs +8554 -0
  28. package/dist/index.d.cts +293 -0
  29. package/dist/index.d.ts +293 -0
  30. package/dist/index.js +742 -0
  31. package/dist/processing/index.cjs +1575 -0
  32. package/dist/processing/index.d.cts +2 -0
  33. package/dist/processing/index.d.ts +2 -0
  34. package/dist/processing/index.js +24 -0
  35. package/dist/retrieval/index.cjs +1262 -0
  36. package/dist/retrieval/index.d.cts +2 -0
  37. package/dist/retrieval/index.d.ts +2 -0
  38. package/dist/retrieval/index.js +26 -0
  39. package/dist/sharing/index.cjs +1003 -0
  40. package/dist/sharing/index.d.cts +3 -0
  41. package/dist/sharing/index.d.ts +3 -0
  42. package/dist/sharing/index.js +16 -0
  43. package/dist/stores/index.cjs +1445 -0
  44. package/dist/stores/index.d.cts +2 -0
  45. package/dist/stores/index.d.ts +2 -0
  46. package/dist/stores/index.js +20 -0
  47. package/dist/structures/index.cjs +1530 -0
  48. package/dist/structures/index.d.cts +3 -0
  49. package/dist/structures/index.d.ts +3 -0
  50. package/dist/structures/index.js +24 -0
  51. package/package.json +141 -0
@@ -0,0 +1,1445 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/stores/index.ts
31
+ var stores_exports = {};
32
+ __export(stores_exports, {
33
+ InMemoryStore: () => InMemoryStore,
34
+ PostgresStore: () => PostgresStore,
35
+ RedisStore: () => RedisStore,
36
+ SQLiteStore: () => SQLiteStore,
37
+ createInMemoryStore: () => createInMemoryStore,
38
+ createPostgresStore: () => createPostgresStore,
39
+ createRedisStore: () => createRedisStore,
40
+ createSQLiteStore: () => createSQLiteStore
41
+ });
42
+ module.exports = __toCommonJS(stores_exports);
43
+
44
+ // src/stores/implementations/InMemoryStore.ts
45
+ var import_lru_cache = require("lru-cache");
46
+ var InMemoryStore = class {
47
+ cache;
48
+ constructor(config = {}) {
49
+ this.cache = new import_lru_cache.LRUCache({
50
+ max: config.maxSize ?? 1e4,
51
+ ttl: config.ttl,
52
+ updateAgeOnGet: true
53
+ });
54
+ }
55
+ /**
56
+ * Add a memory entry
57
+ */
58
+ async add(entry) {
59
+ this.cache.set(entry.id, entry);
60
+ return Promise.resolve(entry.id);
61
+ }
62
+ /**
63
+ * Get a memory entry by ID
64
+ */
65
+ async get(id) {
66
+ const entry = this.cache.get(id);
67
+ if (entry) {
68
+ entry.accessCount++;
69
+ entry.lastAccessedAt = Date.now();
70
+ this.cache.set(id, entry);
71
+ }
72
+ return Promise.resolve(entry ?? null);
73
+ }
74
+ /**
75
+ * Update a memory entry
76
+ */
77
+ async update(id, updates) {
78
+ const entry = this.cache.get(id);
79
+ if (!entry) {
80
+ return Promise.resolve(false);
81
+ }
82
+ const updated = {
83
+ ...entry,
84
+ ...updates,
85
+ metadata: {
86
+ ...entry.metadata,
87
+ ...updates.metadata
88
+ },
89
+ updatedAt: Date.now()
90
+ };
91
+ this.cache.set(id, updated);
92
+ return Promise.resolve(true);
93
+ }
94
+ /**
95
+ * Delete a memory entry
96
+ */
97
+ async delete(id) {
98
+ return Promise.resolve(this.cache.delete(id));
99
+ }
100
+ /**
101
+ * Query memory entries
102
+ */
103
+ async query(options) {
104
+ const entries = [];
105
+ const limit = options.limit ?? 100;
106
+ const offset = options.offset ?? 0;
107
+ for (const entry of this.cache.values()) {
108
+ if (this.matchesQuery(entry, options)) {
109
+ entries.push(entry);
110
+ }
111
+ }
112
+ entries.sort((a, b) => b.timestamp - a.timestamp);
113
+ const paginated = entries.slice(offset, offset + limit);
114
+ return Promise.resolve({
115
+ entries: paginated,
116
+ total: entries.length,
117
+ hasMore: offset + limit < entries.length
118
+ });
119
+ }
120
+ /**
121
+ * Search by vector similarity
122
+ */
123
+ async search(embedding, options) {
124
+ const results = [];
125
+ for (const entry of this.cache.values()) {
126
+ if (!entry.embedding) {
127
+ continue;
128
+ }
129
+ if (options.filter) {
130
+ if (!this.matchesFilter(entry, options.filter)) {
131
+ continue;
132
+ }
133
+ }
134
+ if (options.namespace && entry.metadata.namespace !== options.namespace) {
135
+ continue;
136
+ }
137
+ const score = this.cosineSimilarity(embedding, entry.embedding);
138
+ if (options.minScore !== void 0 && score < options.minScore) {
139
+ continue;
140
+ }
141
+ results.push({ entry, score });
142
+ }
143
+ results.sort((a, b) => b.score - a.score);
144
+ return Promise.resolve(results.slice(0, options.topK));
145
+ }
146
+ /**
147
+ * Clear entries
148
+ */
149
+ async clear(options) {
150
+ if (!options) {
151
+ const size = this.cache.size;
152
+ this.cache.clear();
153
+ return Promise.resolve(size);
154
+ }
155
+ let deleted = 0;
156
+ const toDelete = [];
157
+ for (const [id, entry] of this.cache.entries()) {
158
+ let shouldDelete = true;
159
+ if (options.namespace && entry.metadata.namespace !== options.namespace) {
160
+ shouldDelete = false;
161
+ }
162
+ if (options.userId && entry.metadata.userId !== options.userId) {
163
+ shouldDelete = false;
164
+ }
165
+ if (shouldDelete) {
166
+ toDelete.push(id);
167
+ }
168
+ }
169
+ for (const id of toDelete) {
170
+ this.cache.delete(id);
171
+ deleted++;
172
+ }
173
+ return Promise.resolve(deleted);
174
+ }
175
+ /**
176
+ * Count entries
177
+ */
178
+ async count(options) {
179
+ if (!options) {
180
+ return Promise.resolve(this.cache.size);
181
+ }
182
+ let count = 0;
183
+ for (const entry of this.cache.values()) {
184
+ if (this.matchesQuery(entry, options)) {
185
+ count++;
186
+ }
187
+ }
188
+ return Promise.resolve(count);
189
+ }
190
+ /**
191
+ * Close the store (no-op for in-memory)
192
+ */
193
+ async close() {
194
+ }
195
+ /**
196
+ * Check if entry matches query
197
+ */
198
+ matchesQuery(entry, options) {
199
+ if (options.query) {
200
+ const queryLower = options.query.toLowerCase();
201
+ if (!entry.content.toLowerCase().includes(queryLower)) {
202
+ return false;
203
+ }
204
+ }
205
+ if (options.userId && entry.metadata.userId !== options.userId) {
206
+ return false;
207
+ }
208
+ if (options.agentId && entry.metadata.agentId !== options.agentId) {
209
+ return false;
210
+ }
211
+ if (options.conversationId && entry.metadata.conversationId !== options.conversationId) {
212
+ return false;
213
+ }
214
+ if (options.sessionId && entry.metadata.sessionId !== options.sessionId) {
215
+ return false;
216
+ }
217
+ if (options.namespace && entry.metadata.namespace !== options.namespace) {
218
+ return false;
219
+ }
220
+ if (options.types && options.types.length > 0) {
221
+ if (!options.types.includes(entry.type)) {
222
+ return false;
223
+ }
224
+ }
225
+ if (options.tags && options.tags.length > 0) {
226
+ const entryTags = entry.metadata.tags ?? [];
227
+ const hasAllTags = options.tags.every((tag) => entryTags.includes(tag));
228
+ if (!hasAllTags) {
229
+ return false;
230
+ }
231
+ }
232
+ if (options.minImportance !== void 0 && entry.importance < options.minImportance) {
233
+ return false;
234
+ }
235
+ if (options.startTime !== void 0 && entry.timestamp < options.startTime) {
236
+ return false;
237
+ }
238
+ if (options.endTime !== void 0 && entry.timestamp > options.endTime) {
239
+ return false;
240
+ }
241
+ if (!options.includeExpired && entry.expiresAt) {
242
+ if (entry.expiresAt < Date.now()) {
243
+ return false;
244
+ }
245
+ }
246
+ return true;
247
+ }
248
+ /**
249
+ * Check if entry matches filter
250
+ */
251
+ matchesFilter(entry, filter) {
252
+ for (const [key, value] of Object.entries(filter)) {
253
+ if (value === void 0) continue;
254
+ if (key in entry.metadata) {
255
+ if (Array.isArray(value)) {
256
+ if (!value.includes(entry.metadata[key])) {
257
+ return false;
258
+ }
259
+ } else if (entry.metadata[key] !== value) {
260
+ return false;
261
+ }
262
+ } else if (key in entry) {
263
+ const entryValue = entry[key];
264
+ if (Array.isArray(value)) {
265
+ if (!value.includes(entryValue)) {
266
+ return false;
267
+ }
268
+ } else if (entryValue !== value) {
269
+ return false;
270
+ }
271
+ }
272
+ }
273
+ return true;
274
+ }
275
+ /**
276
+ * Calculate cosine similarity
277
+ */
278
+ cosineSimilarity(a, b) {
279
+ if (a.length !== b.length) {
280
+ throw new Error("Vectors must have the same length");
281
+ }
282
+ let dotProduct = 0;
283
+ let normA = 0;
284
+ let normB = 0;
285
+ for (let i = 0; i < a.length; i++) {
286
+ dotProduct += a[i] * b[i];
287
+ normA += a[i] * a[i];
288
+ normB += b[i] * b[i];
289
+ }
290
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
291
+ if (magnitude === 0) {
292
+ return 0;
293
+ }
294
+ return dotProduct / magnitude;
295
+ }
296
+ /**
297
+ * Get all entries (for debugging)
298
+ */
299
+ getAllEntries() {
300
+ return Array.from(this.cache.values());
301
+ }
302
+ /**
303
+ * Get cache size
304
+ */
305
+ get size() {
306
+ return this.cache.size;
307
+ }
308
+ };
309
+ function createInMemoryStore(config) {
310
+ return new InMemoryStore(config);
311
+ }
312
+
313
+ // src/stores/implementations/SQLiteStore.ts
314
+ var SQLiteStore = class {
315
+ db = null;
316
+ config;
317
+ tableName;
318
+ constructor(config) {
319
+ this.config = config;
320
+ this.tableName = config.tableName ?? "memories";
321
+ }
322
+ /**
323
+ * Initialize the database
324
+ */
325
+ async initialize() {
326
+ const BetterSqlite3 = (await import("better-sqlite3")).default;
327
+ this.db = new BetterSqlite3(this.config.path);
328
+ if (this.config.enableWAL !== false) {
329
+ this.db.pragma("journal_mode = WAL");
330
+ }
331
+ this.db.exec(`
332
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
333
+ id TEXT PRIMARY KEY,
334
+ content TEXT NOT NULL,
335
+ embedding BLOB,
336
+ type TEXT NOT NULL,
337
+ importance REAL NOT NULL,
338
+ metadata TEXT NOT NULL,
339
+ timestamp INTEGER NOT NULL,
340
+ expires_at INTEGER,
341
+ parent_id TEXT,
342
+ access_count INTEGER DEFAULT 0,
343
+ last_accessed_at INTEGER,
344
+ created_at INTEGER NOT NULL,
345
+ updated_at INTEGER NOT NULL
346
+ )
347
+ `);
348
+ this.db.exec(`
349
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_timestamp ON ${this.tableName}(timestamp);
350
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_type ON ${this.tableName}(type);
351
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_importance ON ${this.tableName}(importance);
352
+ `);
353
+ }
354
+ /**
355
+ * Ensure database is initialized
356
+ */
357
+ async ensureInitialized() {
358
+ if (!this.db) {
359
+ await this.initialize();
360
+ }
361
+ return this.db;
362
+ }
363
+ /**
364
+ * Add a memory entry
365
+ */
366
+ async add(entry) {
367
+ const db = await this.ensureInitialized();
368
+ const stmt = db.prepare(`
369
+ INSERT INTO ${this.tableName} (
370
+ id, content, embedding, type, importance, metadata,
371
+ timestamp, expires_at, parent_id, access_count,
372
+ last_accessed_at, created_at, updated_at
373
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
374
+ `);
375
+ stmt.run(
376
+ entry.id,
377
+ entry.content,
378
+ entry.embedding ? this.serializeVector(entry.embedding) : null,
379
+ entry.type,
380
+ entry.importance,
381
+ JSON.stringify(entry.metadata),
382
+ entry.timestamp,
383
+ entry.expiresAt ?? null,
384
+ entry.parentId ?? null,
385
+ entry.accessCount,
386
+ entry.lastAccessedAt ?? null,
387
+ entry.createdAt,
388
+ entry.updatedAt
389
+ );
390
+ return entry.id;
391
+ }
392
+ /**
393
+ * Get a memory entry by ID
394
+ */
395
+ async get(id) {
396
+ const db = await this.ensureInitialized();
397
+ const stmt = db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`);
398
+ const row = stmt.get(id);
399
+ if (!row) {
400
+ return null;
401
+ }
402
+ const updateStmt = db.prepare(`
403
+ UPDATE ${this.tableName}
404
+ SET access_count = access_count + 1, last_accessed_at = ?
405
+ WHERE id = ?
406
+ `);
407
+ updateStmt.run(Date.now(), id);
408
+ return Promise.resolve(this.rowToEntry(row));
409
+ }
410
+ /**
411
+ * Update a memory entry
412
+ */
413
+ async update(id, updates) {
414
+ const db = await this.ensureInitialized();
415
+ const existing = await this.get(id);
416
+ if (!existing) {
417
+ return false;
418
+ }
419
+ const updated = {
420
+ ...existing,
421
+ ...updates,
422
+ metadata: {
423
+ ...existing.metadata,
424
+ ...updates.metadata
425
+ },
426
+ updatedAt: Date.now()
427
+ };
428
+ const stmt = db.prepare(`
429
+ UPDATE ${this.tableName}
430
+ SET content = ?, embedding = ?, type = ?, importance = ?,
431
+ metadata = ?, expires_at = ?, updated_at = ?
432
+ WHERE id = ?
433
+ `);
434
+ const result = stmt.run(
435
+ updated.content,
436
+ updated.embedding ? this.serializeVector(updated.embedding) : null,
437
+ updated.type,
438
+ updated.importance,
439
+ JSON.stringify(updated.metadata),
440
+ updated.expiresAt ?? null,
441
+ updated.updatedAt,
442
+ id
443
+ );
444
+ return result.changes > 0;
445
+ }
446
+ /**
447
+ * Delete a memory entry
448
+ */
449
+ async delete(id) {
450
+ const db = await this.ensureInitialized();
451
+ const stmt = db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`);
452
+ const result = stmt.run(id);
453
+ return result.changes > 0;
454
+ }
455
+ /**
456
+ * Query memory entries
457
+ */
458
+ async query(options) {
459
+ const db = await this.ensureInitialized();
460
+ const conditions = [];
461
+ const params = [];
462
+ if (options.query) {
463
+ conditions.push("content LIKE ?");
464
+ params.push(`%${options.query}%`);
465
+ }
466
+ if (options.userId) {
467
+ conditions.push("json_extract(metadata, '$.userId') = ?");
468
+ params.push(options.userId);
469
+ }
470
+ if (options.agentId) {
471
+ conditions.push("json_extract(metadata, '$.agentId') = ?");
472
+ params.push(options.agentId);
473
+ }
474
+ if (options.conversationId) {
475
+ conditions.push("json_extract(metadata, '$.conversationId') = ?");
476
+ params.push(options.conversationId);
477
+ }
478
+ if (options.namespace) {
479
+ conditions.push("json_extract(metadata, '$.namespace') = ?");
480
+ params.push(options.namespace);
481
+ }
482
+ if (options.types && options.types.length > 0) {
483
+ const placeholders = options.types.map(() => "?").join(", ");
484
+ conditions.push(`type IN (${placeholders})`);
485
+ params.push(...options.types);
486
+ }
487
+ if (options.minImportance !== void 0) {
488
+ conditions.push("importance >= ?");
489
+ params.push(options.minImportance);
490
+ }
491
+ if (options.startTime !== void 0) {
492
+ conditions.push("timestamp >= ?");
493
+ params.push(options.startTime);
494
+ }
495
+ if (options.endTime !== void 0) {
496
+ conditions.push("timestamp <= ?");
497
+ params.push(options.endTime);
498
+ }
499
+ if (!options.includeExpired) {
500
+ conditions.push("(expires_at IS NULL OR expires_at > ?)");
501
+ params.push(Date.now());
502
+ }
503
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
504
+ const countStmt = db.prepare(
505
+ `SELECT COUNT(*) as count FROM ${this.tableName} ${whereClause}`
506
+ );
507
+ const countResult = countStmt.get(...params);
508
+ const total = countResult.count;
509
+ const limit = options.limit ?? 100;
510
+ const offset = options.offset ?? 0;
511
+ const queryStmt = db.prepare(`
512
+ SELECT * FROM ${this.tableName}
513
+ ${whereClause}
514
+ ORDER BY timestamp DESC
515
+ LIMIT ? OFFSET ?
516
+ `);
517
+ const rows = queryStmt.all(...params, limit, offset);
518
+ const entries = rows.map((row) => this.rowToEntry(row));
519
+ return {
520
+ entries,
521
+ total,
522
+ hasMore: offset + limit < total
523
+ };
524
+ }
525
+ /**
526
+ * Search by vector similarity
527
+ */
528
+ async search(embedding, options) {
529
+ const db = await this.ensureInitialized();
530
+ const conditions = ["embedding IS NOT NULL"];
531
+ const params = [];
532
+ if (options.namespace) {
533
+ conditions.push("json_extract(metadata, '$.namespace') = ?");
534
+ params.push(options.namespace);
535
+ }
536
+ if (options.filter) {
537
+ for (const [key, value] of Object.entries(options.filter)) {
538
+ if (value !== void 0) {
539
+ if (Array.isArray(value)) {
540
+ const placeholders = value.map(() => "?").join(", ");
541
+ conditions.push(
542
+ `json_extract(metadata, '$.${key}') IN (${placeholders})`
543
+ );
544
+ params.push(...value);
545
+ } else {
546
+ conditions.push(`json_extract(metadata, '$.${key}') = ?`);
547
+ params.push(value);
548
+ }
549
+ }
550
+ }
551
+ }
552
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
553
+ const stmt = db.prepare(`SELECT * FROM ${this.tableName} ${whereClause}`);
554
+ const rows = stmt.all(...params);
555
+ const results = [];
556
+ for (const row of rows) {
557
+ const entry = this.rowToEntry(row);
558
+ if (!entry.embedding) continue;
559
+ const score = this.cosineSimilarity(embedding, entry.embedding);
560
+ if (options.minScore === void 0 || score >= options.minScore) {
561
+ results.push({ entry, score });
562
+ }
563
+ }
564
+ results.sort((a, b) => b.score - a.score);
565
+ return Promise.resolve(results.slice(0, options.topK));
566
+ }
567
+ /**
568
+ * Clear entries
569
+ */
570
+ async clear(options) {
571
+ const db = await this.ensureInitialized();
572
+ if (!options) {
573
+ const stmt2 = db.prepare(`DELETE FROM ${this.tableName}`);
574
+ const result2 = stmt2.run();
575
+ return result2.changes;
576
+ }
577
+ const conditions = [];
578
+ const params = [];
579
+ if (options.namespace) {
580
+ conditions.push("json_extract(metadata, '$.namespace') = ?");
581
+ params.push(options.namespace);
582
+ }
583
+ if (options.userId) {
584
+ conditions.push("json_extract(metadata, '$.userId') = ?");
585
+ params.push(options.userId);
586
+ }
587
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
588
+ const stmt = db.prepare(`DELETE FROM ${this.tableName} ${whereClause}`);
589
+ const result = stmt.run(...params);
590
+ return result.changes;
591
+ }
592
+ /**
593
+ * Count entries
594
+ */
595
+ async count(options) {
596
+ const db = await this.ensureInitialized();
597
+ if (!options) {
598
+ const stmt = db.prepare(
599
+ `SELECT COUNT(*) as count FROM ${this.tableName}`
600
+ );
601
+ const result = stmt.get();
602
+ return result.count;
603
+ }
604
+ const { total } = await this.query({ ...options, limit: 0 });
605
+ return total;
606
+ }
607
+ /**
608
+ * Close the database
609
+ */
610
+ async close() {
611
+ if (this.db) {
612
+ this.db.close();
613
+ this.db = null;
614
+ }
615
+ return Promise.resolve();
616
+ }
617
+ /**
618
+ * Convert database row to MemoryEntry
619
+ */
620
+ rowToEntry(row) {
621
+ return {
622
+ id: row.id,
623
+ content: row.content,
624
+ embedding: row.embedding ? this.deserializeVector(row.embedding) : void 0,
625
+ type: row.type,
626
+ importance: row.importance,
627
+ metadata: JSON.parse(row.metadata),
628
+ timestamp: row.timestamp,
629
+ expiresAt: row.expires_at,
630
+ parentId: row.parent_id,
631
+ accessCount: row.access_count,
632
+ lastAccessedAt: row.last_accessed_at,
633
+ createdAt: row.created_at,
634
+ updatedAt: row.updated_at
635
+ };
636
+ }
637
+ /**
638
+ * Serialize vector to buffer
639
+ */
640
+ serializeVector(vector) {
641
+ const buffer = Buffer.alloc(vector.length * 4);
642
+ for (let i = 0; i < vector.length; i++) {
643
+ buffer.writeFloatLE(vector[i], i * 4);
644
+ }
645
+ return buffer;
646
+ }
647
+ /**
648
+ * Deserialize vector from buffer
649
+ */
650
+ deserializeVector(buffer) {
651
+ const vector = [];
652
+ for (let i = 0; i < buffer.length / 4; i++) {
653
+ vector.push(buffer.readFloatLE(i * 4));
654
+ }
655
+ return vector;
656
+ }
657
+ /**
658
+ * Calculate cosine similarity
659
+ */
660
+ cosineSimilarity(a, b) {
661
+ if (a.length !== b.length) {
662
+ throw new Error("Vectors must have the same length");
663
+ }
664
+ let dotProduct = 0;
665
+ let normA = 0;
666
+ let normB = 0;
667
+ for (let i = 0; i < a.length; i++) {
668
+ dotProduct += a[i] * b[i];
669
+ normA += a[i] * a[i];
670
+ normB += b[i] * b[i];
671
+ }
672
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
673
+ if (magnitude === 0) {
674
+ return 0;
675
+ }
676
+ return dotProduct / magnitude;
677
+ }
678
+ };
679
+ async function createSQLiteStore(config) {
680
+ const store = new SQLiteStore(config);
681
+ await store.initialize();
682
+ return store;
683
+ }
684
+
685
+ // src/stores/implementations/PostgresStore.ts
686
+ var PostgresStore = class {
687
+ pool = null;
688
+ config;
689
+ tableName;
690
+ vectorDimensions;
691
+ initialized = false;
692
+ constructor(config) {
693
+ this.config = config;
694
+ this.tableName = config.tableName ?? "memories";
695
+ this.vectorDimensions = config.vectorDimensions ?? 1536;
696
+ }
697
+ /**
698
+ * Initialize the database
699
+ */
700
+ async initialize() {
701
+ if (this.initialized) return;
702
+ const { Pool } = await import("pg");
703
+ if (this.config.connectionString) {
704
+ this.pool = new Pool({
705
+ connectionString: this.config.connectionString,
706
+ max: this.config.poolSize ?? 10,
707
+ ssl: this.config.ssl
708
+ });
709
+ } else {
710
+ this.pool = new Pool({
711
+ host: this.config.host ?? "localhost",
712
+ port: this.config.port ?? 5432,
713
+ database: this.config.database ?? "agentsea",
714
+ user: this.config.user ?? "postgres",
715
+ password: this.config.password,
716
+ max: this.config.poolSize ?? 10,
717
+ ssl: this.config.ssl
718
+ });
719
+ }
720
+ await this.pool.query("CREATE EXTENSION IF NOT EXISTS vector");
721
+ await this.pool.query(`
722
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
723
+ id TEXT PRIMARY KEY,
724
+ content TEXT NOT NULL,
725
+ embedding vector(${this.vectorDimensions}),
726
+ type TEXT NOT NULL,
727
+ importance REAL NOT NULL,
728
+ metadata JSONB NOT NULL,
729
+ timestamp BIGINT NOT NULL,
730
+ expires_at BIGINT,
731
+ parent_id TEXT,
732
+ access_count INTEGER DEFAULT 0,
733
+ last_accessed_at BIGINT,
734
+ created_at BIGINT NOT NULL,
735
+ updated_at BIGINT NOT NULL
736
+ )
737
+ `);
738
+ await this.pool.query(`
739
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_timestamp ON ${this.tableName}(timestamp);
740
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_type ON ${this.tableName}(type);
741
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_importance ON ${this.tableName}(importance);
742
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_metadata ON ${this.tableName} USING GIN(metadata);
743
+ `);
744
+ await this.pool.query(
745
+ `
746
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_embedding
747
+ ON ${this.tableName} USING ivfflat (embedding vector_cosine_ops)
748
+ WITH (lists = 100)
749
+ `
750
+ ).catch(() => {
751
+ });
752
+ this.initialized = true;
753
+ }
754
+ /**
755
+ * Ensure database is initialized
756
+ */
757
+ async ensureInitialized() {
758
+ if (!this.initialized) {
759
+ await this.initialize();
760
+ }
761
+ return this.pool;
762
+ }
763
+ /**
764
+ * Add a memory entry
765
+ */
766
+ async add(entry) {
767
+ const pool = await this.ensureInitialized();
768
+ const embeddingValue = entry.embedding ? `[${entry.embedding.join(",")}]` : null;
769
+ await pool.query(
770
+ `INSERT INTO ${this.tableName} (
771
+ id, content, embedding, type, importance, metadata,
772
+ timestamp, expires_at, parent_id, access_count,
773
+ last_accessed_at, created_at, updated_at
774
+ ) VALUES ($1, $2, $3::vector, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,
775
+ [
776
+ entry.id,
777
+ entry.content,
778
+ embeddingValue,
779
+ entry.type,
780
+ entry.importance,
781
+ JSON.stringify(entry.metadata),
782
+ entry.timestamp,
783
+ entry.expiresAt ?? null,
784
+ entry.parentId ?? null,
785
+ entry.accessCount,
786
+ entry.lastAccessedAt ?? null,
787
+ entry.createdAt,
788
+ entry.updatedAt
789
+ ]
790
+ );
791
+ return entry.id;
792
+ }
793
+ /**
794
+ * Get a memory entry by ID
795
+ */
796
+ async get(id) {
797
+ const pool = await this.ensureInitialized();
798
+ const result = await pool.query(
799
+ `SELECT * FROM ${this.tableName} WHERE id = $1`,
800
+ [id]
801
+ );
802
+ if (result.rows.length === 0) {
803
+ return null;
804
+ }
805
+ await pool.query(
806
+ `UPDATE ${this.tableName}
807
+ SET access_count = access_count + 1, last_accessed_at = $1
808
+ WHERE id = $2`,
809
+ [Date.now(), id]
810
+ );
811
+ return Promise.resolve(this.rowToEntry(result.rows[0]));
812
+ }
813
+ /**
814
+ * Update a memory entry
815
+ */
816
+ async update(id, updates) {
817
+ const pool = await this.ensureInitialized();
818
+ const existing = await this.get(id);
819
+ if (!existing) {
820
+ return false;
821
+ }
822
+ const updated = {
823
+ ...existing,
824
+ ...updates,
825
+ metadata: {
826
+ ...existing.metadata,
827
+ ...updates.metadata
828
+ },
829
+ updatedAt: Date.now()
830
+ };
831
+ const embeddingValue = updated.embedding ? `[${updated.embedding.join(",")}]` : null;
832
+ const result = await pool.query(
833
+ `UPDATE ${this.tableName}
834
+ SET content = $1, embedding = $2::vector, type = $3, importance = $4,
835
+ metadata = $5, expires_at = $6, updated_at = $7
836
+ WHERE id = $8`,
837
+ [
838
+ updated.content,
839
+ embeddingValue,
840
+ updated.type,
841
+ updated.importance,
842
+ JSON.stringify(updated.metadata),
843
+ updated.expiresAt ?? null,
844
+ updated.updatedAt,
845
+ id
846
+ ]
847
+ );
848
+ return result.rowCount !== null && result.rowCount > 0;
849
+ }
850
+ /**
851
+ * Delete a memory entry
852
+ */
853
+ async delete(id) {
854
+ const pool = await this.ensureInitialized();
855
+ const result = await pool.query(
856
+ `DELETE FROM ${this.tableName} WHERE id = $1`,
857
+ [id]
858
+ );
859
+ return result.rowCount !== null && result.rowCount > 0;
860
+ }
861
+ /**
862
+ * Query memory entries
863
+ */
864
+ async query(options) {
865
+ const pool = await this.ensureInitialized();
866
+ const conditions = [];
867
+ const params = [];
868
+ let paramIndex = 1;
869
+ if (options.query) {
870
+ conditions.push(`content ILIKE $${paramIndex}`);
871
+ params.push(`%${options.query}%`);
872
+ paramIndex++;
873
+ }
874
+ if (options.userId) {
875
+ conditions.push(`metadata->>'userId' = $${paramIndex}`);
876
+ params.push(options.userId);
877
+ paramIndex++;
878
+ }
879
+ if (options.agentId) {
880
+ conditions.push(`metadata->>'agentId' = $${paramIndex}`);
881
+ params.push(options.agentId);
882
+ paramIndex++;
883
+ }
884
+ if (options.conversationId) {
885
+ conditions.push(`metadata->>'conversationId' = $${paramIndex}`);
886
+ params.push(options.conversationId);
887
+ paramIndex++;
888
+ }
889
+ if (options.namespace) {
890
+ conditions.push(`metadata->>'namespace' = $${paramIndex}`);
891
+ params.push(options.namespace);
892
+ paramIndex++;
893
+ }
894
+ if (options.types && options.types.length > 0) {
895
+ conditions.push(`type = ANY($${paramIndex})`);
896
+ params.push(options.types);
897
+ paramIndex++;
898
+ }
899
+ if (options.minImportance !== void 0) {
900
+ conditions.push(`importance >= $${paramIndex}`);
901
+ params.push(options.minImportance);
902
+ paramIndex++;
903
+ }
904
+ if (options.startTime !== void 0) {
905
+ conditions.push(`timestamp >= $${paramIndex}`);
906
+ params.push(options.startTime);
907
+ paramIndex++;
908
+ }
909
+ if (options.endTime !== void 0) {
910
+ conditions.push(`timestamp <= $${paramIndex}`);
911
+ params.push(options.endTime);
912
+ paramIndex++;
913
+ }
914
+ if (!options.includeExpired) {
915
+ conditions.push(`(expires_at IS NULL OR expires_at > $${paramIndex})`);
916
+ params.push(Date.now());
917
+ paramIndex++;
918
+ }
919
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
920
+ const countResult = await pool.query(
921
+ `SELECT COUNT(*) as count FROM ${this.tableName} ${whereClause}`,
922
+ params
923
+ );
924
+ const total = parseInt(countResult.rows[0].count, 10);
925
+ const limit = options.limit ?? 100;
926
+ const offset = options.offset ?? 0;
927
+ const queryResult = await pool.query(
928
+ `SELECT * FROM ${this.tableName}
929
+ ${whereClause}
930
+ ORDER BY timestamp DESC
931
+ LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
932
+ [...params, limit, offset]
933
+ );
934
+ const entries = queryResult.rows.map((row) => this.rowToEntry(row));
935
+ return {
936
+ entries,
937
+ total,
938
+ hasMore: offset + limit < total
939
+ };
940
+ }
941
+ /**
942
+ * Search by vector similarity using pgvector
943
+ */
944
+ async search(embedding, options) {
945
+ const pool = await this.ensureInitialized();
946
+ const conditions = ["embedding IS NOT NULL"];
947
+ const params = [`[${embedding.join(",")}]`];
948
+ let paramIndex = 2;
949
+ if (options.namespace) {
950
+ conditions.push(`metadata->>'namespace' = $${paramIndex}`);
951
+ params.push(options.namespace);
952
+ paramIndex++;
953
+ }
954
+ if (options.filter) {
955
+ for (const [key, value] of Object.entries(options.filter)) {
956
+ if (value !== void 0) {
957
+ if (Array.isArray(value)) {
958
+ conditions.push(`metadata->>'${key}' = ANY($${paramIndex})`);
959
+ params.push(value);
960
+ } else {
961
+ conditions.push(`metadata->>'${key}' = $${paramIndex}`);
962
+ params.push(value);
963
+ }
964
+ paramIndex++;
965
+ }
966
+ }
967
+ }
968
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
969
+ const minScore = options.minScore ?? 0;
970
+ const result = await pool.query(
971
+ `SELECT *, 1 - (embedding <=> $1::vector) as score
972
+ FROM ${this.tableName}
973
+ ${whereClause}
974
+ AND 1 - (embedding <=> $1::vector) >= $${paramIndex}
975
+ ORDER BY embedding <=> $1::vector
976
+ LIMIT $${paramIndex + 1}`,
977
+ [...params, minScore, options.topK]
978
+ );
979
+ return result.rows.map((row) => ({
980
+ entry: this.rowToEntry(row),
981
+ score: parseFloat(row.score)
982
+ }));
983
+ }
984
+ /**
985
+ * Clear entries
986
+ */
987
+ async clear(options) {
988
+ const pool = await this.ensureInitialized();
989
+ if (!options) {
990
+ const result2 = await pool.query(`DELETE FROM ${this.tableName}`);
991
+ return result2.rowCount ?? 0;
992
+ }
993
+ const conditions = [];
994
+ const params = [];
995
+ let paramIndex = 1;
996
+ if (options.namespace) {
997
+ conditions.push(`metadata->>'namespace' = $${paramIndex}`);
998
+ params.push(options.namespace);
999
+ paramIndex++;
1000
+ }
1001
+ if (options.userId) {
1002
+ conditions.push(`metadata->>'userId' = $${paramIndex}`);
1003
+ params.push(options.userId);
1004
+ }
1005
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1006
+ const result = await pool.query(
1007
+ `DELETE FROM ${this.tableName} ${whereClause}`,
1008
+ params
1009
+ );
1010
+ return result.rowCount ?? 0;
1011
+ }
1012
+ /**
1013
+ * Count entries
1014
+ */
1015
+ async count(options) {
1016
+ const pool = await this.ensureInitialized();
1017
+ if (!options) {
1018
+ const result = await pool.query(
1019
+ `SELECT COUNT(*) as count FROM ${this.tableName}`
1020
+ );
1021
+ return Promise.resolve(parseInt(result.rows[0].count, 10));
1022
+ }
1023
+ const { total } = await this.query({ ...options, limit: 0 });
1024
+ return total;
1025
+ }
1026
+ /**
1027
+ * Close the connection pool
1028
+ */
1029
+ async close() {
1030
+ if (this.pool) {
1031
+ await this.pool.end();
1032
+ this.pool = null;
1033
+ this.initialized = false;
1034
+ }
1035
+ }
1036
+ /**
1037
+ * Convert database row to MemoryEntry
1038
+ */
1039
+ rowToEntry(row) {
1040
+ const embedding = row.embedding;
1041
+ let embeddingArray;
1042
+ if (embedding) {
1043
+ const cleaned = embedding.replace(/[[\]]/g, "");
1044
+ embeddingArray = cleaned.split(",").map((v) => parseFloat(v));
1045
+ }
1046
+ return {
1047
+ id: row.id,
1048
+ content: row.content,
1049
+ embedding: embeddingArray,
1050
+ type: row.type,
1051
+ importance: parseFloat(row.importance),
1052
+ metadata: row.metadata,
1053
+ timestamp: parseInt(row.timestamp, 10),
1054
+ expiresAt: row.expires_at ? parseInt(row.expires_at, 10) : void 0,
1055
+ parentId: row.parent_id,
1056
+ accessCount: parseInt(row.access_count, 10),
1057
+ lastAccessedAt: row.last_accessed_at ? parseInt(row.last_accessed_at, 10) : void 0,
1058
+ createdAt: parseInt(row.created_at, 10),
1059
+ updatedAt: parseInt(row.updated_at, 10)
1060
+ };
1061
+ }
1062
+ };
1063
+ async function createPostgresStore(config) {
1064
+ const store = new PostgresStore(config);
1065
+ await store.initialize();
1066
+ return store;
1067
+ }
1068
+
1069
+ // src/stores/implementations/RedisStore.ts
1070
+ var RedisStore = class {
1071
+ redis = null;
1072
+ config;
1073
+ keyPrefix;
1074
+ ttl;
1075
+ initialized = false;
1076
+ constructor(config) {
1077
+ this.config = config;
1078
+ this.keyPrefix = config.keyPrefix ?? "memory:";
1079
+ this.ttl = config.ttl;
1080
+ }
1081
+ /**
1082
+ * Initialize Redis connection
1083
+ */
1084
+ async initialize() {
1085
+ if (this.initialized) return;
1086
+ const Redis = (await import("ioredis")).default;
1087
+ if (this.config.url) {
1088
+ this.redis = new Redis(this.config.url);
1089
+ } else {
1090
+ this.redis = new Redis({
1091
+ host: this.config.host ?? "localhost",
1092
+ port: this.config.port ?? 6379,
1093
+ password: this.config.password,
1094
+ db: this.config.db ?? 0
1095
+ });
1096
+ }
1097
+ this.initialized = true;
1098
+ }
1099
+ /**
1100
+ * Ensure Redis is initialized
1101
+ */
1102
+ async ensureInitialized() {
1103
+ if (!this.initialized) {
1104
+ await this.initialize();
1105
+ }
1106
+ return this.redis;
1107
+ }
1108
+ /**
1109
+ * Get key for memory entry
1110
+ */
1111
+ getKey(id) {
1112
+ return `${this.keyPrefix}${id}`;
1113
+ }
1114
+ /**
1115
+ * Get index key
1116
+ */
1117
+ getIndexKey(index) {
1118
+ return `${this.keyPrefix}index:${index}`;
1119
+ }
1120
+ /**
1121
+ * Add a memory entry
1122
+ */
1123
+ async add(entry) {
1124
+ const redis = await this.ensureInitialized();
1125
+ const key = this.getKey(entry.id);
1126
+ const data = JSON.stringify(entry);
1127
+ if (this.ttl || entry.expiresAt) {
1128
+ const ttlMs = entry.expiresAt ? entry.expiresAt - Date.now() : this.ttl * 1e3;
1129
+ if (ttlMs > 0) {
1130
+ await redis.setex(key, Math.ceil(ttlMs / 1e3), data);
1131
+ } else {
1132
+ await redis.set(key, data);
1133
+ }
1134
+ } else {
1135
+ await redis.set(key, data);
1136
+ }
1137
+ await this.addToIndexes(entry);
1138
+ return entry.id;
1139
+ }
1140
+ /**
1141
+ * Add entry to indexes
1142
+ */
1143
+ async addToIndexes(entry) {
1144
+ const redis = await this.ensureInitialized();
1145
+ const score = entry.timestamp;
1146
+ await redis.zadd(this.getIndexKey("all"), score, entry.id);
1147
+ await redis.zadd(this.getIndexKey(`type:${entry.type}`), score, entry.id);
1148
+ const namespace = entry.metadata.namespace ?? "default";
1149
+ await redis.zadd(
1150
+ this.getIndexKey(`namespace:${namespace}`),
1151
+ score,
1152
+ entry.id
1153
+ );
1154
+ if (entry.metadata.userId) {
1155
+ await redis.zadd(
1156
+ this.getIndexKey(`user:${entry.metadata.userId}`),
1157
+ score,
1158
+ entry.id
1159
+ );
1160
+ }
1161
+ if (entry.metadata.conversationId) {
1162
+ await redis.zadd(
1163
+ this.getIndexKey(`conversation:${entry.metadata.conversationId}`),
1164
+ score,
1165
+ entry.id
1166
+ );
1167
+ }
1168
+ }
1169
+ /**
1170
+ * Remove entry from indexes
1171
+ */
1172
+ async removeFromIndexes(entry) {
1173
+ const redis = await this.ensureInitialized();
1174
+ await redis.zrem(this.getIndexKey("all"), entry.id);
1175
+ await redis.zrem(this.getIndexKey(`type:${entry.type}`), entry.id);
1176
+ const namespace = entry.metadata.namespace ?? "default";
1177
+ await redis.zrem(this.getIndexKey(`namespace:${namespace}`), entry.id);
1178
+ if (entry.metadata.userId) {
1179
+ await redis.zrem(
1180
+ this.getIndexKey(`user:${entry.metadata.userId}`),
1181
+ entry.id
1182
+ );
1183
+ }
1184
+ if (entry.metadata.conversationId) {
1185
+ await redis.zrem(
1186
+ this.getIndexKey(`conversation:${entry.metadata.conversationId}`),
1187
+ entry.id
1188
+ );
1189
+ }
1190
+ }
1191
+ /**
1192
+ * Get a memory entry by ID
1193
+ */
1194
+ async get(id) {
1195
+ const redis = await this.ensureInitialized();
1196
+ const key = this.getKey(id);
1197
+ const data = await redis.get(key);
1198
+ if (!data) {
1199
+ return null;
1200
+ }
1201
+ const entry = JSON.parse(data);
1202
+ entry.accessCount++;
1203
+ entry.lastAccessedAt = Date.now();
1204
+ await redis.set(key, JSON.stringify(entry));
1205
+ return entry;
1206
+ }
1207
+ /**
1208
+ * Update a memory entry
1209
+ */
1210
+ async update(id, updates) {
1211
+ const redis = await this.ensureInitialized();
1212
+ const existing = await this.get(id);
1213
+ if (!existing) {
1214
+ return false;
1215
+ }
1216
+ await this.removeFromIndexes(existing);
1217
+ const updated = {
1218
+ ...existing,
1219
+ ...updates,
1220
+ metadata: {
1221
+ ...existing.metadata,
1222
+ ...updates.metadata
1223
+ },
1224
+ updatedAt: Date.now()
1225
+ };
1226
+ const key = this.getKey(id);
1227
+ await redis.set(key, JSON.stringify(updated));
1228
+ await this.addToIndexes(updated);
1229
+ return true;
1230
+ }
1231
+ /**
1232
+ * Delete a memory entry
1233
+ */
1234
+ async delete(id) {
1235
+ const redis = await this.ensureInitialized();
1236
+ const existing = await this.get(id);
1237
+ if (!existing) {
1238
+ return false;
1239
+ }
1240
+ await this.removeFromIndexes(existing);
1241
+ const result = await redis.del(this.getKey(id));
1242
+ return result > 0;
1243
+ }
1244
+ /**
1245
+ * Query memory entries
1246
+ */
1247
+ async query(options) {
1248
+ const redis = await this.ensureInitialized();
1249
+ let indexKey = this.getIndexKey("all");
1250
+ if (options.conversationId) {
1251
+ indexKey = this.getIndexKey(`conversation:${options.conversationId}`);
1252
+ } else if (options.userId) {
1253
+ indexKey = this.getIndexKey(`user:${options.userId}`);
1254
+ } else if (options.namespace) {
1255
+ indexKey = this.getIndexKey(`namespace:${options.namespace}`);
1256
+ } else if (options.types && options.types.length === 1) {
1257
+ indexKey = this.getIndexKey(`type:${options.types[0]}`);
1258
+ }
1259
+ const minScore = options.startTime ?? "-inf";
1260
+ const maxScore = options.endTime ?? "+inf";
1261
+ const ids = await redis.zrevrangebyscore(
1262
+ indexKey,
1263
+ maxScore,
1264
+ minScore,
1265
+ "LIMIT",
1266
+ 0,
1267
+ 1e3
1268
+ // Get more than needed for filtering
1269
+ );
1270
+ const entries = [];
1271
+ const pipeline = redis.pipeline();
1272
+ for (const id of ids) {
1273
+ pipeline.get(this.getKey(id));
1274
+ }
1275
+ const results = await pipeline.exec();
1276
+ if (results) {
1277
+ for (const [err, data] of results) {
1278
+ if (!err && data) {
1279
+ const entry = JSON.parse(data);
1280
+ if (this.matchesQuery(entry, options)) {
1281
+ entries.push(entry);
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+ const limit = options.limit ?? 100;
1287
+ const offset = options.offset ?? 0;
1288
+ const paginated = entries.slice(offset, offset + limit);
1289
+ return {
1290
+ entries: paginated,
1291
+ total: entries.length,
1292
+ hasMore: offset + limit < entries.length
1293
+ };
1294
+ }
1295
+ /**
1296
+ * Check if entry matches query
1297
+ */
1298
+ matchesQuery(entry, options) {
1299
+ if (options.query) {
1300
+ if (!entry.content.toLowerCase().includes(options.query.toLowerCase())) {
1301
+ return false;
1302
+ }
1303
+ }
1304
+ if (options.userId && entry.metadata.userId !== options.userId) {
1305
+ return false;
1306
+ }
1307
+ if (options.agentId && entry.metadata.agentId !== options.agentId) {
1308
+ return false;
1309
+ }
1310
+ if (options.conversationId && entry.metadata.conversationId !== options.conversationId) {
1311
+ return false;
1312
+ }
1313
+ if (options.namespace && entry.metadata.namespace !== options.namespace) {
1314
+ return false;
1315
+ }
1316
+ if (options.types && options.types.length > 0 && !options.types.includes(entry.type)) {
1317
+ return false;
1318
+ }
1319
+ if (options.minImportance !== void 0 && entry.importance < options.minImportance) {
1320
+ return false;
1321
+ }
1322
+ if (options.tags && options.tags.length > 0) {
1323
+ const entryTags = entry.metadata.tags ?? [];
1324
+ if (!options.tags.every((tag) => entryTags.includes(tag))) {
1325
+ return false;
1326
+ }
1327
+ }
1328
+ if (!options.includeExpired && entry.expiresAt && entry.expiresAt < Date.now()) {
1329
+ return false;
1330
+ }
1331
+ return true;
1332
+ }
1333
+ /**
1334
+ * Search by vector similarity
1335
+ */
1336
+ async search(embedding, options) {
1337
+ const { entries } = await this.query({
1338
+ limit: 1e4,
1339
+ namespace: options.namespace
1340
+ });
1341
+ const results = [];
1342
+ for (const entry of entries) {
1343
+ if (!entry.embedding) continue;
1344
+ if (options.filter) {
1345
+ let matches = true;
1346
+ for (const [key, value] of Object.entries(options.filter)) {
1347
+ if (value !== void 0) {
1348
+ const metaValue = entry.metadata[key];
1349
+ if (Array.isArray(value)) {
1350
+ if (!value.includes(metaValue)) {
1351
+ matches = false;
1352
+ break;
1353
+ }
1354
+ } else if (metaValue !== value) {
1355
+ matches = false;
1356
+ break;
1357
+ }
1358
+ }
1359
+ }
1360
+ if (!matches) continue;
1361
+ }
1362
+ const score = this.cosineSimilarity(embedding, entry.embedding);
1363
+ if (options.minScore === void 0 || score >= options.minScore) {
1364
+ results.push({ entry, score });
1365
+ }
1366
+ }
1367
+ results.sort((a, b) => b.score - a.score);
1368
+ return Promise.resolve(results.slice(0, options.topK));
1369
+ }
1370
+ /**
1371
+ * Calculate cosine similarity
1372
+ */
1373
+ cosineSimilarity(a, b) {
1374
+ if (a.length !== b.length) return 0;
1375
+ let dotProduct = 0;
1376
+ let normA = 0;
1377
+ let normB = 0;
1378
+ for (let i = 0; i < a.length; i++) {
1379
+ dotProduct += a[i] * b[i];
1380
+ normA += a[i] * a[i];
1381
+ normB += b[i] * b[i];
1382
+ }
1383
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
1384
+ return magnitude === 0 ? 0 : dotProduct / magnitude;
1385
+ }
1386
+ /**
1387
+ * Clear entries
1388
+ */
1389
+ async clear(options) {
1390
+ const redis = await this.ensureInitialized();
1391
+ if (!options) {
1392
+ const keys = await redis.keys(`${this.keyPrefix}*`);
1393
+ if (keys.length > 0) {
1394
+ await redis.del(...keys);
1395
+ }
1396
+ return keys.length;
1397
+ }
1398
+ const { entries } = await this.query({
1399
+ namespace: options.namespace,
1400
+ userId: options.userId,
1401
+ limit: 1e5
1402
+ });
1403
+ for (const entry of entries) {
1404
+ await this.delete(entry.id);
1405
+ }
1406
+ return entries.length;
1407
+ }
1408
+ /**
1409
+ * Count entries
1410
+ */
1411
+ async count(options) {
1412
+ const redis = await this.ensureInitialized();
1413
+ if (!options) {
1414
+ return Promise.resolve(redis.zcard(this.getIndexKey("all")));
1415
+ }
1416
+ const { total } = await this.query({ ...options, limit: 0 });
1417
+ return total;
1418
+ }
1419
+ /**
1420
+ * Close Redis connection
1421
+ */
1422
+ async close() {
1423
+ if (this.redis) {
1424
+ await this.redis.quit();
1425
+ this.redis = null;
1426
+ this.initialized = false;
1427
+ }
1428
+ }
1429
+ };
1430
+ async function createRedisStore(config) {
1431
+ const store = new RedisStore(config);
1432
+ await store.initialize();
1433
+ return store;
1434
+ }
1435
+ // Annotate the CommonJS export names for ESM import in node:
1436
+ 0 && (module.exports = {
1437
+ InMemoryStore,
1438
+ PostgresStore,
1439
+ RedisStore,
1440
+ SQLiteStore,
1441
+ createInMemoryStore,
1442
+ createPostgresStore,
1443
+ createRedisStore,
1444
+ createSQLiteStore
1445
+ });