memo-grafter 0.2.1 → 0.2.3

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 (37) hide show
  1. package/README.md +81 -73
  2. package/USER_GUIDE.md +158 -30
  3. package/dist/MemoGrafterAgent.d.ts +8 -3
  4. package/dist/MemoGrafterAgent.d.ts.map +1 -1
  5. package/dist/MemoGrafterAgent.js +75 -23
  6. package/dist/MemoGrafterAgent.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/pipeline/IngestPipeline.d.ts +2 -0
  10. package/dist/pipeline/IngestPipeline.d.ts.map +1 -1
  11. package/dist/pipeline/IngestPipeline.js +93 -17
  12. package/dist/pipeline/IngestPipeline.js.map +1 -1
  13. package/dist/store/GraphStore.d.ts +13 -1
  14. package/dist/store/GraphStore.d.ts.map +1 -1
  15. package/dist/store/postgres-pgvector/GraphStore.d.ts +17 -1
  16. package/dist/store/postgres-pgvector/GraphStore.d.ts.map +1 -1
  17. package/dist/store/postgres-pgvector/GraphStore.js +255 -0
  18. package/dist/store/postgres-pgvector/GraphStore.js.map +1 -1
  19. package/dist/types.d.ts +34 -0
  20. package/dist/types.d.ts.map +1 -1
  21. package/dist/utils/drift/cosineSimilarity.test.d.ts +2 -0
  22. package/dist/utils/drift/cosineSimilarity.test.d.ts.map +1 -0
  23. package/dist/utils/drift/cosineSimilarity.test.js +25 -0
  24. package/dist/utils/drift/cosineSimilarity.test.js.map +1 -0
  25. package/dist/utils/drift/vectorAvg.test.d.ts +2 -0
  26. package/dist/utils/drift/vectorAvg.test.d.ts.map +1 -0
  27. package/dist/utils/drift/vectorAvg.test.js +36 -0
  28. package/dist/utils/drift/vectorAvg.test.js.map +1 -0
  29. package/dist/utils/text/normalizeText.test.d.ts +2 -0
  30. package/dist/utils/text/normalizeText.test.d.ts.map +1 -0
  31. package/dist/utils/text/normalizeText.test.js +23 -0
  32. package/dist/utils/text/normalizeText.test.js.map +1 -0
  33. package/dist/utils/vector/vectorLiteral.test.d.ts +2 -0
  34. package/dist/utils/vector/vectorLiteral.test.d.ts.map +1 -0
  35. package/dist/utils/vector/vectorLiteral.test.js +28 -0
  36. package/dist/utils/vector/vectorLiteral.test.js.map +1 -0
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -1,73 +1,81 @@
1
- # MemoGrafter
2
- [![npm version](https://img.shields.io/npm/v/memo-grafter.svg)](https://www.npmjs.com/package/memo-grafter)
3
-
4
- Structured memory for TypeScript chatbots.
5
-
6
- MemoGrafter helps chatbot applications remember conversations without stuffing every old message back into the prompt. It turns conversation history into topic-based memory, recalls relevant details later, and can copy useful memory from one chatbot or session into another.
7
-
8
- It is a memory framework, not an autonomous agent runtime. It does not run tools, schedule work, or decide goals for an agent.
9
-
10
- ## What It Is For
11
-
12
- - Chatbots that need long-running memory.
13
- - Assistants that should recall user preferences, prior context, and open questions.
14
- - Multi-chatbot or multi-session flows where selected memory can be grafted into another conversation.
15
- - TypeScript apps that need reusable memory, retrieval, and graph-backed conversation primitives.
16
-
17
- ## How It Works
18
-
19
- ```text
20
- chat messages
21
- -> topic-based memory
22
- -> graph links
23
- -> relevant recall
24
- -> optional memory grafting
25
- ```
26
-
27
- MemoGrafter stores conversation turns, detects topic changes, summarizes useful context, links related memories, and retrieves or grafts memory when needed.
28
-
29
- ## Install
30
-
31
- ```bash
32
- npm install memo-grafter
33
- ```
34
-
35
- MemoGrafter runs server-side on Node.js. The built-in storage backend uses PostgreSQL with `pgvector`.
36
-
37
- ## Minimal Example
38
-
39
- ```ts
40
- import "dotenv/config";
41
-
42
- import {
43
- MemoGrafterAgent,
44
- OpenAIEmbedAdapter,
45
- OpenAILLMAdapter,
46
- } from "memo-grafter";
47
-
48
- const agent = new MemoGrafterAgent({
49
- db: { connectionString: process.env.DATABASE_URL! },
50
- llm: new OpenAILLMAdapter("gpt-4o"),
51
- embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
52
- });
53
-
54
- await agent.initialize();
55
-
56
- await agent.invoke("I am planning a Japan trip.");
57
- await agent.invoke("I like quiet towns, bookstores, and local cafes.");
58
-
59
- const recall = await agent.recall("travel preferences");
60
- console.log(recall.facts);
61
-
62
- await agent.close();
63
- ```
64
-
65
- ## Learn More
66
-
67
- - [USER_GUIDE.md](https://github.com/mayhemking007/memo-grafter/blob/main/USER_GUIDE.md) covers setup, configuration, adapters, queue mode, fleet APIs, examples, and troubleshooting.
68
- - [ARCHITECTURE.md](https://github.com/mayhemking007/memo-grafter/blob/main/ARCHITECTURE.md) explains the current high-level implementation.
69
- - `examples` contains runnable demo.
70
-
71
- ## License
72
-
73
- MIT
1
+ # MemoGrafter
2
+ [![npm version](https://img.shields.io/npm/v/memo-grafter.svg)](https://www.npmjs.com/package/memo-grafter)
3
+
4
+ Structured memory for TypeScript chatbots.
5
+
6
+ MemoGrafter helps chatbot applications remember conversations without stuffing every old message back into the prompt. It turns conversation history into topic-based memory, recalls relevant details later, and can copy useful memory from one chatbot or session into another.
7
+
8
+ It is a memory framework, not an autonomous agent runtime. It does not run tools, schedule work, or decide goals for an agent.
9
+
10
+ MemoGrafter builds the memory graph incrementally. New chatbot turns append topic and memory nodes to the existing graph instead of clearing and rebuilding the session on every response, so grafted and externally enriched memory can survive later conversation turns. Use `clearSession()` explicitly when you want to reset an agent's local history and stored session memory.
11
+
12
+ ## Playground
13
+
14
+ - Try the [MemoGrafter Playground](https://mgplayground-green.vercel.app/).
15
+ - View the playground demo repo at [mayhemking007/mg-demo](https://github.com/mayhemking007/mg-demo).
16
+
17
+ ## What It Is For
18
+
19
+ - Chatbots that need long-running memory.
20
+ - Assistants that should recall user preferences, prior context, and open questions.
21
+ - Multi-chatbot or multi-session flows where selected memory can be grafted into another conversation.
22
+ - TypeScript apps that need reusable memory, retrieval, and graph-backed conversation primitives.
23
+
24
+ ## How It Works
25
+
26
+ ```text
27
+ chat messages
28
+ -> topic-based memory
29
+ -> graph links
30
+ -> relevant recall
31
+ -> optional memory grafting
32
+ ```
33
+
34
+ MemoGrafter stores conversation turns, tracks which messages have already been ingested, detects topic changes for new turns with recent context, summarizes useful context, links related memories, and retrieves or grafts memory when needed.
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ npm install memo-grafter
40
+ ```
41
+
42
+ MemoGrafter runs server-side on Node.js. The built-in storage backend uses PostgreSQL with `pgvector`.
43
+
44
+ ## Minimal Example
45
+
46
+ ```ts
47
+ import "dotenv/config";
48
+
49
+ import {
50
+ MemoGrafterAgent,
51
+ OpenAIEmbedAdapter,
52
+ OpenAILLMAdapter,
53
+ } from "memo-grafter";
54
+
55
+ const agent = new MemoGrafterAgent({
56
+ db: { connectionString: process.env.DATABASE_URL! },
57
+ llm: new OpenAILLMAdapter("gpt-4o"),
58
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
59
+ });
60
+
61
+ await agent.initialize();
62
+
63
+ await agent.invoke("I am planning a Japan trip.");
64
+ await agent.invoke("I like quiet towns, bookstores, and local cafes.");
65
+
66
+ const recall = await agent.recall("travel preferences");
67
+ console.log(recall.facts);
68
+
69
+ await agent.close();
70
+ ```
71
+
72
+ ## Learn More
73
+
74
+ - [USER_GUIDE.md](https://github.com/mayhemking007/memo-grafter/blob/main/USER_GUIDE.md) covers setup, configuration, adapters, queue mode, fleet APIs, examples, and troubleshooting.
75
+ - [ARCHITECTURE.md](https://github.com/mayhemking007/memo-grafter/blob/main/ARCHITECTURE.md) explains the current high-level implementation.
76
+ - `examples/basic-chat-memory` is the simplest runnable single-agent memory demo.
77
+ - `examples/chatbot-memory-demo` shows the larger two-agent grafting workflow.
78
+
79
+ ## License
80
+
81
+ MIT
package/USER_GUIDE.md CHANGED
@@ -8,6 +8,8 @@ The project is intentionally focused. MemoGrafter is a chatbot memory framework,
8
8
 
9
9
  The most important idea is memory grafting. A chatbot can build useful memory during one conversation, and another chatbot can absorb only the relevant parts.
10
10
 
11
+ MemoGrafter ingests conversation memory incrementally. New turns append topic nodes, memory nodes, and graph edges to the existing session graph instead of clearing and rebuilding the graph on every response. This keeps grafted memory and future external graph enrichment durable across normal chatbot turns.
12
+
11
13
  ## Requirements
12
14
 
13
15
  - Node.js 18 or newer.
@@ -82,9 +84,11 @@ Current v1 tables:
82
84
  - `mg_topic_nodes`
83
85
  - `mg_topic_edges`
84
86
  - `mg_memory_nodes`
85
- - `mg_memory_edges`
86
- - `mg_fleets`
87
- - `mg_fleet_agents`
87
+ - `mg_memory_edges`
88
+ - `mg_fleets`
89
+ - `mg_fleet_agents`
90
+ - `mg_session_ingest_state`
91
+ - `mg_graft_registry`
88
92
 
89
93
  ## Quick Start
90
94
 
@@ -140,7 +144,9 @@ export interface Message {
140
144
  }
141
145
  ```
142
146
 
143
- `MemoGrafterAgent` keeps an in-memory user/assistant history for the current session and stores messages in PostgreSQL during ingestion. System messages can be added to LLM calls internally when memory recall is pinned into an overflowing context window.
147
+ `MemoGrafterAgent` keeps an in-memory user/assistant history for the current session and stores messages in PostgreSQL during ingestion. When a session already has memory graph content, `invoke()` can add a system message with recalled facts before the LLM call.
148
+
149
+ Ingestion tracks the last message index that has been processed for each session. Re-running ingestion with the same history is a no-op for graph creation, while later turns append new graph state.
144
150
 
145
151
  ### Segments
146
152
 
@@ -208,13 +214,17 @@ Edges are stored in `mg_topic_edges`.
208
214
 
209
215
  ### Grafting
210
216
 
211
- Grafting is the process of selecting memory nodes and turning them into useful context for another prompt or another chatbot.
217
+ Grafting is the process of selecting topic nodes and turning them into useful context for another prompt or another chatbot.
212
218
 
213
219
  There are two common forms:
214
220
 
215
221
  - Preview memory with `graft()`.
216
222
  - Copy memory into another chatbot with `absorbFromAgent()` or `ingestGraftedNodes()`.
217
223
 
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.
227
+
218
228
  ## Using MemoGrafterAgent
219
229
 
220
230
  `MemoGrafterAgent` is the easiest API to start with.
@@ -251,17 +261,31 @@ await agent.close();
251
261
 
252
262
  On every call, `invoke()`:
253
263
 
254
- 1. Adds the user message to local history.
255
- 2. Builds the message list for the LLM.
256
- 3. If history is under the configured budget, sends the raw local history.
257
- 4. If history crosses the overflow threshold, calls targeted recall using recent conversation context, prepends the recall result as one pinned system message, and keeps only the recent raw message window.
258
- 5. Adds the assistant response to history.
259
- 6. Queues ingestion of the updated conversation into the memory graph.
264
+ 1. Checks whether the current session has topic nodes in the memory graph.
265
+ 2. If graph content exists, calls targeted recall using the current user message.
266
+ 3. Prepends the recalled memory prompt as a system message when recall returns matching facts.
267
+ 4. Builds the LLM message list from the optional memory system message, the recent raw history window, and the current user message.
268
+ 5. Adds the user message and assistant response to local history after the LLM response.
269
+ 6. Queues ingestion of only the newly added conversation turns into the memory graph.
260
270
 
261
- The overflow threshold is 80% of `inject.tokenBudget`. Recall failures are logged as warnings and fall back to the recent raw message window, so a retrieval or embedder problem should not crash the foreground chatbot turn.
271
+ Recall is skipped entirely when the session has no topic nodes yet. This avoids an unnecessary embed and vector search on the first turn or while async ingestion has not produced graph content.
272
+
273
+ Recall failures are logged as warnings and fall back to raw history only, so a retrieval or embedder problem should not crash the foreground chatbot turn.
262
274
 
263
275
  On the first turn there may be no memory to recall. Later turns can use memory created from earlier turns once ingestion has completed.
264
276
 
277
+ Normal ingestion does not call `clearSession()`. Existing topic nodes, grafted nodes, memory rows, and graph edges are preserved unless you explicitly clear the session.
278
+
279
+ ### Clearing A Session
280
+
281
+ Use `clearSession()` when you intentionally want to reset an agent:
282
+
283
+ ```ts
284
+ await agent.clearSession();
285
+ ```
286
+
287
+ 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
+
265
289
  ### Targeted Recall
266
290
 
267
291
  Use `recall()` when you want to retrieve structured memory by meaning without asking the LLM to produce an answer.
@@ -298,12 +322,38 @@ Options:
298
322
 
299
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.
300
324
 
301
- `MemoGrafterAgent.invoke()` also calls `recall()` internally when local history overflows the configured history budget. In that automatic path, the returned `systemPrompt` is pinned as a single system message before the recent raw chat window.
325
+ `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`.
302
326
 
303
327
  If you call `recall()` immediately after `invoke()`, it only sees memory that has already been ingested into storage. In queue mode, wait for your background worker to finish before expecting newly created memories to appear.
304
328
 
305
329
  ## Inspecting Memory
306
330
 
331
+ Read a complete session graph snapshot:
332
+
333
+ ```ts
334
+ const snapshot = await agent.getGraphSnapshot();
335
+
336
+ 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.capturedAt);
342
+ ```
343
+
344
+ `getGraphSnapshot()` returns a `GraphSnapshot`:
345
+
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
+ - `capturedAt`: ISO timestamp for when the snapshot was produced.
352
+
353
+ 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.
354
+
355
+ 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.
356
+
307
357
  Read active topic nodes:
308
358
 
309
359
  ```ts
@@ -397,6 +447,38 @@ const response = await writingBot.invoke(
397
447
  console.log(response);
398
448
  ```
399
449
 
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.
481
+
400
482
  ### Absorb By Semantic Prompt
401
483
 
402
484
  ```ts
@@ -458,6 +540,8 @@ const agent = new MemoGrafterAgent({
458
540
  bufferSize: 4,
459
541
  tokenBudget: 1500,
460
542
  recentWindowSize: 20,
543
+ recallLimit: 6,
544
+ recallMinSimilarity: 0.55,
461
545
  },
462
546
  cache: {
463
547
  connectionString: process.env.REDIS_URL!,
@@ -495,6 +579,9 @@ Useful store inspection methods include:
495
579
  - `getTopicNode(topicNodeId, sessionId?)`: read one topic node by ID.
496
580
  - `getSegmentsBySession(sessionId)`: read topic segments for a session.
497
581
  - `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
+ - `getGraftRegistry(sessionId)`: read graft provenance entries for a session.
498
585
 
499
586
  ### `llm`
500
587
 
@@ -583,7 +670,7 @@ Without reentry detection, the later database discussion is just another topic n
583
670
 
584
671
  This helps graph traversal and memory injection recover earlier related context. A later question about connection pooling can still be connected to the original PostgreSQL/ACID discussion.
585
672
 
586
- Reentry edges are written between the current rebuilt topic nodes. They do not point at deleted nodes from previous ingestion passes.
673
+ Reentry edges are written between newly ingested topic nodes, and can also point from a new node back to an existing durable topic node when the detector recognizes a return to earlier context.
587
674
 
588
675
  ### `graph`
589
676
 
@@ -606,16 +693,20 @@ inject: {
606
693
  bufferSize: 4,
607
694
  tokenBudget: 1500,
608
695
  recentWindowSize: 20,
696
+ recallLimit: 6,
697
+ recallMinSimilarity: 0.55,
609
698
  }
610
699
  ```
611
700
 
612
- Controls memory prompt sizing and the raw history window kept when chat history overflows.
701
+ Controls memory prompt sizing, invoke-time recall, and the raw history window sent to the LLM.
613
702
 
614
703
  - `bufferSize`: nearby raw messages to include.
615
- - `tokenBudget`: approximate token budget used for memory prompts and agent history overflow checks. `MemoGrafterAgent` starts overflow handling at 80% of this value.
616
- - `recentWindowSize`: number of newest raw chat messages to keep after the pinned recall block during overflow. Defaults to `20`.
704
+ - `tokenBudget`: approximate token budget used for graft prompt assembly.
705
+ - `recentWindowSize`: number of newest raw chat messages to send after the optional invoke-time memory system message. Defaults to `20`.
706
+ - `recallLimit`: max memory facts to fetch for automatic invoke-time recall. Defaults to `6`.
707
+ - `recallMinSimilarity`: similarity floor for automatic invoke-time recall. Defaults to `0.55`.
617
708
 
618
- When `MemoGrafterAgent` detects overflow, it builds a recall query from the last six message contents, calls recall with `{ limit: 5, minSimilarity: 0.65 }`, prepends the returned memory prompt as a system message, and keeps the last `recentWindowSize` raw messages. If recall fails, it uses only that recent raw window.
709
+ When `MemoGrafterAgent.invoke()` sees existing topic nodes for the session, it calls recall with the current user message, prepends the returned memory prompt as a system message when facts are found, and keeps the last `recentWindowSize` raw messages. If recall fails or returns no facts, it uses only that recent raw window plus the current user message.
619
710
 
620
711
  ### `cache`
621
712
 
@@ -656,6 +747,8 @@ const agent = new MemoGrafterAgent({
656
747
 
657
748
  Queue mode is useful when ingestion becomes too slow to run inline. Redis connection problems are logged as warnings and should not throw from normal chatbot invocation.
658
749
 
750
+ Whether ingestion runs inline or through the queue, MemoGrafter uses the stored ingest cursor to skip message ranges that have already been processed. Queue retries should therefore avoid creating duplicate topic nodes for the same message range.
751
+
659
752
  ## Custom Adapters
660
753
 
661
754
  You can use any model provider if you implement the public adapter interfaces.
@@ -741,7 +834,7 @@ Breaking changes to pipeline internals may occur in minor versions.
741
834
 
742
835
  Available pipeline exports:
743
836
 
744
- - `IngestPipeline`: segments messages, builds topic nodes, extracts memory nodes, and writes graph edges.
837
+ - `IngestPipeline`: incrementally segments new messages, builds topic nodes, extracts memory nodes, and writes graph edges.
745
838
  - `RetrieverPipeline`: embeds a query, searches memory nodes, and returns a structured `RetrievalResult`.
746
839
  - `GrafterPipeline`: traverses the topic graph and assembles a token-budget-fitted system prompt.
747
840
 
@@ -836,15 +929,29 @@ await conductor.graftByPrompt("invoice credit policy", technical, {
836
929
  });
837
930
  ```
838
931
 
839
- ## Example Project
932
+ ## Example Projects
840
933
 
841
- This repository includes a runnable example:
934
+ This repository includes two runnable examples:
842
935
 
843
936
  ```text
937
+ examples/basic-chat-memory
844
938
  examples/chatbot-memory-demo
845
939
  ```
846
940
 
847
- Run it:
941
+ Run the single-agent memory demo:
942
+
943
+ ```bash
944
+ cd D:/cohort/projects/project-memoGrafter
945
+ npm install
946
+ npm run build
947
+
948
+ cd examples/basic-chat-memory
949
+ npm install
950
+ cp .env.example .env
951
+ npm run dev
952
+ ```
953
+
954
+ Run the two-agent grafting demo:
848
955
 
849
956
  ```bash
850
957
  cd D:/cohort/projects/project-memoGrafter
@@ -953,6 +1060,18 @@ const result = await agent.recall("Japan travel preferences", {
953
1060
  });
954
1061
  ```
955
1062
 
1063
+ For grafted sessions, also confirm that the source topic had active memory nodes before it was absorbed. Absorbing copies active memory rows, but it cannot create facts for a topic if extraction produced only a topic summary and no `mg_memory_nodes` rows.
1064
+
1065
+ ### Duplicate Or Unexpected Topic Nodes
1066
+
1067
+ MemoGrafter processes only messages after the stored ingest cursor. If you see duplicate topic ranges:
1068
+
1069
+ - Confirm your database has the `mg_session_ingest_state` table.
1070
+ - Confirm the same session ID is being reused for the same agent.
1071
+ - Check whether `clearSession()` was called, which resets the cursor and removes stored session data.
1072
+
1073
+ Incremental ingest can still create semantically similar topic nodes over time. That is expected; node merge and graph compaction are separate maintenance features.
1074
+
956
1075
  ### Redis Warnings
957
1076
 
958
1077
  Redis is only required when you pass `queue` or `cache` config. If you do not need background ingestion or recall caching, remove those sections.
@@ -971,7 +1090,8 @@ Practical notes:
971
1090
  - Use PostgreSQL with `pgvector` enabled.
972
1091
  - Tune `tokenBudget` to control prompt size and cost.
973
1092
  - Use queue mode if ingestion becomes slow.
974
- - Use the optional recall cache for long sessions with repeated or automatic overflow recall.
1093
+ - Use `clearSession()` only for intentional resets; normal ingestion preserves the graph incrementally.
1094
+ - Use the optional recall cache for long sessions with repeated direct or invoke-time recall.
975
1095
  - Store your own user/session mapping outside MemoGrafter.
976
1096
  - Call `close()` during graceful shutdown.
977
1097
  - Do not expose database credentials or OpenAI keys to browser code.
@@ -1007,6 +1127,10 @@ Useful `GraphStore` inspection methods:
1007
1127
  - `getNodesBySession(sessionId)`
1008
1128
  - `getSegmentsBySession(sessionId)`
1009
1129
  - `getEdgesByType(sessionId, type)`
1130
+ - `getEdgesBySession(sessionId)`
1131
+ - `getMemoriesBySession(sessionId)`
1132
+ - `getSessionNodeCount(sessionId)`
1133
+ - `getSessionIngestState(sessionId)`
1010
1134
 
1011
1135
  Common `MemoGrafterAgent` methods:
1012
1136
 
@@ -1014,10 +1138,14 @@ Common `MemoGrafterAgent` methods:
1014
1138
  - `invoke(message)`: send a user message and receive an assistant response.
1015
1139
  - `getHistory()`: read local chat history.
1016
1140
  - `getSessionId()`: read the current session ID.
1017
- - `getActiveNodes()`: inspect topic nodes.
1018
- - `getActiveSegments()`: inspect topic segments.
1019
- - `recall(query, options?)`: retrieve structured memory by semantic query.
1020
- - `graft(topicIds?)`: preview memory injection.
1021
- - `ingestGraftedNodes(nodes)`: copy provided nodes into this agent.
1022
- - `absorbFromAgent(sourceAgent, options)`: select and copy memory from another agent.
1023
- - `close()`: close database and queue resources.
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
+ - `clearSession()`: explicitly clear local history and stored session memory.
1146
+ - `recall(query, options?)`: retrieve structured memory by semantic query.
1147
+ - `graft(topicIds?)`: preview memory injection.
1148
+ - `ingestGraftedNodes(nodes)`: copy provided nodes into this agent.
1149
+ - `absorbFromAgent(sourceAgent, options)`: select and copy memory from another agent.
1150
+ - `removeGraft(nodeId)`: remove a registered graft node from the current session.
1151
+ - `close()`: close database and queue resources.
@@ -1,11 +1,12 @@
1
- import type { AbsorbFromAgentOptions, InjectionResult, MemoGrafterConfig, Message, RetrievalResult, RetrieverConfig, TopicNode, TopicSegment } from "./types.js";
1
+ import type { AbsorbFromAgentOptions, GraftRegistryEntry, GraphSnapshot, InjectionResult, MemoGrafterConfig, Message, RetrievalResult, RetrieverConfig, TopicNode, TopicSegment } from "./types.js";
2
2
  export declare class MemoGrafterAgent {
3
3
  private readonly core;
4
4
  private readonly sessionId;
5
5
  private readonly history;
6
6
  private readonly baseSystemPrompt;
7
- private readonly historyTokenBudget;
8
7
  private readonly recentWindowSize;
8
+ private readonly recallLimit;
9
+ private readonly recallMinSimilarity;
9
10
  private readonly cacheConfig;
10
11
  private pendingIngest;
11
12
  constructor(config: MemoGrafterConfig);
@@ -15,12 +16,16 @@ export declare class MemoGrafterAgent {
15
16
  getSessionId(): string;
16
17
  getActiveNodes(): Promise<TopicNode[]>;
17
18
  getActiveSegments(): Promise<TopicSegment[]>;
19
+ getGraphSnapshot(): Promise<GraphSnapshot>;
20
+ getGraftRegistry(): Promise<GraftRegistryEntry[]>;
21
+ removeGraft(nodeId: string): Promise<void>;
22
+ clearSession(): Promise<void>;
18
23
  graft(topicIds?: string[]): Promise<InjectionResult>;
19
24
  ingestGraftedNodes(nodes: TopicNode[]): Promise<TopicNode[]>;
20
25
  recall(query: string, options?: RetrieverConfig): Promise<RetrievalResult>;
21
26
  absorbFromAgent(sourceAgent: MemoGrafterAgent, options?: AbsorbFromAgentOptions): Promise<TopicNode[]>;
22
27
  private enqueueBackgroundIngest;
23
- private buildHistory;
28
+ private _buildMemoryContext;
24
29
  close(): Promise<void>;
25
30
  }
26
31
  //# sourceMappingURL=MemoGrafterAgent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MemoGrafterAgent.d.ts","sourceRoot":"","sources":["../src/MemoGrafterAgent.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,eAAe,EACf,eAAe,EACf,SAAS,EACT,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,aAAa,CAAoC;gBAE7C,MAAM,EAAE,iBAAiB;IAQrC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYlD,UAAU,IAAI,OAAO,EAAE;IAIvB,YAAY,IAAI,MAAM;IAIhB,cAAc,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAMtC,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAM5C,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAO1D,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAItD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAkB9E,eAAe,CAAC,WAAW,EAAE,gBAAgB,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAKhH,OAAO,CAAC,uBAAuB;YAUjB,YAAY;IA4B1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvB"}
1
+ {"version":3,"file":"MemoGrafterAgent.d.ts","sourceRoot":"","sources":["../src/MemoGrafterAgent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,eAAe,EACf,eAAe,EACf,SAAS,EACT,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,aAAa,CAAoC;gBAE7C,MAAM,EAAE,iBAAiB;IASrC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBlD,UAAU,IAAI,OAAO,EAAE;IAIvB,YAAY,IAAI,MAAM;IAIhB,cAAc,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAMtC,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAM5C,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC;IAiC1C,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAKjD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1C,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAO1D,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAItD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAkB9E,eAAe,CAAC,WAAW,EAAE,gBAAgB,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAKhH,OAAO,CAAC,uBAAuB;YAUjB,mBAAmB;IAsBjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvB"}