memory-braid 0.4.7 → 0.6.0

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
@@ -11,6 +11,16 @@ export type MemoryBraidConfig = {
11
11
  recall: {
12
12
  maxResults: number;
13
13
  injectTopK: number;
14
+ user: {
15
+ enabled: boolean;
16
+ injectTopK: number;
17
+ };
18
+ agent: {
19
+ enabled: boolean;
20
+ injectTopK: number;
21
+ minScore: number;
22
+ onlyPlanning: boolean;
23
+ };
14
24
  merge: {
15
25
  strategy: "rrf";
16
26
  rrfK: number;
@@ -23,6 +33,16 @@ export type MemoryBraidConfig = {
23
33
  mode: "local" | "hybrid" | "ml";
24
34
  includeAssistant: boolean;
25
35
  maxItemsPerRun: number;
36
+ assistant: {
37
+ enabled: boolean;
38
+ autoCapture: boolean;
39
+ explicitTool: boolean;
40
+ maxItemsPerRun: number;
41
+ minUtilityScore: number;
42
+ minNoveltyScore: number;
43
+ maxWritesPerSessionWindow: number;
44
+ cooldownMinutes: number;
45
+ };
26
46
  ml: {
27
47
  provider?: "openai" | "anthropic" | "gemini";
28
48
  model?: string;
@@ -80,6 +100,16 @@ const DEFAULTS: MemoryBraidConfig = {
80
100
  recall: {
81
101
  maxResults: 8,
82
102
  injectTopK: 5,
103
+ user: {
104
+ enabled: true,
105
+ injectTopK: 5,
106
+ },
107
+ agent: {
108
+ enabled: true,
109
+ injectTopK: 2,
110
+ minScore: 0.78,
111
+ onlyPlanning: true,
112
+ },
83
113
  merge: {
84
114
  strategy: "rrf",
85
115
  rrfK: 60,
@@ -92,6 +122,16 @@ const DEFAULTS: MemoryBraidConfig = {
92
122
  mode: "local",
93
123
  includeAssistant: false,
94
124
  maxItemsPerRun: 6,
125
+ assistant: {
126
+ enabled: true,
127
+ autoCapture: false,
128
+ explicitTool: true,
129
+ maxItemsPerRun: 2,
130
+ minUtilityScore: 0.8,
131
+ minNoveltyScore: 0.85,
132
+ maxWritesPerSessionWindow: 3,
133
+ cooldownMinutes: 5,
134
+ },
95
135
  ml: {
96
136
  provider: undefined,
97
137
  model: undefined,
@@ -168,8 +208,11 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
168
208
  const root = asRecord(raw);
169
209
  const mem0 = asRecord(root.mem0);
170
210
  const recall = asRecord(root.recall);
211
+ const recallUser = asRecord(recall.user);
212
+ const recallAgent = asRecord(recall.agent);
171
213
  const merge = asRecord(recall.merge);
172
214
  const capture = asRecord(root.capture);
215
+ const captureAssistant = asRecord(capture.assistant);
173
216
  const entityExtraction = asRecord(root.entityExtraction);
174
217
  const entityStartup = asRecord(entityExtraction.startup);
175
218
  const ml = asRecord(capture.ml);
@@ -194,6 +237,16 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
194
237
  ? parsedEntityModel
195
238
  : "gpt-4o-mini"
196
239
  : parsedEntityModel ?? DEFAULTS.entityExtraction.model;
240
+ const includeAssistant = asBoolean(
241
+ capture.includeAssistant,
242
+ DEFAULTS.capture.includeAssistant,
243
+ );
244
+ const legacyInjectTopK = asInt(
245
+ recall.injectTopK,
246
+ DEFAULTS.recall.injectTopK,
247
+ 1,
248
+ 20,
249
+ );
197
250
 
198
251
  return {
199
252
  enabled: asBoolean(root.enabled, DEFAULTS.enabled),
@@ -207,7 +260,35 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
207
260
  },
208
261
  recall: {
209
262
  maxResults: asInt(recall.maxResults, DEFAULTS.recall.maxResults, 1, 50),
210
- injectTopK: asInt(recall.injectTopK, DEFAULTS.recall.injectTopK, 1, 20),
263
+ injectTopK: legacyInjectTopK,
264
+ user: {
265
+ enabled: asBoolean(recallUser.enabled, DEFAULTS.recall.user.enabled),
266
+ injectTopK: asInt(
267
+ recallUser.injectTopK,
268
+ legacyInjectTopK,
269
+ 1,
270
+ 20,
271
+ ),
272
+ },
273
+ agent: {
274
+ enabled: asBoolean(recallAgent.enabled, DEFAULTS.recall.agent.enabled),
275
+ injectTopK: asInt(
276
+ recallAgent.injectTopK,
277
+ DEFAULTS.recall.agent.injectTopK,
278
+ 1,
279
+ 20,
280
+ ),
281
+ minScore: asNumber(
282
+ recallAgent.minScore,
283
+ DEFAULTS.recall.agent.minScore,
284
+ 0,
285
+ 1,
286
+ ),
287
+ onlyPlanning: asBoolean(
288
+ recallAgent.onlyPlanning,
289
+ DEFAULTS.recall.agent.onlyPlanning,
290
+ ),
291
+ },
211
292
  merge: {
212
293
  strategy: "rrf",
213
294
  rrfK: asInt(merge.rrfK, DEFAULTS.recall.merge.rrfK, 1, 500),
@@ -218,8 +299,52 @@ export function parseConfig(raw: unknown): MemoryBraidConfig {
218
299
  capture: {
219
300
  enabled: asBoolean(capture.enabled, DEFAULTS.capture.enabled),
220
301
  mode: captureMode,
221
- includeAssistant: asBoolean(capture.includeAssistant, DEFAULTS.capture.includeAssistant),
302
+ includeAssistant,
222
303
  maxItemsPerRun: asInt(capture.maxItemsPerRun, DEFAULTS.capture.maxItemsPerRun, 1, 50),
304
+ assistant: {
305
+ enabled: asBoolean(
306
+ captureAssistant.enabled,
307
+ DEFAULTS.capture.assistant.enabled,
308
+ ),
309
+ autoCapture: asBoolean(
310
+ captureAssistant.autoCapture,
311
+ includeAssistant,
312
+ ),
313
+ explicitTool: asBoolean(
314
+ captureAssistant.explicitTool,
315
+ DEFAULTS.capture.assistant.explicitTool,
316
+ ),
317
+ maxItemsPerRun: asInt(
318
+ captureAssistant.maxItemsPerRun,
319
+ DEFAULTS.capture.assistant.maxItemsPerRun,
320
+ 1,
321
+ 10,
322
+ ),
323
+ minUtilityScore: asNumber(
324
+ captureAssistant.minUtilityScore,
325
+ DEFAULTS.capture.assistant.minUtilityScore,
326
+ 0,
327
+ 1,
328
+ ),
329
+ minNoveltyScore: asNumber(
330
+ captureAssistant.minNoveltyScore,
331
+ DEFAULTS.capture.assistant.minNoveltyScore,
332
+ 0,
333
+ 1,
334
+ ),
335
+ maxWritesPerSessionWindow: asInt(
336
+ captureAssistant.maxWritesPerSessionWindow,
337
+ DEFAULTS.capture.assistant.maxWritesPerSessionWindow,
338
+ 1,
339
+ 20,
340
+ ),
341
+ cooldownMinutes: asInt(
342
+ captureAssistant.cooldownMinutes,
343
+ DEFAULTS.capture.assistant.cooldownMinutes,
344
+ 0,
345
+ 240,
346
+ ),
347
+ },
223
348
  ml: {
224
349
  provider:
225
350
  ml.provider === "openai" || ml.provider === "anthropic" || ml.provider === "gemini"
package/src/extract.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { normalizeForHash, normalizeWhitespace, sha256 } from "./chunking.js";
2
2
  import type { MemoryBraidConfig } from "./config.js";
3
+ import { isLikelyTranscriptLikeText, isOversizedAtomicMemory } from "./capture.js";
3
4
  import { MemoryBraidLogger } from "./logger.js";
4
5
  import type { ExtractedCandidate } from "./types.js";
5
6
 
@@ -18,6 +19,9 @@ const FEED_TAG_PATTERN = /\[(?:n8n|rss|alert|news|cron|slack|discord|telegram|em
18
19
  const ROLE_LABEL_PATTERN = /\b(?:assistant|system|tool|developer)\s*:/gi;
19
20
 
20
21
  function isLikelyFeedOrImportedText(text: string): boolean {
22
+ if (isLikelyTranscriptLikeText(text) || isOversizedAtomicMemory(text)) {
23
+ return true;
24
+ }
21
25
  if (FEED_TAG_PATTERN.test(text)) {
22
26
  return true;
23
27
  }
@@ -398,6 +402,9 @@ function applyMlExtractionResult(
398
402
  if (!text || text.length < 20 || text.length > 3000) {
399
403
  continue;
400
404
  }
405
+ if (isLikelyFeedOrImportedText(text)) {
406
+ continue;
407
+ }
401
408
  const key = sha256(normalizeForHash(text));
402
409
  if (seen.has(key)) {
403
410
  continue;
@@ -425,7 +432,7 @@ export async function extractCandidates(params: {
425
432
  runId?: string;
426
433
  }): Promise<ExtractedCandidate[]> {
427
434
  const normalized = normalizeMessages(params.messages);
428
- const captureFromAssistant = params.cfg.capture.includeAssistant;
435
+ const captureFromAssistant = params.cfg.capture.assistant.autoCapture;
429
436
  const candidatesInput = normalized.filter((message) =>
430
437
  captureFromAssistant
431
438
  ? message.role === "user" || message.role === "assistant"