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