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.
- package/README.md +81 -73
- package/USER_GUIDE.md +158 -30
- package/dist/MemoGrafterAgent.d.ts +8 -3
- package/dist/MemoGrafterAgent.d.ts.map +1 -1
- package/dist/MemoGrafterAgent.js +75 -23
- package/dist/MemoGrafterAgent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/pipeline/IngestPipeline.d.ts +2 -0
- package/dist/pipeline/IngestPipeline.d.ts.map +1 -1
- package/dist/pipeline/IngestPipeline.js +93 -17
- package/dist/pipeline/IngestPipeline.js.map +1 -1
- package/dist/store/GraphStore.d.ts +13 -1
- package/dist/store/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.d.ts +17 -1
- package/dist/store/postgres-pgvector/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.js +255 -0
- package/dist/store/postgres-pgvector/GraphStore.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/drift/cosineSimilarity.test.d.ts +2 -0
- package/dist/utils/drift/cosineSimilarity.test.d.ts.map +1 -0
- package/dist/utils/drift/cosineSimilarity.test.js +25 -0
- package/dist/utils/drift/cosineSimilarity.test.js.map +1 -0
- package/dist/utils/drift/vectorAvg.test.d.ts +2 -0
- package/dist/utils/drift/vectorAvg.test.d.ts.map +1 -0
- package/dist/utils/drift/vectorAvg.test.js +36 -0
- package/dist/utils/drift/vectorAvg.test.js.map +1 -0
- package/dist/utils/text/normalizeText.test.d.ts +2 -0
- package/dist/utils/text/normalizeText.test.d.ts.map +1 -0
- package/dist/utils/text/normalizeText.test.js +23 -0
- package/dist/utils/text/normalizeText.test.js.map +1 -0
- package/dist/utils/vector/vectorLiteral.test.d.ts +2 -0
- package/dist/utils/vector/vectorLiteral.test.d.ts.map +1 -0
- package/dist/utils/vector/vectorLiteral.test.js +28 -0
- package/dist/utils/vector/vectorLiteral.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,73 +1,81 @@
|
|
|
1
|
-
# MemoGrafter
|
|
2
|
-
[](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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
1
|
+
# MemoGrafter
|
|
2
|
+
[](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.
|
|
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
|
|
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.
|
|
255
|
-
2.
|
|
256
|
-
3.
|
|
257
|
-
4.
|
|
258
|
-
5. Adds the assistant response to history.
|
|
259
|
-
6. Queues ingestion of the
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
616
|
-
- `recentWindowSize`: number of newest raw chat messages to
|
|
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`
|
|
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
|
|
932
|
+
## Example Projects
|
|
840
933
|
|
|
841
|
-
This repository includes
|
|
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
|
|
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
|
|
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
|
-
- `
|
|
1018
|
-
- `
|
|
1019
|
-
- `
|
|
1020
|
-
- `
|
|
1021
|
-
- `
|
|
1022
|
-
- `
|
|
1023
|
-
- `
|
|
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
|
|
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":"
|
|
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"}
|