memory-braid 0.3.7 → 0.4.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.
package/src/config.ts CHANGED
@@ -21,6 +21,7 @@ export type MemoryBraidConfig = {
21
21
  capture: {
22
22
  enabled: boolean;
23
23
  mode: "local" | "hybrid" | "ml";
24
+ includeAssistant: boolean;
24
25
  maxItemsPerRun: number;
25
26
  ml: {
26
27
  provider?: "openai" | "anthropic" | "gemini";
@@ -39,21 +40,6 @@ export type MemoryBraidConfig = {
39
40
  warmupText: string;
40
41
  };
41
42
  };
42
- bootstrap: {
43
- enabled: boolean;
44
- startupMode: "async";
45
- includeMarkdown: boolean;
46
- includeSessions: boolean;
47
- sessionLookbackDays: number;
48
- batchSize: number;
49
- concurrency: number;
50
- };
51
- reconcile: {
52
- enabled: boolean;
53
- intervalMinutes: number;
54
- batchSize: number;
55
- deleteStale: boolean;
56
- };
57
43
  dedupe: {
58
44
  lexical: {
59
45
  minJaccard: number;
@@ -63,6 +49,15 @@ export type MemoryBraidConfig = {
63
49
  minScore: number;
64
50
  };
65
51
  };
52
+ timeDecay: {
53
+ enabled: boolean;
54
+ };
55
+ lifecycle: {
56
+ enabled: boolean;
57
+ captureTtlDays: number;
58
+ cleanupIntervalMinutes: number;
59
+ reinforceOnRecall: boolean;
60
+ };
66
61
  debug: {
67
62
  enabled: boolean;
68
63
  includePayloads: boolean;
@@ -94,6 +89,7 @@ const DEFAULTS: MemoryBraidConfig = {
94
89
  capture: {
95
90
  enabled: true,
96
91
  mode: "local",
92
+ includeAssistant: false,
97
93
  maxItemsPerRun: 6,
98
94
  ml: {
99
95
  provider: undefined,
@@ -112,21 +108,6 @@ const DEFAULTS: MemoryBraidConfig = {
112
108
  warmupText: "John works at Acme in Berlin.",
113
109
  },
114
110
  },
115
- bootstrap: {
116
- enabled: true,
117
- startupMode: "async",
118
- includeMarkdown: true,
119
- includeSessions: true,
120
- sessionLookbackDays: 90,
121
- batchSize: 50,
122
- concurrency: 3,
123
- },
124
- reconcile: {
125
- enabled: true,
126
- intervalMinutes: 30,
127
- batchSize: 100,
128
- deleteStale: true,
129
- },
130
111
  dedupe: {
131
112
  lexical: {
132
113
  minJaccard: 0.3,
@@ -136,6 +117,15 @@ const DEFAULTS: MemoryBraidConfig = {
136
117
  minScore: 0.92,
137
118
  },
138
119
  },
120
+ timeDecay: {
121
+ enabled: false,
122
+ },
123
+ lifecycle: {
124
+ enabled: false,
125
+ captureTtlDays: 90,
126
+ cleanupIntervalMinutes: 360,
127
+ reinforceOnRecall: true,
128
+ },
139
129
  debug: {
140
130
  enabled: false,
141
131
  includePayloads: false,
@@ -181,11 +171,11 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
181
171
  const entityExtraction = asRecord(root.entityExtraction);
182
172
  const entityStartup = asRecord(entityExtraction.startup);
183
173
  const ml = asRecord(capture.ml);
184
- const bootstrap = asRecord(root.bootstrap);
185
- const reconcile = asRecord(root.reconcile);
186
174
  const dedupe = asRecord(root.dedupe);
187
175
  const lexical = asRecord(dedupe.lexical);
188
176
  const semantic = asRecord(dedupe.semantic);
177
+ const timeDecay = asRecord(root.timeDecay);
178
+ const lifecycle = asRecord(root.lifecycle);
189
179
  const debug = asRecord(root.debug);
190
180
 
191
181
  const mode = mem0.mode === "oss" ? "oss" : "cloud";
@@ -218,6 +208,7 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
218
208
  capture: {
219
209
  enabled: asBoolean(capture.enabled, DEFAULTS.capture.enabled),
220
210
  mode: captureMode,
211
+ includeAssistant: asBoolean(capture.includeAssistant, DEFAULTS.capture.includeAssistant),
221
212
  maxItemsPerRun: asInt(capture.maxItemsPerRun, DEFAULTS.capture.maxItemsPerRun, 1, 50),
222
213
  ml: {
223
214
  provider:
@@ -251,31 +242,6 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
251
242
  asString(entityStartup.warmupText) ?? DEFAULTS.entityExtraction.startup.warmupText,
252
243
  },
253
244
  },
254
- bootstrap: {
255
- enabled: asBoolean(bootstrap.enabled, DEFAULTS.bootstrap.enabled),
256
- startupMode: "async",
257
- includeMarkdown: asBoolean(bootstrap.includeMarkdown, DEFAULTS.bootstrap.includeMarkdown),
258
- includeSessions: asBoolean(bootstrap.includeSessions, DEFAULTS.bootstrap.includeSessions),
259
- sessionLookbackDays: asInt(
260
- bootstrap.sessionLookbackDays,
261
- DEFAULTS.bootstrap.sessionLookbackDays,
262
- 1,
263
- 3650,
264
- ),
265
- batchSize: asInt(bootstrap.batchSize, DEFAULTS.bootstrap.batchSize, 1, 1000),
266
- concurrency: asInt(bootstrap.concurrency, DEFAULTS.bootstrap.concurrency, 1, 16),
267
- },
268
- reconcile: {
269
- enabled: asBoolean(reconcile.enabled, DEFAULTS.reconcile.enabled),
270
- intervalMinutes: asInt(
271
- reconcile.intervalMinutes,
272
- DEFAULTS.reconcile.intervalMinutes,
273
- 1,
274
- 1440,
275
- ),
276
- batchSize: asInt(reconcile.batchSize, DEFAULTS.reconcile.batchSize, 1, 5000),
277
- deleteStale: asBoolean(reconcile.deleteStale, DEFAULTS.reconcile.deleteStale),
278
- },
279
245
  dedupe: {
280
246
  lexical: {
281
247
  minJaccard: asNumber(lexical.minJaccard, DEFAULTS.dedupe.lexical.minJaccard, 0, 1),
@@ -285,6 +251,28 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
285
251
  minScore: asNumber(semantic.minScore, DEFAULTS.dedupe.semantic.minScore, 0, 1),
286
252
  },
287
253
  },
254
+ timeDecay: {
255
+ enabled: asBoolean(timeDecay.enabled, DEFAULTS.timeDecay.enabled),
256
+ },
257
+ lifecycle: {
258
+ enabled: asBoolean(lifecycle.enabled, DEFAULTS.lifecycle.enabled),
259
+ captureTtlDays: asInt(
260
+ lifecycle.captureTtlDays,
261
+ DEFAULTS.lifecycle.captureTtlDays,
262
+ 1,
263
+ 3650,
264
+ ),
265
+ cleanupIntervalMinutes: asInt(
266
+ lifecycle.cleanupIntervalMinutes,
267
+ DEFAULTS.lifecycle.cleanupIntervalMinutes,
268
+ 1,
269
+ 10080,
270
+ ),
271
+ reinforceOnRecall: asBoolean(
272
+ lifecycle.reinforceOnRecall,
273
+ DEFAULTS.lifecycle.reinforceOnRecall,
274
+ ),
275
+ },
288
276
  debug: {
289
277
  enabled: asBoolean(debug.enabled, DEFAULTS.debug.enabled),
290
278
  includePayloads: asBoolean(debug.includePayloads, DEFAULTS.debug.includePayloads),
package/src/dedupe.ts CHANGED
@@ -71,14 +71,14 @@ export async function stagedDedupe(
71
71
  }
72
72
 
73
73
  if (!options.semanticCompare) {
74
- duplicate = true;
75
- break;
74
+ // Keep candidate when semantic comparison is unavailable.
75
+ continue;
76
76
  }
77
77
 
78
78
  const semantic = await options.semanticCompare(candidate, chosen);
79
79
  if (typeof semantic !== "number") {
80
- duplicate = true;
81
- break;
80
+ // Keep candidate when semantic score is unavailable.
81
+ continue;
82
82
  }
83
83
  if (semantic >= options.semanticMinScore) {
84
84
  duplicate = true;
package/src/extract.ts CHANGED
@@ -392,13 +392,21 @@ export async function extractCandidates(params: {
392
392
  runId?: string;
393
393
  }): Promise<ExtractedCandidate[]> {
394
394
  const normalized = normalizeMessages(params.messages);
395
- const heuristic = pickHeuristicCandidates(normalized, params.cfg.capture.maxItemsPerRun);
395
+ const captureFromAssistant = params.cfg.capture.includeAssistant;
396
+ const candidatesInput = normalized.filter((message) =>
397
+ captureFromAssistant
398
+ ? message.role === "user" || message.role === "assistant"
399
+ : message.role === "user",
400
+ );
401
+ const heuristic = pickHeuristicCandidates(candidatesInput, params.cfg.capture.maxItemsPerRun);
396
402
 
397
403
  params.log.debug("memory_braid.capture.extract", {
398
404
  runId: params.runId,
399
405
  mode: params.cfg.capture.mode,
406
+ includeAssistant: captureFromAssistant,
400
407
  maxItemsPerRun: params.cfg.capture.maxItemsPerRun,
401
408
  totalMessages: normalized.length,
409
+ eligibleMessages: candidatesInput.length,
402
410
  heuristicCandidates: heuristic.length,
403
411
  });
404
412
 
@@ -452,7 +460,7 @@ export async function extractCandidates(params: {
452
460
  model: params.cfg.capture.ml.model,
453
461
  timeoutMs: params.cfg.capture.ml.timeoutMs,
454
462
  maxItems: params.cfg.capture.maxItemsPerRun,
455
- messages: normalized,
463
+ messages: candidatesInput,
456
464
  });
457
465
  const mlExtracted = applyMlExtractionResult(mlExtractedRaw, params.cfg.capture.maxItemsPerRun);
458
466
  params.log.debug("memory_braid.capture.ml", {