memo-grafter 0.2.3 → 0.2.5
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/USER_GUIDE.md +325 -71
- package/dist/MemoGrafter.d.ts +8 -5
- package/dist/MemoGrafter.d.ts.map +1 -1
- package/dist/MemoGrafter.js +12 -10
- package/dist/MemoGrafter.js.map +1 -1
- package/dist/MemoGrafterAgent.d.ts +5 -2
- package/dist/MemoGrafterAgent.d.ts.map +1 -1
- package/dist/MemoGrafterAgent.js +15 -3
- package/dist/MemoGrafterAgent.js.map +1 -1
- package/dist/crawler/ConflictDetectionPass.d.ts +6 -0
- package/dist/crawler/ConflictDetectionPass.d.ts.map +1 -0
- package/dist/crawler/ConflictDetectionPass.js +46 -0
- package/dist/crawler/ConflictDetectionPass.js.map +1 -0
- package/dist/crawler/DecayScoringPass.d.ts +17 -0
- package/dist/crawler/DecayScoringPass.d.ts.map +1 -0
- package/dist/crawler/DecayScoringPass.js +73 -0
- package/dist/crawler/DecayScoringPass.js.map +1 -0
- package/dist/crawler/MemoGrafterCrawler.d.ts +14 -0
- package/dist/crawler/MemoGrafterCrawler.d.ts.map +1 -0
- package/dist/crawler/MemoGrafterCrawler.js +108 -0
- package/dist/crawler/MemoGrafterCrawler.js.map +1 -0
- package/dist/crawler/VersioningPass.d.ts +6 -0
- package/dist/crawler/VersioningPass.d.ts.map +1 -0
- package/dist/crawler/VersioningPass.js +43 -0
- package/dist/crawler/VersioningPass.js.map +1 -0
- package/dist/crawler/decayScoring.d.ts +7 -0
- package/dist/crawler/decayScoring.d.ts.map +1 -0
- package/dist/crawler/decayScoring.js +9 -0
- package/dist/crawler/decayScoring.js.map +1 -0
- package/dist/crawler/index.d.ts +7 -0
- package/dist/crawler/index.d.ts.map +1 -0
- package/dist/crawler/index.js +5 -0
- package/dist/crawler/index.js.map +1 -0
- package/dist/crawler/memoryMaintenance.d.ts +15 -0
- package/dist/crawler/memoryMaintenance.d.ts.map +1 -0
- package/dist/crawler/memoryMaintenance.js +110 -0
- package/dist/crawler/memoryMaintenance.js.map +1 -0
- package/dist/crawler/types.d.ts +63 -0
- package/dist/crawler/types.d.ts.map +1 -0
- package/dist/crawler/types.js +2 -0
- package/dist/crawler/types.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/GrafterPipeline.d.ts.map +1 -1
- package/dist/pipeline/GrafterPipeline.js +42 -1
- package/dist/pipeline/GrafterPipeline.js.map +1 -1
- package/dist/pipeline/IngestPipeline.d.ts +7 -3
- package/dist/pipeline/IngestPipeline.d.ts.map +1 -1
- package/dist/pipeline/IngestPipeline.js +24 -13
- package/dist/pipeline/IngestPipeline.js.map +1 -1
- package/dist/pipeline/RetrieverPipeline.d.ts +3 -0
- package/dist/pipeline/RetrieverPipeline.d.ts.map +1 -1
- package/dist/pipeline/RetrieverPipeline.js +56 -13
- package/dist/pipeline/RetrieverPipeline.js.map +1 -1
- package/dist/pipeline/SegmentProcessor.d.ts +3 -1
- package/dist/pipeline/SegmentProcessor.d.ts.map +1 -1
- package/dist/pipeline/SegmentProcessor.js +9 -5
- package/dist/pipeline/SegmentProcessor.js.map +1 -1
- package/dist/prompts/memoryInjectionPrompt.d.ts +6 -2
- package/dist/prompts/memoryInjectionPrompt.d.ts.map +1 -1
- package/dist/prompts/memoryInjectionPrompt.js +25 -2
- package/dist/prompts/memoryInjectionPrompt.js.map +1 -1
- package/dist/queue/IngestQueue.d.ts +2 -2
- package/dist/queue/IngestQueue.d.ts.map +1 -1
- package/dist/queue/IngestQueue.js +3 -2
- package/dist/queue/IngestQueue.js.map +1 -1
- package/dist/store/GraphStore.d.ts +13 -3
- package/dist/store/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.d.ts +16 -3
- package/dist/store/postgres-pgvector/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.js +170 -6
- package/dist/store/postgres-pgvector/GraphStore.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/drift/adaptiveDriftSensitivity.d.ts +20 -0
- package/dist/utils/drift/adaptiveDriftSensitivity.d.ts.map +1 -0
- package/dist/utils/drift/adaptiveDriftSensitivity.js +67 -0
- package/dist/utils/drift/adaptiveDriftSensitivity.js.map +1 -0
- package/dist/utils/tags.d.ts +2 -0
- package/dist/utils/tags.d.ts.map +1 -0
- package/dist/utils/tags.js +13 -0
- package/dist/utils/tags.js.map +1 -0
- package/package.json +1 -1
package/USER_GUIDE.md
CHANGED
|
@@ -84,11 +84,13 @@ Current v1 tables:
|
|
|
84
84
|
- `mg_topic_nodes`
|
|
85
85
|
- `mg_topic_edges`
|
|
86
86
|
- `mg_memory_nodes`
|
|
87
|
-
- `mg_memory_edges`
|
|
88
|
-
- `mg_fleets`
|
|
89
|
-
- `mg_fleet_agents`
|
|
90
|
-
- `mg_session_ingest_state`
|
|
91
|
-
- `mg_graft_registry`
|
|
87
|
+
- `mg_memory_edges`
|
|
88
|
+
- `mg_fleets`
|
|
89
|
+
- `mg_fleet_agents`
|
|
90
|
+
- `mg_session_ingest_state`
|
|
91
|
+
- `mg_graft_registry`
|
|
92
|
+
|
|
93
|
+
`mg_topic_nodes` and `mg_memory_nodes` include optional `tags TEXT[]` columns. Tags default to an empty array, so existing untagged sessions continue to work normally.
|
|
92
94
|
|
|
93
95
|
## Quick Start
|
|
94
96
|
|
|
@@ -179,6 +181,7 @@ Important fields:
|
|
|
179
181
|
- `label`: short label.
|
|
180
182
|
- `summary`: structured summary of the segment.
|
|
181
183
|
- `embedding`: vector used for semantic search.
|
|
184
|
+
- `tags`: optional normalized tags such as `"project:memo-grafter"` or `"planning"`.
|
|
182
185
|
- `messageRange`: source message range.
|
|
183
186
|
- `topicOrder`: chronological order.
|
|
184
187
|
- `driftScore`: topic-change score.
|
|
@@ -196,11 +199,15 @@ Important fields:
|
|
|
196
199
|
- `subject`, `predicate`, `value`: the structured memory triple.
|
|
197
200
|
- `confidence`: confidence score from `0` to `1`.
|
|
198
201
|
- `topicNodeId`: parent topic node ID.
|
|
202
|
+
- `tags`: optional normalized tags copied from the session or ingest call.
|
|
199
203
|
- `decayed`: whether the memory is stale.
|
|
204
|
+
- `hasConflict`: whether crawler maintenance found a conflicting active fact.
|
|
200
205
|
- `supersededBy`: newer memory ID when this memory has been replaced.
|
|
201
206
|
|
|
202
207
|
Memory nodes are stored in `mg_memory_nodes`.
|
|
203
208
|
|
|
209
|
+
`decayed`, `hasConflict`, and `supersededBy` are maintenance fields. Normal ingestion creates active memories. Optional crawler passes can later annotate existing memory rows, but they do not delete rows or rewrite topic summaries.
|
|
210
|
+
|
|
204
211
|
### Graph Edges
|
|
205
212
|
|
|
206
213
|
Edges connect related topic nodes. They can represent temporal, semantic, grafted, or reentry relationships.
|
|
@@ -212,6 +219,19 @@ Edges connect related topic nodes. They can represent temporal, semantic, grafte
|
|
|
212
219
|
|
|
213
220
|
Edges are stored in `mg_topic_edges`.
|
|
214
221
|
|
|
222
|
+
Memory edges are stored separately in `mg_memory_edges`. They can represent:
|
|
223
|
+
|
|
224
|
+
- `semantic`: two memory facts are similar.
|
|
225
|
+
- `conflicts`: two active memory facts disagree.
|
|
226
|
+
- `updates`: a newer memory supersedes an older memory.
|
|
227
|
+
- `related`: reserved for broader memory relationships.
|
|
228
|
+
|
|
229
|
+
For version edges, MemoGrafter uses this direction:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
newer_memory --updates--> older_memory
|
|
233
|
+
```
|
|
234
|
+
|
|
215
235
|
### Grafting
|
|
216
236
|
|
|
217
237
|
Grafting is the process of selecting topic nodes and turning them into useful context for another prompt or another chatbot.
|
|
@@ -221,9 +241,9 @@ There are two common forms:
|
|
|
221
241
|
- Preview memory with `graft()`.
|
|
222
242
|
- Copy memory into another chatbot with `absorbFromAgent()` or `ingestGraftedNodes()`.
|
|
223
243
|
|
|
224
|
-
When topic nodes are absorbed into another session, MemoGrafter also copies their active memory nodes so targeted recall can find the transferred facts. Copied memory rows get fresh IDs, keep their existing embeddings, and are copied as active memories only when the source row is not decayed or superseded.
|
|
225
|
-
|
|
226
|
-
Absorbed topic nodes are also registered in `mg_graft_registry`. The registry records the destination session, copied node ID, source session ID, source node ID, and graft timestamp so applications can inspect provenance or remove a graft later.
|
|
244
|
+
When topic nodes are absorbed into another session, MemoGrafter also copies their active memory nodes so targeted recall can find the transferred facts. Copied memory rows get fresh IDs, keep their existing embeddings, and are copied as active memories only when the source row is not decayed or superseded.
|
|
245
|
+
|
|
246
|
+
Absorbed topic nodes are also registered in `mg_graft_registry`. The registry records the destination session, copied node ID, source session ID, source node ID, and graft timestamp so applications can inspect provenance or remove a graft later.
|
|
227
247
|
|
|
228
248
|
## Using MemoGrafterAgent
|
|
229
249
|
|
|
@@ -286,6 +306,32 @@ await agent.clearSession();
|
|
|
286
306
|
|
|
287
307
|
This waits for pending ingestion, clears the agent's local in-memory history, removes stored messages, topic nodes, memory nodes, graph edges, segments, and resets the session ingest cursor. It is a destructive operation and is not part of normal `invoke()` processing.
|
|
288
308
|
|
|
309
|
+
### Session Tags
|
|
310
|
+
|
|
311
|
+
Use session tags when you want to organize memory by project, planning area, week, domain, or worker route.
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
await agent.setSessionTags([
|
|
315
|
+
"project:memo-grafter",
|
|
316
|
+
"planning",
|
|
317
|
+
"week:2026-05-25",
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
console.log(agent.getSessionTags());
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Tags are optional. They are normalized by trimming whitespace, lowercasing, deduplicating, and sorting. Calling `setSessionTags()` waits for pending ingestion, updates existing topic and memory rows for the current session, and applies the same tags to future memories created by `invoke()`.
|
|
324
|
+
|
|
325
|
+
You can also tag direct ingestion:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
await memo.ingest(messages, sessionId, {
|
|
329
|
+
tags: ["project:memo-grafter", "planning"],
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Tags do not replace `sessionId`. By default, MemoGrafter still reads from the current session. Tag filters are opt-in.
|
|
334
|
+
|
|
289
335
|
### Targeted Recall
|
|
290
336
|
|
|
291
337
|
Use `recall()` when you want to retrieve structured memory by meaning without asking the LLM to produce an answer.
|
|
@@ -295,6 +341,13 @@ const result = await agent.recall("deployment config", {
|
|
|
295
341
|
limit: 8,
|
|
296
342
|
minSimilarity: 0.55,
|
|
297
343
|
tokenBudget: 1000,
|
|
344
|
+
tags: ["project:memo-grafter"],
|
|
345
|
+
tagMode: "all",
|
|
346
|
+
scope: "session-and-tags",
|
|
347
|
+
scoring: {
|
|
348
|
+
similarityWeight: 0.7,
|
|
349
|
+
confidenceWeight: 0.3,
|
|
350
|
+
},
|
|
298
351
|
cache: {
|
|
299
352
|
ttlSeconds: 90,
|
|
300
353
|
},
|
|
@@ -318,9 +371,26 @@ Options:
|
|
|
318
371
|
- `limit`: max memory nodes to fetch before filtering. Defaults to `10`.
|
|
319
372
|
- `minSimilarity`: cosine similarity floor. Defaults to `0.6`.
|
|
320
373
|
- `tokenBudget`: max approximate tokens for included fact blocks. Defaults to `1200`.
|
|
374
|
+
- `tags`: optional normalized tag filter.
|
|
375
|
+
- `tagMode`: `"all"` requires every requested tag, `"any"` accepts at least one requested tag. Defaults to `"all"`.
|
|
376
|
+
- `scope`: `"session"` keeps normal current-session recall, `"session-and-tags"` filters current-session recall by tags, and `"tagged"` searches across sessions matching the tags.
|
|
377
|
+
- `scoring.similarityWeight`: weight applied to semantic similarity when ranking retrieved facts. Defaults to `0.7`.
|
|
378
|
+
- `scoring.confidenceWeight`: weight applied to memory confidence when ranking retrieved facts. Defaults to `0.3`.
|
|
321
379
|
- `cache.ttlSeconds`: per-call recall cache TTL override when `MemoGrafterConfig.cache` is enabled. Values are clamped to 60-120 seconds.
|
|
322
380
|
|
|
323
|
-
`recall()` is side-effect free. It does not call `invoke()`, does not trigger a new LLM completion, and does not mutate local history. Your application can call it directly to display memories, add `result.systemPrompt` to a model call, or ignore the result.
|
|
381
|
+
`recall()` is side-effect free. It does not call `invoke()`, does not trigger a new LLM completion, and does not mutate local history. Your application can call it directly to display memories, add `result.systemPrompt` to a model call, or ignore the result. Retrieval still uses `minSimilarity` for the vector search floor, then ranks returned active facts with `similarity * similarityWeight + confidence * confidenceWeight`.
|
|
382
|
+
|
|
383
|
+
Cross-session tagged recall is explicit:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
const projectMemory = await agent.recall("deployment decisions", {
|
|
387
|
+
tags: ["project:memo-grafter"],
|
|
388
|
+
scope: "tagged",
|
|
389
|
+
minSimilarity: 0.3,
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This can return matching active memories from older or different sessions with the same tag. If your development database contains repeated smoke-test runs, you may see more than one matching fact because the older tagged rows are still present.
|
|
324
394
|
|
|
325
395
|
`MemoGrafterAgent.invoke()` also calls `recall()` internally before answering when the session has topic nodes. In that automatic path, the returned `systemPrompt` is pinned as a single system message before the recent raw chat window. Automatic recall uses `inject.recallLimit` and `inject.recallMinSimilarity`, defaulting to `6` and `0.55`.
|
|
326
396
|
|
|
@@ -334,25 +404,29 @@ Read a complete session graph snapshot:
|
|
|
334
404
|
const snapshot = await agent.getGraphSnapshot();
|
|
335
405
|
|
|
336
406
|
console.log(snapshot.sessionId);
|
|
337
|
-
console.log(snapshot.nodes);
|
|
338
|
-
console.log(snapshot.snapshotNodes);
|
|
339
|
-
console.log(snapshot.edges);
|
|
340
|
-
console.log(snapshot.memories);
|
|
341
|
-
console.log(snapshot.
|
|
407
|
+
console.log(snapshot.nodes);
|
|
408
|
+
console.log(snapshot.snapshotNodes);
|
|
409
|
+
console.log(snapshot.edges);
|
|
410
|
+
console.log(snapshot.memories);
|
|
411
|
+
console.log(snapshot.memoryEdges);
|
|
412
|
+
console.log(snapshot.capturedAt);
|
|
342
413
|
```
|
|
343
414
|
|
|
344
415
|
`getGraphSnapshot()` returns a `GraphSnapshot`:
|
|
345
416
|
|
|
346
|
-
- `sessionId`: current agent session ID.
|
|
347
|
-
- `nodes`: active topic nodes for the session.
|
|
348
|
-
- `snapshotNodes`: active topic nodes wrapped with provenance metadata when a node came from a graft.
|
|
349
|
-
- `edges`: topic edges where either endpoint belongs to a session topic node.
|
|
350
|
-
- `memories`: all memory nodes for the session, including decayed or superseded rows.
|
|
351
|
-
- `
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
417
|
+
- `sessionId`: current agent session ID.
|
|
418
|
+
- `nodes`: active topic nodes for the session.
|
|
419
|
+
- `snapshotNodes`: active topic nodes wrapped with provenance metadata when a node came from a graft.
|
|
420
|
+
- `edges`: topic edges where either endpoint belongs to a session topic node.
|
|
421
|
+
- `memories`: all memory nodes for the session, including decayed or superseded rows.
|
|
422
|
+
- `memoryEdges`: memory-level edges such as `semantic`, `conflicts`, `updates`, and `related`.
|
|
423
|
+
- `capturedAt`: ISO timestamp for when the snapshot was produced.
|
|
424
|
+
|
|
425
|
+
Each `snapshotNodes` entry contains the topic `node` and an optional `graftOrigin` with `sourceSessionId`, `sourceNodeId`, and `graftedAt`. The plain `nodes` array remains available for callers that only need the topic nodes.
|
|
426
|
+
|
|
427
|
+
This method is read-only. It does not include raw `mg_message_buffer` content and does not add rendering, layout, or color decisions. Like `getActiveNodes()` and `getActiveSegments()`, it waits for the agent's pending ingest work before reading. If called immediately after `invoke()` in queue mode, it waits for the current ingest job to settle before returning.
|
|
428
|
+
|
|
429
|
+
Graph snapshots intentionally include stale and maintenance metadata so visualizers can show memory lifecycle state. For example, a UI can fade `decayed` memories, show `hasConflict` badges, draw `conflicts` edges between contradictory facts, and draw `updates` edges from the current fact to the older fact it replaced.
|
|
356
430
|
|
|
357
431
|
Read active topic nodes:
|
|
358
432
|
|
|
@@ -371,6 +445,15 @@ for (const node of nodes) {
|
|
|
371
445
|
}
|
|
372
446
|
```
|
|
373
447
|
|
|
448
|
+
Filter active topic nodes by tag:
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
const planningNodes = await agent.getActiveNodes({
|
|
452
|
+
tags: ["planning"],
|
|
453
|
+
tagMode: "all",
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
374
457
|
Read active segments:
|
|
375
458
|
|
|
376
459
|
```ts
|
|
@@ -417,6 +500,117 @@ const graft = await agent.graft([nodes[0]!.id]);
|
|
|
417
500
|
- `nodes`: selected topic nodes.
|
|
418
501
|
- `tokenCount`: estimated token count.
|
|
419
502
|
|
|
503
|
+
Graft prompts include topic summaries because they preserve useful conversation context. Topic summaries are historical: if an older topic summary says "the user lives in Delhi" and a later memory says "the user lives in Bangalore", MemoGrafter does not rewrite the old summary. Instead, when crawler maintenance has marked a contradiction or supersession, graft prompt assembly adds deterministic maintenance notes and active memory facts:
|
|
504
|
+
|
|
505
|
+
```text
|
|
506
|
+
Memory maintenance notes:
|
|
507
|
+
- The fact "user location: Delhi" was superseded by "Bangalore".
|
|
508
|
+
- Prefer active memory facts over contradictory historical summary details.
|
|
509
|
+
Active memory facts:
|
|
510
|
+
- user location: Bangalore
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
This keeps history intact while telling the downstream model which fact is current.
|
|
514
|
+
|
|
515
|
+
## Maintaining Memory With The Crawler
|
|
516
|
+
|
|
517
|
+
`MemoGrafterCrawler` is an optional graph maintenance worker. It can run once on demand or on a simple in-process interval. It does not use Redis, BullMQ, OpenAI, embeddings, or LLMs for the built-in conflict/versioning/decay passes.
|
|
518
|
+
|
|
519
|
+
Typical usage with the real store:
|
|
520
|
+
|
|
521
|
+
```ts
|
|
522
|
+
import {
|
|
523
|
+
ConflictDetectionPass,
|
|
524
|
+
DecayScoringPass,
|
|
525
|
+
MemoGrafter,
|
|
526
|
+
MemoGrafterCrawler,
|
|
527
|
+
VersioningPass,
|
|
528
|
+
} from "memo-grafter";
|
|
529
|
+
|
|
530
|
+
const memo = new MemoGrafter(config);
|
|
531
|
+
await memo.initialize();
|
|
532
|
+
|
|
533
|
+
const crawler = new MemoGrafterCrawler({
|
|
534
|
+
store: memo.store,
|
|
535
|
+
intervalMs: 60_000,
|
|
536
|
+
passes: [
|
|
537
|
+
new ConflictDetectionPass(),
|
|
538
|
+
new VersioningPass(),
|
|
539
|
+
new DecayScoringPass({
|
|
540
|
+
halfLifeDays: 90,
|
|
541
|
+
minScore: 0.25,
|
|
542
|
+
}),
|
|
543
|
+
],
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
const report = await crawler.runOnce();
|
|
547
|
+
console.log(report);
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
`runOnce()` executes the configured passes exactly one time and returns a `CrawlerReport`. `intervalMs` does not affect `runOnce()`.
|
|
551
|
+
|
|
552
|
+
To run the crawler in-process on a schedule:
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
crawler.start();
|
|
556
|
+
|
|
557
|
+
// Later, during shutdown:
|
|
558
|
+
crawler.stop();
|
|
559
|
+
await memo.close();
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
`start()` is safe to call more than once; it does not create duplicate intervals. If a scheduled tick fires while the previous run is still executing, that tick is skipped.
|
|
563
|
+
|
|
564
|
+
The built-in conflict/versioning passes use deterministic matching:
|
|
565
|
+
|
|
566
|
+
- they group active memories by session, normalized `subject`, and normalized `predicate`;
|
|
567
|
+
- a group conflicts when it has different normalized `value` strings;
|
|
568
|
+
- decayed memories are skipped;
|
|
569
|
+
- already superseded memories are skipped;
|
|
570
|
+
- broad topic memories with generic subject/predicate pairs are skipped unless they match a recognized competing trip-plan pattern;
|
|
571
|
+
- the newest conflicting fact wins by `createdAt`;
|
|
572
|
+
- if timestamps tie, deterministic ID ordering is used.
|
|
573
|
+
|
|
574
|
+
Conflict detection is meant for mutually exclusive fact slots such as `user location Delhi` versus `user location Bangalore`. For generic "things discussed" memories, MemoGrafter only recognizes a narrow travel destination plan pattern by default. That means `Goa trip plan` and `Vietnam trip plan` can conflict, while `how to cook rajma chawal`, `food in Vietnam`, and `places to visit Vietnam` do not all conflict just because extraction used a generic subject and predicate.
|
|
575
|
+
|
|
576
|
+
`DecayScoringPass` uses confidence-weighted exponential recency decay:
|
|
577
|
+
|
|
578
|
+
```text
|
|
579
|
+
recency_factor = exp(-(ln(2) / half_life_days) * age_days)
|
|
580
|
+
decay_score = confidence * recency_factor
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
If `decay_score < minScore`, the memory is marked `decayed: true`. Superseded memories and already decayed memories are skipped. Conservative defaults are used when options are omitted:
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
new DecayScoringPass({
|
|
587
|
+
halfLifeDays: 90,
|
|
588
|
+
minScore: 0.25,
|
|
589
|
+
});
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
By default the pass does not change stored `confidence`; confidence is treated as extraction confidence, while decay score is temporal freshness. If you explicitly want the score written back as confidence, pass `updateConfidence: true`.
|
|
593
|
+
|
|
594
|
+
When conflicts are found:
|
|
595
|
+
|
|
596
|
+
- both active facts get `hasConflict: true`;
|
|
597
|
+
- a `conflicts` memory edge is created;
|
|
598
|
+
- the older fact gets `supersededBy` pointing to the newer fact;
|
|
599
|
+
- an `updates` edge is created as `newer_memory --updates--> older_memory`.
|
|
600
|
+
- stale active memories can be marked `decayed: true` by the decay pass.
|
|
601
|
+
|
|
602
|
+
Crawler maintenance is non-destructive. It annotates existing memory rows and creates memory edges. It does not delete nodes, does not rebuild topics, and does not rewrite topic summaries.
|
|
603
|
+
|
|
604
|
+
Existing incorrect conflict edges are not automatically deleted. If an older crawler run created a false-positive edge, handle cleanup with a future explicit pruning pass or filter displayed memory edges to active memories in your app.
|
|
605
|
+
|
|
606
|
+
Do not put crawler behavior inside `clearSession()`. `clearSession()` is a destructive reset. The crawler is a non-destructive maintenance worker. If you intentionally rebuild a session graph, use this order:
|
|
607
|
+
|
|
608
|
+
```ts
|
|
609
|
+
await agent.clearSession();
|
|
610
|
+
await memo.ingestNow(messages, sessionId);
|
|
611
|
+
await crawler.runOnce();
|
|
612
|
+
```
|
|
613
|
+
|
|
420
614
|
## Absorbing Memory Into Another Chatbot
|
|
421
615
|
|
|
422
616
|
Use `absorbFromAgent()` to copy selected memory from one chatbot into another.
|
|
@@ -447,37 +641,37 @@ const response = await writingBot.invoke(
|
|
|
447
641
|
console.log(response);
|
|
448
642
|
```
|
|
449
643
|
|
|
450
|
-
Absorbing copies selected topic nodes into the target session and creates `grafted` edges back to their source nodes. It also copies active memory facts attached to those topic nodes into the target session so future `recall()` and `invoke()` calls can surface the transferred context. Decayed or superseded source memories are not copied.
|
|
451
|
-
|
|
452
|
-
Each copied topic node is recorded in the graft registry. Registry entries let you answer where a graft came from and which copied destination node owns it.
|
|
453
|
-
|
|
454
|
-
Known limitation: if a source topic node has no associated memory rows in `mg_memory_nodes`, there are no facts to copy. The topic node can still be grafted, but targeted recall will not return facts for that node unless memory extraction produced them.
|
|
455
|
-
|
|
456
|
-
### Inspect Graft Registry
|
|
457
|
-
|
|
458
|
-
```ts
|
|
459
|
-
const registry = await writingBot.getGraftRegistry();
|
|
460
|
-
|
|
461
|
-
for (const entry of registry) {
|
|
462
|
-
console.log({
|
|
463
|
-
nodeId: entry.nodeId,
|
|
464
|
-
sourceSessionId: entry.sourceSessionId,
|
|
465
|
-
sourceNodeId: entry.sourceNodeId,
|
|
466
|
-
graftedAt: entry.graftedAt,
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
Use this when your app needs to display transferred memory provenance or decide which graft to remove.
|
|
472
|
-
|
|
473
|
-
### Remove A Graft
|
|
474
|
-
|
|
475
|
-
```ts
|
|
476
|
-
const registry = await writingBot.getGraftRegistry();
|
|
477
|
-
await writingBot.removeGraft(registry[0]!.nodeId);
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
`removeGraft()` removes the copied graft node from the current session. The registry row is removed with it. The method is scoped to the current agent session and throws if the node is not a registered graft for that session.
|
|
644
|
+
Absorbing copies selected topic nodes into the target session and creates `grafted` edges back to their source nodes. It also copies active memory facts attached to those topic nodes into the target session so future `recall()` and `invoke()` calls can surface the transferred context. Decayed or superseded source memories are not copied.
|
|
645
|
+
|
|
646
|
+
Each copied topic node is recorded in the graft registry. Registry entries let you answer where a graft came from and which copied destination node owns it.
|
|
647
|
+
|
|
648
|
+
Known limitation: if a source topic node has no associated memory rows in `mg_memory_nodes`, there are no facts to copy. The topic node can still be grafted, but targeted recall will not return facts for that node unless memory extraction produced them.
|
|
649
|
+
|
|
650
|
+
### Inspect Graft Registry
|
|
651
|
+
|
|
652
|
+
```ts
|
|
653
|
+
const registry = await writingBot.getGraftRegistry();
|
|
654
|
+
|
|
655
|
+
for (const entry of registry) {
|
|
656
|
+
console.log({
|
|
657
|
+
nodeId: entry.nodeId,
|
|
658
|
+
sourceSessionId: entry.sourceSessionId,
|
|
659
|
+
sourceNodeId: entry.sourceNodeId,
|
|
660
|
+
graftedAt: entry.graftedAt,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Use this when your app needs to display transferred memory provenance or decide which graft to remove.
|
|
666
|
+
|
|
667
|
+
### Remove A Graft
|
|
668
|
+
|
|
669
|
+
```ts
|
|
670
|
+
const registry = await writingBot.getGraftRegistry();
|
|
671
|
+
await writingBot.removeGraft(registry[0]!.nodeId);
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
`removeGraft()` removes the copied graft node from the current session. The registry row is removed with it. The method is scoped to the current agent session and throws if the node is not a registered graft for that session.
|
|
481
675
|
|
|
482
676
|
### Absorb By Semantic Prompt
|
|
483
677
|
|
|
@@ -527,6 +721,9 @@ const agent = new MemoGrafterAgent({
|
|
|
527
721
|
mode: "intent",
|
|
528
722
|
windowSize: 5,
|
|
529
723
|
driftSensitivity: "medium",
|
|
724
|
+
adaptiveSensitivity: {
|
|
725
|
+
enabled: false,
|
|
726
|
+
},
|
|
530
727
|
minSegmentMessages: 3,
|
|
531
728
|
llmAmbiguityDetection: false,
|
|
532
729
|
reentryDetection: true,
|
|
@@ -575,13 +772,15 @@ const store: GraphStore = new PostgresGraphStore(process.env.DATABASE_URL!);
|
|
|
575
772
|
|
|
576
773
|
Useful store inspection methods include:
|
|
577
774
|
|
|
578
|
-
- `getNodesBySession(sessionId)`: read topic nodes for a session.
|
|
775
|
+
- `getNodesBySession(sessionId, options?)`: read topic nodes for a session, optionally filtered by tags.
|
|
579
776
|
- `getTopicNode(topicNodeId, sessionId?)`: read one topic node by ID.
|
|
580
777
|
- `getSegmentsBySession(sessionId)`: read topic segments for a session.
|
|
581
778
|
- `getEdgesByType(sessionId, type)`: inspect graph edges such as `"reentry"`, `"semantic"`, `"temporal"`, or `"grafted"`.
|
|
582
|
-
- `getEdgesBySession(sessionId)`: read all topic edges where either endpoint belongs to the session's topic nodes.
|
|
583
|
-
- `getMemoriesBySession(sessionId)`: read all memory nodes for a session, including decayed and superseded rows.
|
|
584
|
-
- `
|
|
779
|
+
- `getEdgesBySession(sessionId)`: read all topic edges where either endpoint belongs to the session's topic nodes.
|
|
780
|
+
- `getMemoriesBySession(sessionId)`: read all memory nodes for a session, including decayed and superseded rows.
|
|
781
|
+
- `getMemoryEdgesBySession(sessionId)`: read memory-level edges such as `conflicts` and `updates`.
|
|
782
|
+
- `getGraftRegistry(sessionId)`: read graft provenance entries for a session.
|
|
783
|
+
- `setSessionTags(sessionId, tags)`: replace the normalized tag set on existing topic and memory rows for a session.
|
|
585
784
|
|
|
586
785
|
### `llm`
|
|
587
786
|
|
|
@@ -628,6 +827,9 @@ drift: {
|
|
|
628
827
|
mode: "intent",
|
|
629
828
|
windowSize: 5,
|
|
630
829
|
driftSensitivity: "medium",
|
|
830
|
+
adaptiveSensitivity: {
|
|
831
|
+
enabled: false,
|
|
832
|
+
},
|
|
631
833
|
minSegmentMessages: 3,
|
|
632
834
|
llmAmbiguityDetection: false,
|
|
633
835
|
reentryDetection: true,
|
|
@@ -640,6 +842,7 @@ Controls topic boundary detection.
|
|
|
640
842
|
- `mode`: `"intent"` or `"window"`.
|
|
641
843
|
- `windowSize`: message window size for window mode.
|
|
642
844
|
- `driftSensitivity`: preferred sensitivity preset, one of `"low"`, `"medium"`, or `"high"`.
|
|
845
|
+
- `adaptiveSensitivity`: optional session-history based threshold tuning. Disabled by default.
|
|
643
846
|
- `threshold`: deprecated numeric threshold. It still works when `driftSensitivity` is not set, but MemoGrafter logs a one-time warning.
|
|
644
847
|
- `minSegmentMessages`: minimum messages before a boundary.
|
|
645
848
|
- `llmAmbiguityDetection`: optional LLM check for borderline topic shifts. Defaults to `false`.
|
|
@@ -658,6 +861,30 @@ Use `"medium"` first. Boundaries are cut when a drift score exceeds the resolved
|
|
|
658
861
|
|
|
659
862
|
If both `driftSensitivity` and `threshold` are provided, `driftSensitivity` wins.
|
|
660
863
|
|
|
864
|
+
#### Adaptive Sensitivity
|
|
865
|
+
|
|
866
|
+
Adaptive sensitivity is opt-in and keeps the configured `driftSensitivity` as its baseline. When enabled, MemoGrafter looks at recent saved segments for the session and nudges the resolved threshold by a small bounded step:
|
|
867
|
+
|
|
868
|
+
```ts
|
|
869
|
+
drift: {
|
|
870
|
+
mode: "intent",
|
|
871
|
+
driftSensitivity: "medium",
|
|
872
|
+
adaptiveSensitivity: {
|
|
873
|
+
enabled: true,
|
|
874
|
+
minSegments: 4,
|
|
875
|
+
lookbackSegments: 8,
|
|
876
|
+
targetSegmentMessages: {
|
|
877
|
+
min: 3,
|
|
878
|
+
max: 8,
|
|
879
|
+
},
|
|
880
|
+
adjustmentStep: 0.05,
|
|
881
|
+
maxAdjustment: 0.1,
|
|
882
|
+
},
|
|
883
|
+
}
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
If recent segments are consistently short, MemoGrafter raises the threshold slightly to reduce fragmentation. If recent segments are consistently long, it lowers the threshold slightly to split more readily. It does not adapt until enough segment history exists, and it skips adjustment when recent segment lengths are too erratic.
|
|
887
|
+
|
|
661
888
|
#### Reentry Detection
|
|
662
889
|
|
|
663
890
|
Reentry detection handles conversations that leave a topic and later return to it:
|
|
@@ -724,6 +951,20 @@ Enables an opt-in Redis cache for targeted recall. MemoGrafter creates one share
|
|
|
724
951
|
|
|
725
952
|
Recall cache keys include the session ID, `limit`, `minSimilarity`, and a deterministic hash of the query embedding. Redis failures are logged as warnings and recall falls back to PostgreSQL search. The cache is disabled unless this section is present.
|
|
726
953
|
|
|
954
|
+
When tag-aware recall is used, cache keys also include recall `scope`, `tagMode`, and the normalized tag list. This prevents untagged, session-filtered, and cross-session tagged recall from sharing cached search results.
|
|
955
|
+
|
|
956
|
+
## Manual Smoke Tests
|
|
957
|
+
|
|
958
|
+
From this repository, run the session-tagging smoke with a real PostgreSQL database:
|
|
959
|
+
|
|
960
|
+
```powershell
|
|
961
|
+
npx tsx --env-file=.env ./tests/manual/graft/session-tags-smoke.ts
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Use the forward-slash path in PowerShell. An unquoted backslash path can be collapsed before `tsx` receives it.
|
|
965
|
+
|
|
966
|
+
The smoke creates two tagged sessions, writes one memory into each, verifies current-session tag filtering with `getActiveNodes()`, and verifies cross-session project recall with `recall(..., { scope: "tagged" })`. If you run it repeatedly against the same database, tagged recall can return rows from previous smoke runs because those historical sessions are still present.
|
|
967
|
+
|
|
727
968
|
## Queue Mode
|
|
728
969
|
|
|
729
970
|
Without queue config, ingestion runs synchronously after `invoke()`.
|
|
@@ -856,6 +1097,10 @@ const retriever = new RetrieverPipeline(store, embedder, {
|
|
|
856
1097
|
limit: 8,
|
|
857
1098
|
minSimilarity: 0.55,
|
|
858
1099
|
tokenBudget: 1000,
|
|
1100
|
+
scoring: {
|
|
1101
|
+
similarityWeight: 0.7,
|
|
1102
|
+
confidenceWeight: 0.3,
|
|
1103
|
+
},
|
|
859
1104
|
});
|
|
860
1105
|
|
|
861
1106
|
const result = await retriever.run(
|
|
@@ -1112,6 +1357,10 @@ Main exports:
|
|
|
1112
1357
|
- `OpenAILLMAdapter`
|
|
1113
1358
|
- `OpenAIEmbedAdapter`
|
|
1114
1359
|
- `PostgresGraphStore`
|
|
1360
|
+
- `MemoGrafterCrawler`
|
|
1361
|
+
- `ConflictDetectionPass`
|
|
1362
|
+
- `DecayScoringPass`
|
|
1363
|
+
- `VersioningPass`
|
|
1115
1364
|
- `GrafterPipeline`
|
|
1116
1365
|
- `IngestPipeline`
|
|
1117
1366
|
- `RetrieverPipeline`
|
|
@@ -1119,16 +1368,19 @@ Main exports:
|
|
|
1119
1368
|
- `FleetAgentRecord`
|
|
1120
1369
|
- `RetrievalResult`
|
|
1121
1370
|
- `RetrieverConfig`
|
|
1371
|
+
- `TagFilterOptions`
|
|
1372
|
+
- `IngestOptions`
|
|
1122
1373
|
- public shared and fleet types
|
|
1123
1374
|
|
|
1124
1375
|
Useful `GraphStore` inspection methods:
|
|
1125
1376
|
|
|
1126
1377
|
- `getTopicNode(topicNodeId, sessionId?)`
|
|
1127
|
-
- `getNodesBySession(sessionId)`
|
|
1378
|
+
- `getNodesBySession(sessionId, options?)`
|
|
1128
1379
|
- `getSegmentsBySession(sessionId)`
|
|
1129
1380
|
- `getEdgesByType(sessionId, type)`
|
|
1130
1381
|
- `getEdgesBySession(sessionId)`
|
|
1131
1382
|
- `getMemoriesBySession(sessionId)`
|
|
1383
|
+
- `getMemoryEdgesBySession(sessionId)`
|
|
1132
1384
|
- `getSessionNodeCount(sessionId)`
|
|
1133
1385
|
- `getSessionIngestState(sessionId)`
|
|
1134
1386
|
|
|
@@ -1138,14 +1390,16 @@ Common `MemoGrafterAgent` methods:
|
|
|
1138
1390
|
- `invoke(message)`: send a user message and receive an assistant response.
|
|
1139
1391
|
- `getHistory()`: read local chat history.
|
|
1140
1392
|
- `getSessionId()`: read the current session ID.
|
|
1141
|
-
- `getGraphSnapshot()`: read nodes, edges, memories, session ID, and capture timestamp for visualization or inspection.
|
|
1142
|
-
- `getGraftRegistry()`: inspect provenance for grafted nodes in the current session.
|
|
1143
|
-
- `getActiveNodes()`: inspect topic nodes.
|
|
1144
|
-
- `getActiveSegments()`: inspect topic segments.
|
|
1145
|
-
- `
|
|
1146
|
-
- `
|
|
1147
|
-
- `
|
|
1148
|
-
- `
|
|
1149
|
-
- `
|
|
1150
|
-
- `
|
|
1151
|
-
- `
|
|
1393
|
+
- `getGraphSnapshot()`: read nodes, edges, memories, session ID, and capture timestamp for visualization or inspection.
|
|
1394
|
+
- `getGraftRegistry()`: inspect provenance for grafted nodes in the current session.
|
|
1395
|
+
- `getActiveNodes(options?)`: inspect topic nodes, optionally filtered by tags.
|
|
1396
|
+
- `getActiveSegments()`: inspect topic segments.
|
|
1397
|
+
- `setSessionTags(tags)`: replace tags on the current session and apply them to future ingested memories.
|
|
1398
|
+
- `getSessionTags()`: read the current agent's normalized session tags.
|
|
1399
|
+
- `clearSession()`: explicitly clear local history and stored session memory.
|
|
1400
|
+
- `recall(query, options?)`: retrieve structured memory by semantic query, optionally filtered by tags.
|
|
1401
|
+
- `graft(topicIds?)`: preview memory injection.
|
|
1402
|
+
- `ingestGraftedNodes(nodes)`: copy provided nodes into this agent.
|
|
1403
|
+
- `absorbFromAgent(sourceAgent, options)`: select and copy memory from another agent.
|
|
1404
|
+
- `removeGraft(nodeId)`: remove a registered graft node from the current session.
|
|
1405
|
+
- `close()`: close database and queue resources.
|
package/dist/MemoGrafter.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Redis } from "ioredis";
|
|
|
2
2
|
import { MemoGrafterFleet } from "./fleet/MemoGrafterFleet.js";
|
|
3
3
|
import type { MemoGrafterFleetOptions } from "./fleet/types.js";
|
|
4
4
|
import type { GraphStore } from "./store/index.js";
|
|
5
|
-
import type { AbsorbFromAgentOptions, EmbedAdapter, InjectionResult, LLMAdapter, MemoGrafterConfig, Message, TopicNode, TopicSegment } from "./types.js";
|
|
5
|
+
import type { AbsorbFromAgentOptions, EmbedAdapter, IngestOptions, InjectionResult, LLMAdapter, MemoGrafterConfig, Message, TopicNode, TopicSegment } from "./types.js";
|
|
6
6
|
export declare class MemoGrafter {
|
|
7
7
|
readonly llm: LLMAdapter;
|
|
8
8
|
readonly embedder: EmbedAdapter;
|
|
@@ -13,10 +13,13 @@ export declare class MemoGrafter {
|
|
|
13
13
|
private readonly ingestQueue;
|
|
14
14
|
constructor(config: MemoGrafterConfig);
|
|
15
15
|
initialize(): Promise<void>;
|
|
16
|
-
ingest(messages: Message[], sessionId: string): Promise<TopicNode[]>;
|
|
17
|
-
ingestNow(messages: Message[], sessionId: string): Promise<TopicNode[]>;
|
|
18
|
-
enqueueIngest(messages: Message[], sessionId: string): Promise<void>;
|
|
19
|
-
getTopics(sessionId: string
|
|
16
|
+
ingest(messages: Message[], sessionId: string, options?: IngestOptions): Promise<TopicNode[]>;
|
|
17
|
+
ingestNow(messages: Message[], sessionId: string, options?: IngestOptions): Promise<TopicNode[]>;
|
|
18
|
+
enqueueIngest(messages: Message[], sessionId: string, options?: IngestOptions): Promise<void>;
|
|
19
|
+
getTopics(sessionId: string, options?: {
|
|
20
|
+
tags?: string[];
|
|
21
|
+
tagMode?: "all" | "any";
|
|
22
|
+
}): Promise<{
|
|
20
23
|
nodes: TopicNode[];
|
|
21
24
|
segments: TopicSegment[];
|
|
22
25
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoGrafter.d.ts","sourceRoot":"","sources":["../src/MemoGrafter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAKhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,SAAS,EACT,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,WAAW;IACtB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,MAAM,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"MemoGrafter.d.ts","sourceRoot":"","sources":["../src/MemoGrafter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAKhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,SAAS,EACT,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,WAAW;IACtB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,MAAM,EAAE,iBAAiB;IAqDrC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAQjG,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAI9F,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASjG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAMzJ,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAIjE,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMrF,oBAAoB,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAmBpG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMpF,WAAW,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB;IAI9D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,uBAAuB;CAUhC"}
|
package/dist/MemoGrafter.js
CHANGED
|
@@ -22,6 +22,7 @@ export class MemoGrafter {
|
|
|
22
22
|
const llmAmbiguityDetection = config.drift?.llmAmbiguityDetection;
|
|
23
23
|
const reentryDetection = config.drift?.reentryDetection;
|
|
24
24
|
const reentryThreshold = config.drift?.reentryThreshold;
|
|
25
|
+
const adaptiveSensitivity = config.drift?.adaptiveSensitivity;
|
|
25
26
|
const topK = config.graph?.topK ?? 5;
|
|
26
27
|
const hopDepth = config.graph?.hopDepth ?? 1;
|
|
27
28
|
const bufferSize = config.inject?.bufferSize ?? 1;
|
|
@@ -51,6 +52,7 @@ export class MemoGrafter {
|
|
|
51
52
|
...(llmAmbiguityDetection !== undefined ? { llmAmbiguityDetection } : {}),
|
|
52
53
|
...(reentryDetection !== undefined ? { reentryDetection } : {}),
|
|
53
54
|
...(reentryThreshold !== undefined ? { reentryThreshold } : {}),
|
|
55
|
+
...(adaptiveSensitivity !== undefined ? { adaptiveSensitivity } : {}),
|
|
54
56
|
});
|
|
55
57
|
this.grafterPipeline = new GrafterPipeline(this.store, {
|
|
56
58
|
hopDepth,
|
|
@@ -62,24 +64,24 @@ export class MemoGrafter {
|
|
|
62
64
|
initialize() {
|
|
63
65
|
return this.store.initialize();
|
|
64
66
|
}
|
|
65
|
-
ingest(messages, sessionId) {
|
|
67
|
+
ingest(messages, sessionId, options = {}) {
|
|
66
68
|
if (this.ingestQueue) {
|
|
67
|
-
return this.enqueueIngest(messages, sessionId).then(() => []);
|
|
69
|
+
return this.enqueueIngest(messages, sessionId, options).then(() => []);
|
|
68
70
|
}
|
|
69
|
-
return this.ingestPipeline.run(messages, sessionId);
|
|
71
|
+
return this.ingestPipeline.run(messages, sessionId, options);
|
|
70
72
|
}
|
|
71
|
-
ingestNow(messages, sessionId) {
|
|
72
|
-
return this.ingestPipeline.run(messages, sessionId);
|
|
73
|
+
ingestNow(messages, sessionId, options = {}) {
|
|
74
|
+
return this.ingestPipeline.run(messages, sessionId, options);
|
|
73
75
|
}
|
|
74
|
-
async enqueueIngest(messages, sessionId) {
|
|
76
|
+
async enqueueIngest(messages, sessionId, options = {}) {
|
|
75
77
|
if (this.ingestQueue) {
|
|
76
|
-
await this.ingestQueue.enqueue(messages, sessionId);
|
|
78
|
+
await this.ingestQueue.enqueue(messages, sessionId, options);
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
|
-
await this.ingestPipeline.run(messages, sessionId);
|
|
81
|
+
await this.ingestPipeline.run(messages, sessionId, options);
|
|
80
82
|
}
|
|
81
|
-
async getTopics(sessionId) {
|
|
82
|
-
const nodes = await this.store.getNodesBySession(sessionId);
|
|
83
|
+
async getTopics(sessionId, options = {}) {
|
|
84
|
+
const nodes = await this.store.getNodesBySession(sessionId, options);
|
|
83
85
|
const segments = await this.store.getSegmentsBySession(sessionId);
|
|
84
86
|
return { nodes, segments };
|
|
85
87
|
}
|