@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,1248 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/debug/index.ts
21
+ var debug_exports = {};
22
+ __export(debug_exports, {
23
+ Debugger: () => Debugger,
24
+ Exporter: () => Exporter,
25
+ Inspector: () => Inspector,
26
+ Timeline: () => Timeline,
27
+ createDebugger: () => createDebugger,
28
+ createExporter: () => createExporter,
29
+ createInspector: () => createInspector,
30
+ createTimeline: () => createTimeline
31
+ });
32
+ module.exports = __toCommonJS(debug_exports);
33
+
34
+ // src/debug/Inspector.ts
35
+ var Inspector = class {
36
+ store;
37
+ config;
38
+ constructor(store, config = {}) {
39
+ this.store = store;
40
+ this.config = {
41
+ includeEmbeddings: config.includeEmbeddings ?? false,
42
+ samplingRate: config.samplingRate ?? 1,
43
+ maxEntriesForAnalysis: config.maxEntriesForAnalysis ?? 1e4,
44
+ warningThresholds: {
45
+ lowImportance: config.warningThresholds?.lowImportance ?? 0.2,
46
+ highEntryCount: config.warningThresholds?.highEntryCount ?? 5e4,
47
+ oldAge: config.warningThresholds?.oldAge ?? 30 * 24 * 60 * 60 * 1e3,
48
+ // 30 days
49
+ ...config.warningThresholds
50
+ }
51
+ };
52
+ }
53
+ /**
54
+ * Get comprehensive memory statistics
55
+ */
56
+ async getStats() {
57
+ const { entries, total } = await this.store.query({
58
+ limit: this.config.maxEntriesForAnalysis
59
+ });
60
+ const now = Date.now();
61
+ let totalSize = 0;
62
+ let totalImportance = 0;
63
+ let totalAccessCount = 0;
64
+ let entriesWithEmbeddings = 0;
65
+ let expiredEntries = 0;
66
+ let oldest = null;
67
+ let newest = null;
68
+ const typeDistribution = {};
69
+ const namespaceDistribution = {};
70
+ for (const entry of entries) {
71
+ totalSize += entry.content.length + JSON.stringify(entry.metadata).length;
72
+ totalImportance += entry.importance;
73
+ totalAccessCount += entry.accessCount;
74
+ if (entry.embedding) entriesWithEmbeddings++;
75
+ if (entry.expiresAt && entry.expiresAt < now) expiredEntries++;
76
+ if (oldest === null || entry.timestamp < oldest) oldest = entry.timestamp;
77
+ if (newest === null || entry.timestamp > newest) newest = entry.timestamp;
78
+ typeDistribution[entry.type] = (typeDistribution[entry.type] ?? 0) + 1;
79
+ const namespace = String(entry.metadata.namespace ?? "default");
80
+ namespaceDistribution[namespace] = (namespaceDistribution[namespace] ?? 0) + 1;
81
+ }
82
+ return {
83
+ totalEntries: total,
84
+ totalSize,
85
+ avgContentLength: entries.length > 0 ? totalSize / entries.length : 0,
86
+ avgImportance: entries.length > 0 ? totalImportance / entries.length : 0,
87
+ avgAccessCount: entries.length > 0 ? totalAccessCount / entries.length : 0,
88
+ typeDistribution,
89
+ namespaceDistribution,
90
+ timeRange: oldest !== null ? { oldest, newest } : null,
91
+ entriesWithEmbeddings,
92
+ expiredEntries
93
+ };
94
+ }
95
+ /**
96
+ * Inspect a specific entry
97
+ */
98
+ async inspect(id) {
99
+ const entry = await this.store.get(id);
100
+ if (!entry) return null;
101
+ const now = Date.now();
102
+ const age = now - entry.timestamp;
103
+ const hoursOld = age / (60 * 60 * 1e3);
104
+ return {
105
+ entry,
106
+ analysis: {
107
+ contentLength: entry.content.length,
108
+ wordCount: entry.content.split(/\s+/).filter((w) => w.length > 0).length,
109
+ hasEmbedding: !!entry.embedding,
110
+ embeddingDimensions: entry.embedding?.length,
111
+ metadataKeys: Object.keys(entry.metadata),
112
+ age,
113
+ accessRate: hoursOld > 0 ? entry.accessCount / hoursOld : entry.accessCount,
114
+ isExpired: !!(entry.expiresAt && entry.expiresAt < now)
115
+ }
116
+ };
117
+ }
118
+ /**
119
+ * Get memory health report
120
+ */
121
+ async getHealthReport() {
122
+ const stats = await this.getStats();
123
+ const issues = [];
124
+ const recommendations = [];
125
+ if (stats.totalEntries > this.config.warningThresholds.highEntryCount) {
126
+ issues.push({
127
+ type: "warning",
128
+ message: `High entry count: ${stats.totalEntries} entries`,
129
+ suggestion: "Consider consolidating or archiving old memories"
130
+ });
131
+ recommendations.push("Run memory consolidation to reduce entry count");
132
+ }
133
+ if (stats.avgImportance < this.config.warningThresholds.lowImportance) {
134
+ issues.push({
135
+ type: "info",
136
+ message: `Low average importance: ${(stats.avgImportance * 100).toFixed(1)}%`,
137
+ suggestion: "Review importance scoring or prune low-importance entries"
138
+ });
139
+ }
140
+ if (stats.expiredEntries > 0) {
141
+ issues.push({
142
+ type: "warning",
143
+ message: `${stats.expiredEntries} expired entries found`,
144
+ affectedEntries: stats.expiredEntries,
145
+ suggestion: "Run cleanup to remove expired entries"
146
+ });
147
+ recommendations.push("Clean up expired entries to free storage");
148
+ }
149
+ const withoutEmbeddings = stats.totalEntries - stats.entriesWithEmbeddings;
150
+ if (withoutEmbeddings > stats.totalEntries * 0.3) {
151
+ issues.push({
152
+ type: "info",
153
+ message: `${withoutEmbeddings} entries without embeddings (${(withoutEmbeddings / stats.totalEntries * 100).toFixed(1)}%)`,
154
+ affectedEntries: withoutEmbeddings,
155
+ suggestion: "Generate embeddings for better semantic search"
156
+ });
157
+ }
158
+ if (stats.timeRange) {
159
+ const oldestAge = Date.now() - stats.timeRange.oldest;
160
+ if (oldestAge > this.config.warningThresholds.oldAge) {
161
+ issues.push({
162
+ type: "info",
163
+ message: `Oldest entry is ${Math.round(oldestAge / (24 * 60 * 60 * 1e3))} days old`,
164
+ suggestion: "Consider archiving or summarizing old memories"
165
+ });
166
+ }
167
+ }
168
+ const namespaceCount = Object.keys(stats.namespaceDistribution).length;
169
+ if (namespaceCount === 1 && stats.totalEntries > 1e3) {
170
+ recommendations.push("Consider using namespaces to organize memories");
171
+ }
172
+ let score = 100;
173
+ for (const issue of issues) {
174
+ if (issue.type === "error") score -= 20;
175
+ else if (issue.type === "warning") score -= 10;
176
+ else score -= 5;
177
+ }
178
+ score = Math.max(0, Math.min(100, score));
179
+ return {
180
+ score,
181
+ issues,
182
+ recommendations
183
+ };
184
+ }
185
+ /**
186
+ * Find duplicate entries
187
+ */
188
+ async findDuplicates(threshold = 0.95) {
189
+ const { entries } = await this.store.query({
190
+ limit: this.config.maxEntriesForAnalysis
191
+ });
192
+ const duplicates = [];
193
+ for (let i = 0; i < entries.length; i++) {
194
+ for (let j = i + 1; j < entries.length; j++) {
195
+ const similarity = this.calculateSimilarity(entries[i], entries[j]);
196
+ if (similarity >= threshold) {
197
+ duplicates.push([entries[i], entries[j]]);
198
+ }
199
+ }
200
+ }
201
+ return duplicates;
202
+ }
203
+ /**
204
+ * Find orphaned entries (no parent, but has parentId)
205
+ */
206
+ async findOrphans() {
207
+ const { entries } = await this.store.query({
208
+ limit: this.config.maxEntriesForAnalysis
209
+ });
210
+ const entryIds = new Set(entries.map((e) => e.id));
211
+ const orphans = [];
212
+ for (const entry of entries) {
213
+ if (entry.parentId && !entryIds.has(entry.parentId)) {
214
+ orphans.push(entry);
215
+ }
216
+ }
217
+ return orphans;
218
+ }
219
+ /**
220
+ * Find low-value entries
221
+ */
222
+ async findLowValueEntries(options) {
223
+ const { entries } = await this.store.query({
224
+ limit: this.config.maxEntriesForAnalysis
225
+ });
226
+ const now = Date.now();
227
+ const maxImportance = options?.maxImportance ?? 0.2;
228
+ const maxAccessCount = options?.maxAccessCount ?? 2;
229
+ const minAge = options?.minAge ?? 7 * 24 * 60 * 60 * 1e3;
230
+ return entries.filter((entry) => {
231
+ const age = now - entry.timestamp;
232
+ return entry.importance <= maxImportance && entry.accessCount <= maxAccessCount && age >= minAge;
233
+ });
234
+ }
235
+ /**
236
+ * Get entry distribution over time
237
+ */
238
+ async getTimeDistribution(bucketSize = "day") {
239
+ const { entries } = await this.store.query({
240
+ limit: this.config.maxEntriesForAnalysis
241
+ });
242
+ const distribution = /* @__PURE__ */ new Map();
243
+ for (const entry of entries) {
244
+ const date = new Date(entry.timestamp);
245
+ let key;
246
+ switch (bucketSize) {
247
+ case "hour":
248
+ key = `${date.toISOString().slice(0, 13)}:00`;
249
+ break;
250
+ case "day":
251
+ key = date.toISOString().slice(0, 10);
252
+ break;
253
+ case "week": {
254
+ const weekStart = new Date(date);
255
+ weekStart.setDate(date.getDate() - date.getDay());
256
+ key = `week-${weekStart.toISOString().slice(0, 10)}`;
257
+ break;
258
+ }
259
+ case "month":
260
+ key = date.toISOString().slice(0, 7);
261
+ break;
262
+ }
263
+ distribution.set(key, (distribution.get(key) ?? 0) + 1);
264
+ }
265
+ return distribution;
266
+ }
267
+ /**
268
+ * Calculate similarity between two entries
269
+ */
270
+ calculateSimilarity(a, b) {
271
+ if (a.embedding && b.embedding) {
272
+ return this.cosineSimilarity(a.embedding, b.embedding);
273
+ }
274
+ return this.textSimilarity(a.content, b.content);
275
+ }
276
+ /**
277
+ * Cosine similarity
278
+ */
279
+ cosineSimilarity(a, b) {
280
+ if (a.length !== b.length) return 0;
281
+ let dotProduct = 0;
282
+ let normA = 0;
283
+ let normB = 0;
284
+ for (let i = 0; i < a.length; i++) {
285
+ dotProduct += a[i] * b[i];
286
+ normA += a[i] * a[i];
287
+ normB += b[i] * b[i];
288
+ }
289
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
290
+ return magnitude === 0 ? 0 : dotProduct / magnitude;
291
+ }
292
+ /**
293
+ * Text similarity (Jaccard)
294
+ */
295
+ textSimilarity(a, b) {
296
+ const wordsA = new Set(a.toLowerCase().split(/\s+/));
297
+ const wordsB = new Set(b.toLowerCase().split(/\s+/));
298
+ const intersection = new Set([...wordsA].filter((x) => wordsB.has(x)));
299
+ const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
300
+ return intersection.size / union.size;
301
+ }
302
+ };
303
+ function createInspector(store, config) {
304
+ return new Inspector(store, config);
305
+ }
306
+
307
+ // src/debug/Timeline.ts
308
+ var Timeline = class {
309
+ store;
310
+ config;
311
+ events = [];
312
+ markers = [];
313
+ constructor(store, config = {}) {
314
+ this.store = store;
315
+ this.config = {
316
+ timeRange: config.timeRange ?? { start: 0, end: Date.now() },
317
+ groupBy: config.groupBy ?? "day",
318
+ showTypes: config.showTypes ?? true,
319
+ showNamespaces: config.showNamespaces ?? true,
320
+ maxEvents: config.maxEvents ?? 1e4,
321
+ autoTrack: config.autoTrack ?? true,
322
+ segmentSize: config.segmentSize ?? "day"
323
+ };
324
+ }
325
+ /**
326
+ * Record a timeline event
327
+ */
328
+ recordEvent(event) {
329
+ const fullEvent = {
330
+ ...event,
331
+ id: `event-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
332
+ };
333
+ this.events.push(fullEvent);
334
+ if (this.events.length > this.config.maxEvents) {
335
+ this.events = this.events.slice(-this.config.maxEvents);
336
+ }
337
+ }
338
+ /**
339
+ * Add a marker to the timeline
340
+ */
341
+ addMarker(marker) {
342
+ this.markers.push({
343
+ ...marker,
344
+ timestamp: marker.timestamp ?? Date.now()
345
+ });
346
+ }
347
+ /**
348
+ * Get timeline segments
349
+ */
350
+ async getSegments(startTime, endTime) {
351
+ const segments = [];
352
+ const segmentSize = this.getSegmentSizeMs();
353
+ const { entries } = await this.store.query({
354
+ startTime,
355
+ endTime,
356
+ limit: 1e4
357
+ });
358
+ const rangeEvents = this.events.filter(
359
+ (e) => e.timestamp >= startTime && e.timestamp <= endTime
360
+ );
361
+ let currentStart = startTime;
362
+ while (currentStart < endTime) {
363
+ const currentEnd = Math.min(currentStart + segmentSize, endTime);
364
+ const segmentEntries = entries.filter(
365
+ (e) => e.timestamp >= currentStart && e.timestamp < currentEnd
366
+ );
367
+ const segmentEvents = rangeEvents.filter(
368
+ (e) => e.timestamp >= currentStart && e.timestamp < currentEnd
369
+ );
370
+ if (segmentEntries.length > 0 || segmentEvents.length > 0) {
371
+ segments.push({
372
+ start: currentStart,
373
+ end: currentEnd,
374
+ entries: segmentEntries,
375
+ events: segmentEvents
376
+ });
377
+ }
378
+ currentStart = currentEnd;
379
+ }
380
+ return segments;
381
+ }
382
+ /**
383
+ * Get timeline for a specific entry
384
+ */
385
+ async getEntryTimeline(entryId) {
386
+ const entry = await this.store.get(entryId);
387
+ const entryEvents = this.events.filter((e) => e.entryId === entryId);
388
+ entryEvents.sort((a, b) => a.timestamp - b.timestamp);
389
+ const accessHistory = entryEvents.filter((e) => e.type === "access").map((e) => e.timestamp);
390
+ return {
391
+ entry,
392
+ events: entryEvents,
393
+ createdAt: entry?.createdAt ?? 0,
394
+ lastModified: entry?.updatedAt ?? 0,
395
+ accessHistory
396
+ };
397
+ }
398
+ /**
399
+ * Get activity heatmap data
400
+ */
401
+ async getActivityHeatmap(startTime, endTime, bucketSize = "hour") {
402
+ const heatmap = /* @__PURE__ */ new Map();
403
+ const { entries } = await this.store.query({
404
+ startTime,
405
+ endTime,
406
+ limit: 1e4
407
+ });
408
+ const rangeEvents = this.events.filter(
409
+ (e) => e.timestamp >= startTime && e.timestamp <= endTime
410
+ );
411
+ for (const entry of entries) {
412
+ const key = this.getBucketKey(entry.timestamp, bucketSize);
413
+ const existing = heatmap.get(key) ?? { entries: 0, events: 0 };
414
+ existing.entries++;
415
+ heatmap.set(key, existing);
416
+ }
417
+ for (const event of rangeEvents) {
418
+ const key = this.getBucketKey(event.timestamp, bucketSize);
419
+ const existing = heatmap.get(key) ?? { entries: 0, events: 0 };
420
+ existing.events++;
421
+ heatmap.set(key, existing);
422
+ }
423
+ return heatmap;
424
+ }
425
+ /**
426
+ * Get markers in time range
427
+ */
428
+ getMarkers(startTime, endTime) {
429
+ return this.markers.filter(
430
+ (m) => m.timestamp >= startTime && m.timestamp <= endTime
431
+ );
432
+ }
433
+ /**
434
+ * Get recent activity summary
435
+ */
436
+ getRecentActivity(windowMs = 24 * 60 * 60 * 1e3) {
437
+ const now = Date.now();
438
+ const startTime = now - windowMs;
439
+ const recentEvents = this.events.filter((e) => e.timestamp >= startTime);
440
+ const newEntries = recentEvents.filter((e) => e.type === "add").length;
441
+ const updatedEntries = recentEvents.filter(
442
+ (e) => e.type === "update"
443
+ ).length;
444
+ const deletedEntries = recentEvents.filter(
445
+ (e) => e.type === "delete"
446
+ ).length;
447
+ const totalAccesses = recentEvents.filter(
448
+ (e) => e.type === "access"
449
+ ).length;
450
+ const accessCounts = /* @__PURE__ */ new Map();
451
+ for (const event of recentEvents) {
452
+ if (event.type === "access") {
453
+ accessCounts.set(
454
+ event.entryId,
455
+ (accessCounts.get(event.entryId) ?? 0) + 1
456
+ );
457
+ }
458
+ }
459
+ const topAccessed = Array.from(accessCounts.entries()).map(([entryId, accessCount]) => ({ entryId, accessCount })).sort((a, b) => b.accessCount - a.accessCount).slice(0, 10);
460
+ return {
461
+ newEntries,
462
+ updatedEntries,
463
+ deletedEntries,
464
+ totalAccesses,
465
+ topAccessed
466
+ };
467
+ }
468
+ /**
469
+ * Get memory growth over time
470
+ */
471
+ async getGrowthChart(startTime, endTime, bucketSize = "day") {
472
+ const { entries } = await this.store.query({
473
+ startTime,
474
+ endTime,
475
+ limit: 1e5
476
+ });
477
+ entries.sort((a, b) => a.timestamp - b.timestamp);
478
+ const buckets = /* @__PURE__ */ new Map();
479
+ for (const entry of entries) {
480
+ const key = this.getBucketKey(entry.timestamp, bucketSize);
481
+ buckets.set(key, (buckets.get(key) ?? 0) + 1);
482
+ }
483
+ const sortedKeys = Array.from(buckets.keys()).sort();
484
+ let cumulative = 0;
485
+ const chart = [];
486
+ for (const key of sortedKeys) {
487
+ const newCount = buckets.get(key) ?? 0;
488
+ cumulative += newCount;
489
+ chart.push({
490
+ time: key,
491
+ cumulativeCount: cumulative,
492
+ newCount
493
+ });
494
+ }
495
+ return chart;
496
+ }
497
+ /**
498
+ * Find gaps in timeline (periods with no activity)
499
+ */
500
+ async findGaps(startTime, endTime, minGapSize = 24 * 60 * 60 * 1e3) {
501
+ const { entries } = await this.store.query({
502
+ startTime,
503
+ endTime,
504
+ limit: 1e4
505
+ });
506
+ if (entries.length < 2) return [];
507
+ const sorted = [...entries].sort((a, b) => a.timestamp - b.timestamp);
508
+ const gaps = [];
509
+ for (let i = 1; i < sorted.length; i++) {
510
+ const gap = sorted[i].timestamp - sorted[i - 1].timestamp;
511
+ if (gap >= minGapSize) {
512
+ gaps.push({
513
+ start: sorted[i - 1].timestamp,
514
+ end: sorted[i].timestamp,
515
+ durationMs: gap
516
+ });
517
+ }
518
+ }
519
+ return gaps;
520
+ }
521
+ /**
522
+ * Clear events
523
+ */
524
+ clearEvents() {
525
+ this.events = [];
526
+ }
527
+ /**
528
+ * Clear markers
529
+ */
530
+ clearMarkers() {
531
+ this.markers = [];
532
+ }
533
+ /**
534
+ * Export timeline data
535
+ */
536
+ exportData() {
537
+ return {
538
+ events: [...this.events],
539
+ markers: [...this.markers],
540
+ exportedAt: Date.now()
541
+ };
542
+ }
543
+ /**
544
+ * Import timeline data
545
+ */
546
+ importData(data) {
547
+ this.events.push(...data.events);
548
+ this.markers.push(...data.markers);
549
+ }
550
+ /**
551
+ * Get segment size in milliseconds
552
+ */
553
+ getSegmentSizeMs() {
554
+ switch (this.config.segmentSize) {
555
+ case "hour":
556
+ return 60 * 60 * 1e3;
557
+ case "day":
558
+ return 24 * 60 * 60 * 1e3;
559
+ case "week":
560
+ return 7 * 24 * 60 * 60 * 1e3;
561
+ default:
562
+ return 24 * 60 * 60 * 1e3;
563
+ }
564
+ }
565
+ /**
566
+ * Get bucket key for timestamp
567
+ */
568
+ getBucketKey(timestamp, bucketSize) {
569
+ const date = new Date(timestamp);
570
+ switch (bucketSize) {
571
+ case "hour":
572
+ return `${date.toISOString().slice(0, 13)}:00`;
573
+ case "day":
574
+ return date.toISOString().slice(0, 10);
575
+ case "week": {
576
+ const weekStart = new Date(date);
577
+ weekStart.setDate(date.getDate() - date.getDay());
578
+ return `week-${weekStart.toISOString().slice(0, 10)}`;
579
+ }
580
+ default:
581
+ return date.toISOString().slice(0, 10);
582
+ }
583
+ }
584
+ };
585
+ function createTimeline(store, config) {
586
+ return new Timeline(store, config);
587
+ }
588
+
589
+ // src/debug/Debugger.ts
590
+ var import_eventemitter3 = require("eventemitter3");
591
+ var Debugger = class extends import_eventemitter3.EventEmitter {
592
+ store;
593
+ traces = [];
594
+ breakpoints = /* @__PURE__ */ new Map();
595
+ enabled = true;
596
+ maxTraces = 1e3;
597
+ constructor(store) {
598
+ super();
599
+ this.store = store;
600
+ }
601
+ /**
602
+ * Enable debugging
603
+ */
604
+ enable() {
605
+ this.enabled = true;
606
+ }
607
+ /**
608
+ * Disable debugging
609
+ */
610
+ disable() {
611
+ this.enabled = false;
612
+ }
613
+ /**
614
+ * Check if debugging is enabled
615
+ */
616
+ isEnabled() {
617
+ return this.enabled;
618
+ }
619
+ /**
620
+ * Trace an operation
621
+ */
622
+ trace(operation, input, output, durationMs, metadata) {
623
+ if (!this.enabled) return;
624
+ const trace = {
625
+ id: `trace-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
626
+ operation,
627
+ timestamp: Date.now(),
628
+ duration: durationMs,
629
+ input,
630
+ output,
631
+ metadata
632
+ };
633
+ this.traces.push(trace);
634
+ if (this.traces.length > this.maxTraces) {
635
+ this.traces = this.traces.slice(-this.maxTraces);
636
+ }
637
+ this.emit("trace", trace);
638
+ }
639
+ /**
640
+ * Wrap a function with tracing
641
+ */
642
+ wrapWithTrace(operation, fn) {
643
+ return (async (...args) => {
644
+ const startTime = Date.now();
645
+ try {
646
+ const result = await fn(...args);
647
+ this.trace(operation, args, result, Date.now() - startTime);
648
+ return result;
649
+ } catch (error) {
650
+ this.trace(
651
+ operation,
652
+ args,
653
+ { error: String(error) },
654
+ Date.now() - startTime,
655
+ {
656
+ error: true
657
+ }
658
+ );
659
+ throw error;
660
+ }
661
+ });
662
+ }
663
+ /**
664
+ * Add a breakpoint
665
+ */
666
+ addBreakpoint(condition, id) {
667
+ const breakpointId = id ?? `bp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
668
+ this.breakpoints.set(breakpointId, {
669
+ id: breakpointId,
670
+ condition,
671
+ enabled: true,
672
+ hitCount: 0
673
+ });
674
+ return breakpointId;
675
+ }
676
+ /**
677
+ * Remove a breakpoint
678
+ */
679
+ removeBreakpoint(id) {
680
+ return this.breakpoints.delete(id);
681
+ }
682
+ /**
683
+ * Enable/disable a breakpoint
684
+ */
685
+ toggleBreakpoint(id, enabled) {
686
+ const bp = this.breakpoints.get(id);
687
+ if (!bp) return false;
688
+ bp.enabled = enabled;
689
+ return true;
690
+ }
691
+ /**
692
+ * Check breakpoints for an entry/operation
693
+ */
694
+ checkBreakpoints(entry, operation) {
695
+ if (!this.enabled) return;
696
+ for (const bp of this.breakpoints.values()) {
697
+ if (!bp.enabled) continue;
698
+ try {
699
+ if (bp.condition(entry, operation)) {
700
+ bp.hitCount++;
701
+ this.emit("breakpointHit", bp, entry, operation);
702
+ }
703
+ } catch (error) {
704
+ this.emit("warning", `Breakpoint ${bp.id} condition error`, error);
705
+ }
706
+ }
707
+ }
708
+ /**
709
+ * Debug a retrieval operation
710
+ */
711
+ async debugRetrieval(query, embedFn, options) {
712
+ const timing = { total: 0 };
713
+ const filteringSteps = [];
714
+ const scoringDetails = [];
715
+ const totalStart = Date.now();
716
+ const embeddingStart = Date.now();
717
+ const embedding = await embedFn(query);
718
+ timing.embedding = Date.now() - embeddingStart;
719
+ const searchStart = Date.now();
720
+ const searchResults = await this.store.search(embedding, {
721
+ topK: options?.candidateMultiplier ? (options.limit ?? 10) * options.candidateMultiplier : 100,
722
+ minScore: 0
723
+ // Get all for debugging
724
+ });
725
+ timing.search = Date.now() - searchStart;
726
+ filteringSteps.push({
727
+ name: "initial-search",
728
+ inputCount: 0,
729
+ outputCount: searchResults.length,
730
+ durationMs: timing.search
731
+ });
732
+ let filtered = searchResults;
733
+ const filterStart = Date.now();
734
+ if (options?.types && options.types.length > 0) {
735
+ const beforeCount = filtered.length;
736
+ filtered = filtered.filter((r) => options.types.includes(r.entry.type));
737
+ filteringSteps.push({
738
+ name: "type-filter",
739
+ inputCount: beforeCount,
740
+ outputCount: filtered.length,
741
+ durationMs: 0
742
+ });
743
+ }
744
+ if (options?.namespace) {
745
+ const beforeCount = filtered.length;
746
+ filtered = filtered.filter(
747
+ (r) => r.entry.metadata.namespace === options.namespace
748
+ );
749
+ filteringSteps.push({
750
+ name: "namespace-filter",
751
+ inputCount: beforeCount,
752
+ outputCount: filtered.length,
753
+ durationMs: 0
754
+ });
755
+ }
756
+ if (options?.minScore !== void 0) {
757
+ const beforeCount = filtered.length;
758
+ filtered = filtered.filter((r) => r.score >= options.minScore);
759
+ filteringSteps.push({
760
+ name: "score-filter",
761
+ inputCount: beforeCount,
762
+ outputCount: filtered.length,
763
+ durationMs: 0
764
+ });
765
+ }
766
+ timing.filtering = Date.now() - filterStart;
767
+ for (const result of filtered.slice(0, options?.limit ?? 10)) {
768
+ scoringDetails.push({
769
+ entryId: result.entry.id,
770
+ scores: {
771
+ similarity: result.score,
772
+ importance: result.entry.importance,
773
+ recency: 1 / (1 + (Date.now() - result.entry.timestamp) / (24 * 60 * 60 * 1e3))
774
+ },
775
+ finalScore: result.score
776
+ });
777
+ }
778
+ timing.total = Date.now() - totalStart;
779
+ return {
780
+ query,
781
+ totalCandidates: searchResults.length,
782
+ returnedCount: Math.min(filtered.length, options?.limit ?? 10),
783
+ strategyUsed: "semantic",
784
+ filteringSteps,
785
+ scoringDetails,
786
+ timing
787
+ };
788
+ }
789
+ /**
790
+ * Get recent traces
791
+ */
792
+ getTraces(options) {
793
+ let traces = [...this.traces];
794
+ if (options?.operation) {
795
+ traces = traces.filter((t) => t.operation === options.operation);
796
+ }
797
+ if (options?.startTime) {
798
+ traces = traces.filter((t) => t.timestamp >= options.startTime);
799
+ }
800
+ if (options?.endTime) {
801
+ traces = traces.filter((t) => t.timestamp <= options.endTime);
802
+ }
803
+ traces.sort((a, b) => b.timestamp - a.timestamp);
804
+ return options?.limit ? traces.slice(0, options.limit) : traces;
805
+ }
806
+ /**
807
+ * Get operation statistics
808
+ */
809
+ getOperationStats() {
810
+ const stats = /* @__PURE__ */ new Map();
811
+ for (const trace of this.traces) {
812
+ const existing = stats.get(trace.operation) ?? {
813
+ count: 0,
814
+ totalDuration: 0,
815
+ maxDuration: 0,
816
+ minDuration: Infinity
817
+ };
818
+ existing.count++;
819
+ existing.totalDuration += trace.duration;
820
+ existing.maxDuration = Math.max(existing.maxDuration, trace.duration);
821
+ existing.minDuration = Math.min(existing.minDuration, trace.duration);
822
+ stats.set(trace.operation, existing);
823
+ }
824
+ const result = /* @__PURE__ */ new Map();
825
+ for (const [op, data] of stats) {
826
+ result.set(op, {
827
+ count: data.count,
828
+ avgDuration: data.totalDuration / data.count,
829
+ maxDuration: data.maxDuration,
830
+ minDuration: data.minDuration === Infinity ? 0 : data.minDuration
831
+ });
832
+ }
833
+ return result;
834
+ }
835
+ /**
836
+ * Get all breakpoints
837
+ */
838
+ getBreakpoints() {
839
+ return Array.from(this.breakpoints.values());
840
+ }
841
+ /**
842
+ * Clear traces
843
+ */
844
+ clearTraces() {
845
+ this.traces = [];
846
+ }
847
+ /**
848
+ * Clear all breakpoints
849
+ */
850
+ clearBreakpoints() {
851
+ this.breakpoints.clear();
852
+ }
853
+ /**
854
+ * Create a snapshot of current debug state
855
+ */
856
+ createSnapshot() {
857
+ return {
858
+ traces: [...this.traces],
859
+ breakpoints: this.getBreakpoints().map((bp) => ({
860
+ id: bp.id,
861
+ enabled: bp.enabled,
862
+ hitCount: bp.hitCount
863
+ })),
864
+ stats: this.getOperationStats(),
865
+ timestamp: Date.now()
866
+ };
867
+ }
868
+ };
869
+ function createDebugger(store) {
870
+ return new Debugger(store);
871
+ }
872
+
873
+ // src/debug/Exporter.ts
874
+ var Exporter = class {
875
+ store;
876
+ constructor(store) {
877
+ this.store = store;
878
+ }
879
+ /**
880
+ * Export memories to string
881
+ */
882
+ async export(options = {}) {
883
+ const format = options.format ?? "json";
884
+ const { entries } = await this.store.query({
885
+ namespace: options.namespace,
886
+ types: options.types,
887
+ startTime: options.startTime,
888
+ endTime: options.endTime,
889
+ limit: 1e5
890
+ // High limit for export
891
+ });
892
+ let filtered = entries;
893
+ if (options.ids && options.ids.length > 0) {
894
+ const idSet = new Set(options.ids);
895
+ filtered = entries.filter((e) => idSet.has(e.id));
896
+ }
897
+ if (!options.includeEmbeddings) {
898
+ filtered = filtered.map((e) => ({ ...e, embedding: void 0 }));
899
+ }
900
+ let data;
901
+ switch (format) {
902
+ case "json":
903
+ data = this.toJSON(filtered, options.pretty);
904
+ break;
905
+ case "jsonl":
906
+ data = this.toJSONL(filtered);
907
+ break;
908
+ case "csv":
909
+ data = this.toCSV(filtered);
910
+ break;
911
+ default:
912
+ data = this.toJSON(filtered, options.pretty);
913
+ }
914
+ return {
915
+ data,
916
+ format,
917
+ entryCount: filtered.length,
918
+ exportedAt: Date.now(),
919
+ checksum: this.calculateChecksum(data)
920
+ };
921
+ }
922
+ /**
923
+ * Export to JSON file content
924
+ */
925
+ toJSON(entries, pretty = false) {
926
+ const exportData = {
927
+ version: "1.0",
928
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
929
+ entryCount: entries.length,
930
+ entries
931
+ };
932
+ return pretty ? JSON.stringify(exportData, null, 2) : JSON.stringify(exportData);
933
+ }
934
+ /**
935
+ * Export to JSON Lines format
936
+ */
937
+ toJSONL(entries) {
938
+ return entries.map((e) => JSON.stringify(e)).join("\n");
939
+ }
940
+ /**
941
+ * Export to CSV format
942
+ */
943
+ toCSV(entries) {
944
+ const headers = [
945
+ "id",
946
+ "content",
947
+ "type",
948
+ "importance",
949
+ "timestamp",
950
+ "accessCount",
951
+ "createdAt",
952
+ "updatedAt",
953
+ "namespace",
954
+ "userId",
955
+ "agentId"
956
+ ];
957
+ const rows = entries.map((e) => {
958
+ return [
959
+ this.escapeCSV(e.id),
960
+ this.escapeCSV(e.content),
961
+ e.type,
962
+ e.importance.toString(),
963
+ e.timestamp.toString(),
964
+ e.accessCount.toString(),
965
+ e.createdAt.toString(),
966
+ e.updatedAt.toString(),
967
+ this.escapeCSV(String(e.metadata.namespace ?? "")),
968
+ this.escapeCSV(String(e.metadata.userId ?? "")),
969
+ this.escapeCSV(String(e.metadata.agentId ?? ""))
970
+ ].join(",");
971
+ });
972
+ return [headers.join(","), ...rows].join("\n");
973
+ }
974
+ /**
975
+ * Escape CSV value
976
+ */
977
+ escapeCSV(value) {
978
+ if (value.includes(",") || value.includes('"') || value.includes("\n")) {
979
+ return `"${value.replace(/"/g, '""')}"`;
980
+ }
981
+ return value;
982
+ }
983
+ /**
984
+ * Import memories from string
985
+ */
986
+ async import(data, format = "json", options) {
987
+ let entries;
988
+ switch (format) {
989
+ case "json":
990
+ entries = this.fromJSON(data);
991
+ break;
992
+ case "jsonl":
993
+ entries = this.fromJSONL(data);
994
+ break;
995
+ case "csv":
996
+ entries = this.fromCSV(data);
997
+ break;
998
+ default:
999
+ entries = this.fromJSON(data);
1000
+ }
1001
+ if (options?.validateOnly) {
1002
+ return {
1003
+ imported: 0,
1004
+ skipped: 0,
1005
+ errors: []
1006
+ };
1007
+ }
1008
+ let imported = 0;
1009
+ let skipped = 0;
1010
+ const errors = [];
1011
+ for (const entry of entries) {
1012
+ try {
1013
+ if (options?.namespace) {
1014
+ entry.metadata.namespace = options.namespace;
1015
+ }
1016
+ const existing = await this.store.get(entry.id);
1017
+ if (existing && !options?.overwrite) {
1018
+ skipped++;
1019
+ continue;
1020
+ }
1021
+ if (!this.validateEntry(entry)) {
1022
+ errors.push({ entry, error: "Invalid entry format" });
1023
+ continue;
1024
+ }
1025
+ if (existing) {
1026
+ await this.store.update(entry.id, entry);
1027
+ } else {
1028
+ await this.store.add(entry);
1029
+ }
1030
+ imported++;
1031
+ } catch (error) {
1032
+ errors.push({ entry, error: String(error) });
1033
+ }
1034
+ }
1035
+ return {
1036
+ imported,
1037
+ skipped,
1038
+ errors
1039
+ };
1040
+ }
1041
+ /**
1042
+ * Parse JSON export
1043
+ */
1044
+ fromJSON(data) {
1045
+ const parsed = JSON.parse(data);
1046
+ if (Array.isArray(parsed)) {
1047
+ return parsed;
1048
+ }
1049
+ if (parsed.entries && Array.isArray(parsed.entries)) {
1050
+ return parsed.entries;
1051
+ }
1052
+ throw new Error("Invalid JSON format");
1053
+ }
1054
+ /**
1055
+ * Parse JSONL export
1056
+ */
1057
+ fromJSONL(data) {
1058
+ return data.split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
1059
+ }
1060
+ /**
1061
+ * Parse CSV export
1062
+ */
1063
+ fromCSV(data) {
1064
+ const lines = data.split("\n");
1065
+ if (lines.length < 2) return [];
1066
+ const headers = this.parseCSVLine(lines[0]);
1067
+ const entries = [];
1068
+ for (let i = 1; i < lines.length; i++) {
1069
+ if (!lines[i].trim()) continue;
1070
+ const values = this.parseCSVLine(lines[i]);
1071
+ const obj = {};
1072
+ headers.forEach((header, index) => {
1073
+ obj[header] = values[index];
1074
+ });
1075
+ const entry = {
1076
+ id: String(obj.id),
1077
+ content: String(obj.content),
1078
+ type: obj.type,
1079
+ importance: parseFloat(String(obj.importance)) || 0.5,
1080
+ metadata: {
1081
+ source: "explicit",
1082
+ confidence: 1,
1083
+ namespace: String(obj.namespace || "default"),
1084
+ userId: obj.userId ? String(obj.userId) : void 0,
1085
+ agentId: obj.agentId ? String(obj.agentId) : void 0
1086
+ },
1087
+ timestamp: parseInt(String(obj.timestamp)) || Date.now(),
1088
+ accessCount: parseInt(String(obj.accessCount)) || 0,
1089
+ createdAt: parseInt(String(obj.createdAt)) || Date.now(),
1090
+ updatedAt: parseInt(String(obj.updatedAt)) || Date.now()
1091
+ };
1092
+ entries.push(entry);
1093
+ }
1094
+ return entries;
1095
+ }
1096
+ /**
1097
+ * Parse a CSV line
1098
+ */
1099
+ parseCSVLine(line) {
1100
+ const result = [];
1101
+ let current = "";
1102
+ let inQuotes = false;
1103
+ for (let i = 0; i < line.length; i++) {
1104
+ const char = line[i];
1105
+ if (char === '"') {
1106
+ if (inQuotes && line[i + 1] === '"') {
1107
+ current += '"';
1108
+ i++;
1109
+ } else {
1110
+ inQuotes = !inQuotes;
1111
+ }
1112
+ } else if (char === "," && !inQuotes) {
1113
+ result.push(current);
1114
+ current = "";
1115
+ } else {
1116
+ current += char;
1117
+ }
1118
+ }
1119
+ result.push(current);
1120
+ return result;
1121
+ }
1122
+ /**
1123
+ * Validate entry
1124
+ */
1125
+ validateEntry(entry) {
1126
+ if (!entry.id || typeof entry.id !== "string") return false;
1127
+ if (!entry.content || typeof entry.content !== "string") return false;
1128
+ if (!entry.type) return false;
1129
+ if (typeof entry.importance !== "number") return false;
1130
+ if (typeof entry.timestamp !== "number") return false;
1131
+ return true;
1132
+ }
1133
+ /**
1134
+ * Calculate simple checksum
1135
+ */
1136
+ calculateChecksum(data) {
1137
+ let hash = 0;
1138
+ for (let i = 0; i < data.length; i++) {
1139
+ const char = data.charCodeAt(i);
1140
+ hash = (hash << 5) - hash + char;
1141
+ hash = hash & hash;
1142
+ }
1143
+ return Math.abs(hash).toString(16);
1144
+ }
1145
+ /**
1146
+ * Create backup
1147
+ */
1148
+ async createBackup(name) {
1149
+ const data = await this.export({
1150
+ format: "json",
1151
+ includeEmbeddings: true,
1152
+ pretty: false
1153
+ });
1154
+ return {
1155
+ name: name ?? `backup-${Date.now()}`,
1156
+ data,
1157
+ createdAt: Date.now()
1158
+ };
1159
+ }
1160
+ /**
1161
+ * Restore from backup
1162
+ */
1163
+ async restoreBackup(backup, options) {
1164
+ if (options?.clearExisting) {
1165
+ await this.store.clear();
1166
+ }
1167
+ return this.import(backup.data.data, backup.data.format, {
1168
+ overwrite: true
1169
+ });
1170
+ }
1171
+ /**
1172
+ * Get export size estimate
1173
+ */
1174
+ async estimateExportSize(options) {
1175
+ const { entries, total } = await this.store.query({
1176
+ namespace: options?.namespace,
1177
+ types: options?.types,
1178
+ limit: 100
1179
+ // Sample
1180
+ });
1181
+ if (entries.length === 0) {
1182
+ return {
1183
+ entryCount: total,
1184
+ estimatedSizeBytes: 0
1185
+ };
1186
+ }
1187
+ let totalSize = 0;
1188
+ let totalSizeWithEmbeddings = 0;
1189
+ for (const entry of entries) {
1190
+ const withoutEmbed = {
1191
+ ...entry,
1192
+ embedding: void 0
1193
+ };
1194
+ totalSize += JSON.stringify(withoutEmbed).length;
1195
+ totalSizeWithEmbeddings += JSON.stringify(entry).length;
1196
+ }
1197
+ const avgSize = totalSize / entries.length;
1198
+ const avgSizeWithEmbed = totalSizeWithEmbeddings / entries.length;
1199
+ return {
1200
+ entryCount: total,
1201
+ estimatedSizeBytes: Math.round(avgSize * total),
1202
+ withEmbeddingsBytes: Math.round(avgSizeWithEmbed * total)
1203
+ };
1204
+ }
1205
+ /**
1206
+ * Diff two exports
1207
+ */
1208
+ diffExports(export1, export2) {
1209
+ const entries1 = this.fromJSON(export1.data);
1210
+ const entries2 = this.fromJSON(export2.data);
1211
+ const map1 = new Map(entries1.map((e) => [e.id, e]));
1212
+ const map2 = new Map(entries2.map((e) => [e.id, e]));
1213
+ const added = [];
1214
+ const removed = [];
1215
+ const modified = [];
1216
+ const unchanged = [];
1217
+ for (const [id, entry2] of map2) {
1218
+ const entry1 = map1.get(id);
1219
+ if (!entry1) {
1220
+ added.push(id);
1221
+ } else if (JSON.stringify(entry1) !== JSON.stringify(entry2)) {
1222
+ modified.push(id);
1223
+ } else {
1224
+ unchanged.push(id);
1225
+ }
1226
+ }
1227
+ for (const id of map1.keys()) {
1228
+ if (!map2.has(id)) {
1229
+ removed.push(id);
1230
+ }
1231
+ }
1232
+ return { added, removed, modified, unchanged };
1233
+ }
1234
+ };
1235
+ function createExporter(store) {
1236
+ return new Exporter(store);
1237
+ }
1238
+ // Annotate the CommonJS export names for ESM import in node:
1239
+ 0 && (module.exports = {
1240
+ Debugger,
1241
+ Exporter,
1242
+ Inspector,
1243
+ Timeline,
1244
+ createDebugger,
1245
+ createExporter,
1246
+ createInspector,
1247
+ createTimeline
1248
+ });