memo-grafter 0.2.2 → 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 +165 -64
- package/dist/MemoGrafterAgent.d.ts +7 -3
- package/dist/MemoGrafterAgent.d.ts.map +1 -1
- package/dist/MemoGrafterAgent.js +62 -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 +11 -1
- package/dist/store/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.d.ts +15 -1
- package/dist/store/postgres-pgvector/GraphStore.d.ts.map +1 -1
- package/dist/store/postgres-pgvector/GraphStore.js +229 -0
- package/dist/store/postgres-pgvector/GraphStore.js.map +1 -1
- package/dist/types.d.ts +27 -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.
|
|
270
|
+
|
|
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.
|
|
260
272
|
|
|
261
|
-
|
|
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,38 +322,42 @@ 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
|
-
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
|
-
|
|
305
|
-
## Inspecting Memory
|
|
306
|
-
|
|
307
|
-
Read a complete session graph snapshot:
|
|
308
|
-
|
|
309
|
-
```ts
|
|
310
|
-
const snapshot = await agent.getGraphSnapshot();
|
|
311
|
-
|
|
312
|
-
console.log(snapshot.sessionId);
|
|
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.
|
|
328
|
+
|
|
329
|
+
## Inspecting Memory
|
|
330
|
+
|
|
331
|
+
Read a complete session graph snapshot:
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
const snapshot = await agent.getGraphSnapshot();
|
|
335
|
+
|
|
336
|
+
console.log(snapshot.sessionId);
|
|
313
337
|
console.log(snapshot.nodes);
|
|
338
|
+
console.log(snapshot.snapshotNodes);
|
|
314
339
|
console.log(snapshot.edges);
|
|
315
340
|
console.log(snapshot.memories);
|
|
316
341
|
console.log(snapshot.capturedAt);
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
`getGraphSnapshot()` returns a `GraphSnapshot`:
|
|
320
|
-
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`getGraphSnapshot()` returns a `GraphSnapshot`:
|
|
345
|
+
|
|
321
346
|
- `sessionId`: current agent session ID.
|
|
322
347
|
- `nodes`: active topic nodes for the session.
|
|
348
|
+
- `snapshotNodes`: active topic nodes wrapped with provenance metadata when a node came from a graft.
|
|
323
349
|
- `edges`: topic edges where either endpoint belongs to a session topic node.
|
|
324
350
|
- `memories`: all memory nodes for the session, including decayed or superseded rows.
|
|
325
351
|
- `capturedAt`: ISO timestamp for when the snapshot was produced.
|
|
326
352
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
Read active topic nodes:
|
|
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.
|
|
330
354
|
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
|
|
357
|
+
Read active topic nodes:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const nodes = await agent.getActiveNodes();
|
|
333
361
|
|
|
334
362
|
for (const node of nodes) {
|
|
335
363
|
console.log({
|
|
@@ -419,6 +447,38 @@ const response = await writingBot.invoke(
|
|
|
419
447
|
console.log(response);
|
|
420
448
|
```
|
|
421
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
|
+
|
|
422
482
|
### Absorb By Semantic Prompt
|
|
423
483
|
|
|
424
484
|
```ts
|
|
@@ -480,6 +540,8 @@ const agent = new MemoGrafterAgent({
|
|
|
480
540
|
bufferSize: 4,
|
|
481
541
|
tokenBudget: 1500,
|
|
482
542
|
recentWindowSize: 20,
|
|
543
|
+
recallLimit: 6,
|
|
544
|
+
recallMinSimilarity: 0.55,
|
|
483
545
|
},
|
|
484
546
|
cache: {
|
|
485
547
|
connectionString: process.env.REDIS_URL!,
|
|
@@ -511,14 +573,15 @@ const store: GraphStore = new PostgresGraphStore(process.env.DATABASE_URL!);
|
|
|
511
573
|
|
|
512
574
|
`GraphStore` is the public storage interface. `PostgresGraphStore` is the default PostgreSQL and pgvector implementation.
|
|
513
575
|
|
|
514
|
-
Useful store inspection methods include:
|
|
515
|
-
|
|
516
|
-
- `getNodesBySession(sessionId)`: read topic nodes for a session.
|
|
517
|
-
- `getTopicNode(topicNodeId, sessionId?)`: read one topic node by ID.
|
|
518
|
-
- `getSegmentsBySession(sessionId)`: read topic segments for a session.
|
|
519
|
-
- `getEdgesByType(sessionId, type)`: inspect graph edges such as `"reentry"`, `"semantic"`, `"temporal"`, or `"grafted"`.
|
|
576
|
+
Useful store inspection methods include:
|
|
577
|
+
|
|
578
|
+
- `getNodesBySession(sessionId)`: read topic nodes for a session.
|
|
579
|
+
- `getTopicNode(topicNodeId, sessionId?)`: read one topic node by ID.
|
|
580
|
+
- `getSegmentsBySession(sessionId)`: read topic segments for a session.
|
|
581
|
+
- `getEdgesByType(sessionId, type)`: inspect graph edges such as `"reentry"`, `"semantic"`, `"temporal"`, or `"grafted"`.
|
|
520
582
|
- `getEdgesBySession(sessionId)`: read all topic edges where either endpoint belongs to the session's topic nodes.
|
|
521
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.
|
|
522
585
|
|
|
523
586
|
### `llm`
|
|
524
587
|
|
|
@@ -607,7 +670,7 @@ Without reentry detection, the later database discussion is just another topic n
|
|
|
607
670
|
|
|
608
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.
|
|
609
672
|
|
|
610
|
-
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.
|
|
611
674
|
|
|
612
675
|
### `graph`
|
|
613
676
|
|
|
@@ -630,16 +693,20 @@ inject: {
|
|
|
630
693
|
bufferSize: 4,
|
|
631
694
|
tokenBudget: 1500,
|
|
632
695
|
recentWindowSize: 20,
|
|
696
|
+
recallLimit: 6,
|
|
697
|
+
recallMinSimilarity: 0.55,
|
|
633
698
|
}
|
|
634
699
|
```
|
|
635
700
|
|
|
636
|
-
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.
|
|
637
702
|
|
|
638
703
|
- `bufferSize`: nearby raw messages to include.
|
|
639
|
-
- `tokenBudget`: approximate token budget used for
|
|
640
|
-
- `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`.
|
|
641
708
|
|
|
642
|
-
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.
|
|
643
710
|
|
|
644
711
|
### `cache`
|
|
645
712
|
|
|
@@ -680,6 +747,8 @@ const agent = new MemoGrafterAgent({
|
|
|
680
747
|
|
|
681
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.
|
|
682
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
|
+
|
|
683
752
|
## Custom Adapters
|
|
684
753
|
|
|
685
754
|
You can use any model provider if you implement the public adapter interfaces.
|
|
@@ -765,7 +834,7 @@ Breaking changes to pipeline internals may occur in minor versions.
|
|
|
765
834
|
|
|
766
835
|
Available pipeline exports:
|
|
767
836
|
|
|
768
|
-
- `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.
|
|
769
838
|
- `RetrieverPipeline`: embeds a query, searches memory nodes, and returns a structured `RetrievalResult`.
|
|
770
839
|
- `GrafterPipeline`: traverses the topic graph and assembles a token-budget-fitted system prompt.
|
|
771
840
|
|
|
@@ -860,15 +929,29 @@ await conductor.graftByPrompt("invoice credit policy", technical, {
|
|
|
860
929
|
});
|
|
861
930
|
```
|
|
862
931
|
|
|
863
|
-
## Example
|
|
932
|
+
## Example Projects
|
|
864
933
|
|
|
865
|
-
This repository includes
|
|
934
|
+
This repository includes two runnable examples:
|
|
866
935
|
|
|
867
936
|
```text
|
|
937
|
+
examples/basic-chat-memory
|
|
868
938
|
examples/chatbot-memory-demo
|
|
869
939
|
```
|
|
870
940
|
|
|
871
|
-
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:
|
|
872
955
|
|
|
873
956
|
```bash
|
|
874
957
|
cd D:/cohort/projects/project-memoGrafter
|
|
@@ -977,6 +1060,18 @@ const result = await agent.recall("Japan travel preferences", {
|
|
|
977
1060
|
});
|
|
978
1061
|
```
|
|
979
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
|
+
|
|
980
1075
|
### Redis Warnings
|
|
981
1076
|
|
|
982
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.
|
|
@@ -995,7 +1090,8 @@ Practical notes:
|
|
|
995
1090
|
- Use PostgreSQL with `pgvector` enabled.
|
|
996
1091
|
- Tune `tokenBudget` to control prompt size and cost.
|
|
997
1092
|
- Use queue mode if ingestion becomes slow.
|
|
998
|
-
- 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.
|
|
999
1095
|
- Store your own user/session mapping outside MemoGrafter.
|
|
1000
1096
|
- Call `close()` during graceful shutdown.
|
|
1001
1097
|
- Do not expose database credentials or OpenAI keys to browser code.
|
|
@@ -1025,26 +1121,31 @@ Main exports:
|
|
|
1025
1121
|
- `RetrieverConfig`
|
|
1026
1122
|
- public shared and fleet types
|
|
1027
1123
|
|
|
1028
|
-
Useful `GraphStore` inspection methods:
|
|
1029
|
-
|
|
1030
|
-
- `getTopicNode(topicNodeId, sessionId?)`
|
|
1031
|
-
- `getNodesBySession(sessionId)`
|
|
1032
|
-
- `getSegmentsBySession(sessionId)`
|
|
1033
|
-
- `getEdgesByType(sessionId, type)`
|
|
1034
|
-
- `getEdgesBySession(sessionId)`
|
|
1035
|
-
- `getMemoriesBySession(sessionId)`
|
|
1036
|
-
|
|
1037
|
-
|
|
1124
|
+
Useful `GraphStore` inspection methods:
|
|
1125
|
+
|
|
1126
|
+
- `getTopicNode(topicNodeId, sessionId?)`
|
|
1127
|
+
- `getNodesBySession(sessionId)`
|
|
1128
|
+
- `getSegmentsBySession(sessionId)`
|
|
1129
|
+
- `getEdgesByType(sessionId, type)`
|
|
1130
|
+
- `getEdgesBySession(sessionId)`
|
|
1131
|
+
- `getMemoriesBySession(sessionId)`
|
|
1132
|
+
- `getSessionNodeCount(sessionId)`
|
|
1133
|
+
- `getSessionIngestState(sessionId)`
|
|
1134
|
+
|
|
1135
|
+
Common `MemoGrafterAgent` methods:
|
|
1038
1136
|
|
|
1039
1137
|
- `initialize()`: initialize storage.
|
|
1040
1138
|
- `invoke(message)`: send a user message and receive an assistant response.
|
|
1041
1139
|
- `getHistory()`: read local chat history.
|
|
1042
|
-
- `getSessionId()`: read the current session ID.
|
|
1140
|
+
- `getSessionId()`: read the current session ID.
|
|
1043
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.
|
|
1044
1143
|
- `getActiveNodes()`: inspect topic nodes.
|
|
1045
1144
|
- `getActiveSegments()`: inspect topic segments.
|
|
1046
|
-
- `
|
|
1047
|
-
- `
|
|
1048
|
-
- `
|
|
1049
|
-
- `
|
|
1050
|
-
- `
|
|
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, GraphSnapshot, 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);
|
|
@@ -16,12 +17,15 @@ export declare class MemoGrafterAgent {
|
|
|
16
17
|
getActiveNodes(): Promise<TopicNode[]>;
|
|
17
18
|
getActiveSegments(): Promise<TopicSegment[]>;
|
|
18
19
|
getGraphSnapshot(): Promise<GraphSnapshot>;
|
|
20
|
+
getGraftRegistry(): Promise<GraftRegistryEntry[]>;
|
|
21
|
+
removeGraft(nodeId: string): Promise<void>;
|
|
22
|
+
clearSession(): Promise<void>;
|
|
19
23
|
graft(topicIds?: string[]): Promise<InjectionResult>;
|
|
20
24
|
ingestGraftedNodes(nodes: TopicNode[]): Promise<TopicNode[]>;
|
|
21
25
|
recall(query: string, options?: RetrieverConfig): Promise<RetrievalResult>;
|
|
22
26
|
absorbFromAgent(sourceAgent: MemoGrafterAgent, options?: AbsorbFromAgentOptions): Promise<TopicNode[]>;
|
|
23
27
|
private enqueueBackgroundIngest;
|
|
24
|
-
private
|
|
28
|
+
private _buildMemoryContext;
|
|
25
29
|
close(): Promise<void>;
|
|
26
30
|
}
|
|
27
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"}
|