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/README.md +57 -27
- package/openclaw.plugin.json +24 -24
- package/package.json +2 -2
- package/src/chunking.ts +0 -267
- package/src/config.ts +45 -57
- package/src/dedupe.ts +4 -4
- package/src/extract.ts +10 -2
- package/src/index.ts +681 -163
- package/src/mem0-client.ts +62 -5
- package/src/state.ts +55 -28
- package/src/types.ts +34 -52
- package/src/bootstrap.ts +0 -82
- package/src/reconcile.ts +0 -278
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
|
-
|
|
75
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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
|
|
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:
|
|
463
|
+
messages: candidatesInput,
|
|
456
464
|
});
|
|
457
465
|
const mlExtracted = applyMlExtractionResult(mlExtractedRaw, params.cfg.capture.maxItemsPerRun);
|
|
458
466
|
params.log.debug("memory_braid.capture.ml", {
|