memo-grafter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.env.example +3 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -0
  4. package/USER_GUIDE.md +702 -0
  5. package/dist/MemoGrafter.d.ts +29 -0
  6. package/dist/MemoGrafter.d.ts.map +1 -0
  7. package/dist/MemoGrafter.js +106 -0
  8. package/dist/MemoGrafter.js.map +1 -0
  9. package/dist/MemoGrafterAgent.d.ts +18 -0
  10. package/dist/MemoGrafterAgent.d.ts.map +1 -0
  11. package/dist/MemoGrafterAgent.js +55 -0
  12. package/dist/MemoGrafterAgent.js.map +1 -0
  13. package/dist/adapters/OpenAIAdapter.d.ts +14 -0
  14. package/dist/adapters/OpenAIAdapter.d.ts.map +1 -0
  15. package/dist/adapters/OpenAIAdapter.js +37 -0
  16. package/dist/adapters/OpenAIAdapter.js.map +1 -0
  17. package/dist/adapters/types.d.ts +2 -0
  18. package/dist/adapters/types.d.ts.map +1 -0
  19. package/dist/adapters/types.js +2 -0
  20. package/dist/adapters/types.js.map +1 -0
  21. package/dist/fleet/ConductorAgent.d.ts +15 -0
  22. package/dist/fleet/ConductorAgent.d.ts.map +1 -0
  23. package/dist/fleet/ConductorAgent.js +41 -0
  24. package/dist/fleet/ConductorAgent.js.map +1 -0
  25. package/dist/fleet/FleetStore.d.ts +12 -0
  26. package/dist/fleet/FleetStore.d.ts.map +1 -0
  27. package/dist/fleet/FleetStore.js +30 -0
  28. package/dist/fleet/FleetStore.js.map +1 -0
  29. package/dist/fleet/MemoGrafterFleet.d.ts +20 -0
  30. package/dist/fleet/MemoGrafterFleet.d.ts.map +1 -0
  31. package/dist/fleet/MemoGrafterFleet.js +49 -0
  32. package/dist/fleet/MemoGrafterFleet.js.map +1 -0
  33. package/dist/fleet/WorkerAgent.d.ts +30 -0
  34. package/dist/fleet/WorkerAgent.d.ts.map +1 -0
  35. package/dist/fleet/WorkerAgent.js +95 -0
  36. package/dist/fleet/WorkerAgent.js.map +1 -0
  37. package/dist/fleet/types.d.ts +38 -0
  38. package/dist/fleet/types.d.ts.map +1 -0
  39. package/dist/fleet/types.js +2 -0
  40. package/dist/fleet/types.js.map +1 -0
  41. package/dist/index.d.ts +9 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +7 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/pipeline/GrafterPipeline.d.ts +16 -0
  46. package/dist/pipeline/GrafterPipeline.d.ts.map +1 -0
  47. package/dist/pipeline/GrafterPipeline.js +58 -0
  48. package/dist/pipeline/GrafterPipeline.js.map +1 -0
  49. package/dist/pipeline/IngestPipeline.d.ts +19 -0
  50. package/dist/pipeline/IngestPipeline.d.ts.map +1 -0
  51. package/dist/pipeline/IngestPipeline.js +44 -0
  52. package/dist/pipeline/IngestPipeline.js.map +1 -0
  53. package/dist/pipeline/SegmentProcessor.d.ts +19 -0
  54. package/dist/pipeline/SegmentProcessor.d.ts.map +1 -0
  55. package/dist/pipeline/SegmentProcessor.js +92 -0
  56. package/dist/pipeline/SegmentProcessor.js.map +1 -0
  57. package/dist/pipeline/TopicDriftDetector.d.ts +22 -0
  58. package/dist/pipeline/TopicDriftDetector.d.ts.map +1 -0
  59. package/dist/pipeline/TopicDriftDetector.js +96 -0
  60. package/dist/pipeline/TopicDriftDetector.js.map +1 -0
  61. package/dist/queue/IngestQueue.d.ts +16 -0
  62. package/dist/queue/IngestQueue.d.ts.map +1 -0
  63. package/dist/queue/IngestQueue.js +103 -0
  64. package/dist/queue/IngestQueue.js.map +1 -0
  65. package/dist/store/GraphStore.d.ts +71 -0
  66. package/dist/store/GraphStore.d.ts.map +1 -0
  67. package/dist/store/GraphStore.js +577 -0
  68. package/dist/store/GraphStore.js.map +1 -0
  69. package/dist/types.d.ts +84 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +2 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/utils/drift/cosineSimilarity.d.ts +2 -0
  74. package/dist/utils/drift/cosineSimilarity.d.ts.map +1 -0
  75. package/dist/utils/drift/cosineSimilarity.js +12 -0
  76. package/dist/utils/drift/cosineSimilarity.js.map +1 -0
  77. package/dist/utils/drift/vectorAvg.d.ts +2 -0
  78. package/dist/utils/drift/vectorAvg.d.ts.map +1 -0
  79. package/dist/utils/drift/vectorAvg.js +11 -0
  80. package/dist/utils/drift/vectorAvg.js.map +1 -0
  81. package/dist/utils/normalizeText.d.ts +2 -0
  82. package/dist/utils/normalizeText.d.ts.map +1 -0
  83. package/dist/utils/normalizeText.js +14 -0
  84. package/dist/utils/normalizeText.js.map +1 -0
  85. package/dist/utils/vectorLiteral.d.ts +3 -0
  86. package/dist/utils/vectorLiteral.d.ts.map +1 -0
  87. package/dist/utils/vectorLiteral.js +18 -0
  88. package/dist/utils/vectorLiteral.js.map +1 -0
  89. package/package.json +55 -0
package/USER_GUIDE.md ADDED
@@ -0,0 +1,702 @@
1
+ # MemoGrafter User Guide
2
+
3
+ ## Introduction
4
+
5
+ MemoGrafter is an experimental Node.js and TypeScript framework for structured chatbot memory. It stores chatbot conversations as message buffers, topic segments, topic nodes, and graph edges. Later, it can inject relevant memory into a chatbot turn or copy selected memory into another chatbot/session.
6
+
7
+ The project is intentionally focused. MemoGrafter is a chatbot memory framework, not an autonomous agent runtime. It does not run tools, schedule work, or decide goals for an agent. It helps a chatbot remember, retrieve, and transfer conversational context.
8
+
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
+
11
+ ## Requirements
12
+
13
+ - Node.js 18 or newer.
14
+ - TypeScript or modern JavaScript using ES modules.
15
+ - PostgreSQL with the `pgvector` extension enabled.
16
+ - An LLM adapter.
17
+ - An embedding adapter.
18
+ - An OpenAI API key only if using the included OpenAI adapters.
19
+ - Redis only if enabling queue mode.
20
+
21
+ MemoGrafter is server-side only. Do not run it in browser code.
22
+
23
+ ## Installation
24
+
25
+ Install from npm:
26
+
27
+ ```bash
28
+ npm install memo-grafter
29
+ ```
30
+
31
+ Install from a local clone before publishing or while developing:
32
+
33
+ ```bash
34
+ cd path/to/your-app
35
+ npm install D:/cohort/projects/project-memoGrafter
36
+ ```
37
+
38
+ If you are working inside this repository, build it first:
39
+
40
+ ```bash
41
+ cd D:/cohort/projects/project-memoGrafter
42
+ npm install
43
+ npm run build
44
+ ```
45
+
46
+ ## Environment Setup
47
+
48
+ Create a `.env` file in your app:
49
+
50
+ ```bash
51
+ DATABASE_URL=postgres://postgres:postgres@localhost:5432/memo_grafter
52
+ OPENAI_API_KEY=sk-...
53
+ REDIS_URL=redis://localhost:6379
54
+ ```
55
+
56
+ `DATABASE_URL` is required.
57
+
58
+ `OPENAI_API_KEY` is required only when using `OpenAILLMAdapter` or `OpenAIEmbedAdapter`.
59
+
60
+ `REDIS_URL` is optional and only needed when you pass `queue` config.
61
+
62
+ Enable `pgvector` in PostgreSQL:
63
+
64
+ ```sql
65
+ CREATE EXTENSION IF NOT EXISTS vector;
66
+ ```
67
+
68
+ MemoGrafter creates its own tables during `initialize()`.
69
+
70
+ Current v1 tables:
71
+
72
+ - `mg_message_buffer`
73
+ - `mg_segments`
74
+ - `mg_topic_nodes`
75
+ - `mg_topic_edges`
76
+ - `mg_fleets`
77
+ - `mg_fleet_agents`
78
+
79
+ ## Quick Start
80
+
81
+ Create `src/index.ts`:
82
+
83
+ ```ts
84
+ import "dotenv/config";
85
+
86
+ import {
87
+ MemoGrafterAgent,
88
+ OpenAIEmbedAdapter,
89
+ OpenAILLMAdapter,
90
+ } from "memo-grafter";
91
+
92
+ const agent = new MemoGrafterAgent({
93
+ db: {
94
+ connectionString: process.env.DATABASE_URL!,
95
+ },
96
+ llm: new OpenAILLMAdapter("gpt-4o"),
97
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
98
+ });
99
+
100
+ try {
101
+ await agent.initialize();
102
+
103
+ console.log(await agent.invoke("I am planning a Japan trip."));
104
+ console.log(await agent.invoke("I like quiet towns and local cafes."));
105
+ console.log(await agent.invoke("What should I remember while planning?"));
106
+
107
+ const nodes = await agent.getActiveNodes();
108
+ console.log(nodes.map((node) => ({ label: node.label, summary: node.summary })));
109
+ } finally {
110
+ await agent.close();
111
+ }
112
+ ```
113
+
114
+ Run it:
115
+
116
+ ```bash
117
+ npx tsx --env-file=.env src/index.ts
118
+ ```
119
+
120
+ ## Core Concepts
121
+
122
+ ### Messages
123
+
124
+ A message is one user or assistant turn:
125
+
126
+ ```ts
127
+ export interface Message {
128
+ role: "user" | "assistant";
129
+ content: string;
130
+ }
131
+ ```
132
+
133
+ `MemoGrafterAgent` keeps an in-memory history for the current session and stores messages in PostgreSQL during ingestion.
134
+
135
+ ### Segments
136
+
137
+ A segment is a range of messages that belong to the same topic. MemoGrafter uses drift detection to decide where topic boundaries are.
138
+
139
+ Example:
140
+
141
+ ```text
142
+ messages 0-4 -> Japan travel planning
143
+ messages 5-8 -> cover letter writing
144
+ ```
145
+
146
+ Segments are stored in `mg_segments`.
147
+
148
+ ### Topic Nodes
149
+
150
+ A topic node is the main unit of memory. It represents a segment as a label, summary, embedding, message range, and metadata.
151
+
152
+ Important fields:
153
+
154
+ - `id`: unique topic node ID.
155
+ - `label`: short label.
156
+ - `summary`: structured summary of the segment.
157
+ - `embedding`: vector used for semantic search.
158
+ - `messageRange`: source message range.
159
+ - `topicOrder`: chronological order.
160
+ - `driftScore`: topic-change score.
161
+ - `agentColor`, `fleetId`, `agentId`: nullable fleet metadata.
162
+
163
+ Topic nodes are stored in `mg_topic_nodes`.
164
+
165
+ ### Graph Edges
166
+
167
+ Edges connect related topic nodes. They can represent temporal, semantic, or grafted relationships.
168
+
169
+ Edges are stored in `mg_topic_edges`.
170
+
171
+ ### Grafting
172
+
173
+ Grafting is the process of selecting memory nodes and turning them into useful context for another prompt or another chatbot.
174
+
175
+ There are two common forms:
176
+
177
+ - Preview memory with `graft()`.
178
+ - Copy memory into another chatbot with `absorbFromAgent()` or `ingestGraftedNodes()`.
179
+
180
+ ## Using MemoGrafterAgent
181
+
182
+ `MemoGrafterAgent` is the easiest API to start with.
183
+
184
+ ```ts
185
+ const agent = new MemoGrafterAgent({
186
+ db: {
187
+ connectionString: process.env.DATABASE_URL!,
188
+ },
189
+ llm: new OpenAILLMAdapter("gpt-4o"),
190
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
191
+ });
192
+ ```
193
+
194
+ Initialize it before use:
195
+
196
+ ```ts
197
+ await agent.initialize();
198
+ ```
199
+
200
+ Send user messages with `invoke()`:
201
+
202
+ ```ts
203
+ const answer = await agent.invoke("Help me plan a Kyoto itinerary.");
204
+ ```
205
+
206
+ Close resources when done:
207
+
208
+ ```ts
209
+ await agent.close();
210
+ ```
211
+
212
+ ### What `invoke()` Does
213
+
214
+ On every call, `invoke()`:
215
+
216
+ 1. Adds the user message to local history.
217
+ 2. Loads existing topic nodes for the session.
218
+ 3. Builds a memory injection prompt from those nodes.
219
+ 4. Sends history plus memory prompt to the LLM.
220
+ 5. Adds the assistant response to history.
221
+ 6. Ingests the updated conversation into the memory graph.
222
+
223
+ On the first turn there may be no memory to inject. Later turns can use memory created from earlier turns.
224
+
225
+ ## Inspecting Memory
226
+
227
+ Read active topic nodes:
228
+
229
+ ```ts
230
+ const nodes = await agent.getActiveNodes();
231
+
232
+ for (const node of nodes) {
233
+ console.log({
234
+ id: node.id,
235
+ label: node.label,
236
+ summary: node.summary,
237
+ messageRange: node.messageRange,
238
+ topicOrder: node.topicOrder,
239
+ driftScore: node.driftScore,
240
+ });
241
+ }
242
+ ```
243
+
244
+ Read active segments:
245
+
246
+ ```ts
247
+ const segments = await agent.getActiveSegments();
248
+ console.log(segments);
249
+ ```
250
+
251
+ Read the in-memory chat history:
252
+
253
+ ```ts
254
+ const history = agent.getHistory();
255
+ console.log(history);
256
+ ```
257
+
258
+ Read the session ID:
259
+
260
+ ```ts
261
+ console.log(agent.getSessionId());
262
+ ```
263
+
264
+ ## Grafting Memory
265
+
266
+ Use `graft()` to preview what memory would be injected:
267
+
268
+ ```ts
269
+ const graft = await agent.graft();
270
+
271
+ console.log(graft.systemPrompt);
272
+ console.log(graft.nodes);
273
+ console.log(graft.tokenCount);
274
+ ```
275
+
276
+ You can graft specific topic IDs:
277
+
278
+ ```ts
279
+ const nodes = await agent.getActiveNodes();
280
+
281
+ const graft = await agent.graft([nodes[0]!.id]);
282
+ ```
283
+
284
+ `graft()` returns:
285
+
286
+ - `systemPrompt`: memory context suitable for an LLM system prompt.
287
+ - `nodes`: selected topic nodes.
288
+ - `tokenCount`: estimated token count.
289
+
290
+ ## Absorbing Memory Into Another Chatbot
291
+
292
+ Use `absorbFromAgent()` to copy selected memory from one chatbot into another.
293
+
294
+ ```ts
295
+ const travelBot = new MemoGrafterAgent(config);
296
+ const writingBot = new MemoGrafterAgent(config);
297
+
298
+ await travelBot.initialize();
299
+ await writingBot.initialize();
300
+
301
+ await travelBot.invoke("I am planning a Japan trip.");
302
+ await travelBot.invoke("I like quiet towns, bookstores, and local cafes.");
303
+ await travelBot.invoke("My budget is around 2500 dollars.");
304
+
305
+ const copiedNodes = await writingBot.absorbFromAgent(travelBot, {
306
+ prompt: "Japan travel preferences",
307
+ minSimilarity: 0.6,
308
+ limit: 3,
309
+ });
310
+
311
+ console.log(`Copied ${copiedNodes.length} nodes.`);
312
+
313
+ const response = await writingBot.invoke(
314
+ "Suggest a reflective blog intro for my Japan trip."
315
+ );
316
+
317
+ console.log(response);
318
+ ```
319
+
320
+ ### Absorb By Semantic Prompt
321
+
322
+ ```ts
323
+ await targetAgent.absorbFromAgent(sourceAgent, {
324
+ prompt: "Japan travel preferences",
325
+ minSimilarity: 0.6,
326
+ limit: 3,
327
+ });
328
+ ```
329
+
330
+ Use this when you want MemoGrafter to find relevant memory by meaning.
331
+
332
+ ### Absorb By Topic ID
333
+
334
+ ```ts
335
+ const sourceNodes = await sourceAgent.getActiveNodes();
336
+
337
+ await targetAgent.absorbFromAgent(sourceAgent, {
338
+ topicIds: [sourceNodes[0]!.id],
339
+ });
340
+ ```
341
+
342
+ Use this when your UI lets a user choose memory nodes manually.
343
+
344
+ ### Ingest Grafted Nodes Directly
345
+
346
+ ```ts
347
+ const graft = await sourceAgent.graft();
348
+ await targetAgent.ingestGraftedNodes(graft.nodes);
349
+ ```
350
+
351
+ Use this when you want to inspect or filter a graft before copying it.
352
+
353
+ ## Configuration
354
+
355
+ Full shape:
356
+
357
+ ```ts
358
+ const agent = new MemoGrafterAgent({
359
+ db: {
360
+ connectionString: process.env.DATABASE_URL!,
361
+ },
362
+ llm,
363
+ embedder,
364
+ drift: {
365
+ mode: "intent",
366
+ windowSize: 5,
367
+ threshold: 0.3,
368
+ minSegmentMessages: 3,
369
+ },
370
+ graph: {
371
+ topK: 5,
372
+ hopDepth: 2,
373
+ },
374
+ inject: {
375
+ bufferSize: 4,
376
+ tokenBudget: 1500,
377
+ },
378
+ });
379
+ ```
380
+
381
+ ### `db`
382
+
383
+ ```ts
384
+ db: {
385
+ connectionString: process.env.DATABASE_URL!,
386
+ }
387
+ ```
388
+
389
+ PostgreSQL connection string.
390
+
391
+ ### `llm`
392
+
393
+ ```ts
394
+ llm: new OpenAILLMAdapter("gpt-4o")
395
+ ```
396
+
397
+ Adapter used to generate assistant responses and summarize segments.
398
+
399
+ ### `embedder`
400
+
401
+ ```ts
402
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small")
403
+ ```
404
+
405
+ Adapter used to create vectors for semantic search.
406
+
407
+ ### `drift`
408
+
409
+ ```ts
410
+ drift: {
411
+ mode: "intent",
412
+ windowSize: 5,
413
+ threshold: 0.3,
414
+ minSegmentMessages: 3,
415
+ }
416
+ ```
417
+
418
+ Controls topic boundary detection.
419
+
420
+ - `mode`: `"intent"` or `"window"`.
421
+ - `windowSize`: message window size for window mode.
422
+ - `threshold`: drift sensitivity.
423
+ - `minSegmentMessages`: minimum messages before a boundary.
424
+
425
+ Use `"intent"` for most chatbot memory demos. In intent mode, user messages drive topic shifts.
426
+
427
+ ### `graph`
428
+
429
+ ```ts
430
+ graph: {
431
+ topK: 5,
432
+ hopDepth: 2,
433
+ }
434
+ ```
435
+
436
+ Controls graph retrieval and traversal.
437
+
438
+ - `topK`: number of similar nodes to retrieve.
439
+ - `hopDepth`: how far grafting walks graph neighbors.
440
+
441
+ ### `inject`
442
+
443
+ ```ts
444
+ inject: {
445
+ bufferSize: 4,
446
+ tokenBudget: 1500,
447
+ }
448
+ ```
449
+
450
+ Controls how much memory is inserted into the prompt.
451
+
452
+ - `bufferSize`: nearby raw messages to include.
453
+ - `tokenBudget`: approximate memory prompt budget.
454
+
455
+ ## Queue Mode
456
+
457
+ Without queue config, ingestion runs synchronously after `invoke()`.
458
+
459
+ With queue config, MemoGrafter uses BullMQ and Redis:
460
+
461
+ ```ts
462
+ const agent = new MemoGrafterAgent({
463
+ db: {
464
+ connectionString: process.env.DATABASE_URL!,
465
+ },
466
+ llm: new OpenAILLMAdapter("gpt-4o"),
467
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
468
+ queue: {
469
+ redisUrl: process.env.REDIS_URL!,
470
+ removeOnComplete: true,
471
+ removeOnFail: true,
472
+ },
473
+ });
474
+ ```
475
+
476
+ 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.
477
+
478
+ ## Custom Adapters
479
+
480
+ You can use any model provider if you implement the public adapter interfaces.
481
+
482
+ Custom LLM adapter:
483
+
484
+ ```ts
485
+ import type { LLMAdapter, Message } from "memo-grafter";
486
+
487
+ class MyLLMAdapter implements LLMAdapter {
488
+ async complete(messages: Message[], system?: string): Promise<string> {
489
+ // Call your model provider here.
490
+ return "Assistant response";
491
+ }
492
+ }
493
+ ```
494
+
495
+ Custom embedding adapter:
496
+
497
+ ```ts
498
+ import type { EmbedAdapter } from "memo-grafter";
499
+
500
+ class MyEmbedAdapter implements EmbedAdapter {
501
+ async embed(text: string): Promise<number[]> {
502
+ // Return an embedding vector from your provider here.
503
+ return [];
504
+ }
505
+ }
506
+ ```
507
+
508
+ Use them normally:
509
+
510
+ ```ts
511
+ const agent = new MemoGrafterAgent({
512
+ db: {
513
+ connectionString: process.env.DATABASE_URL!,
514
+ },
515
+ llm: new MyLLMAdapter(),
516
+ embedder: new MyEmbedAdapter(),
517
+ });
518
+ ```
519
+
520
+ Your embedding vector dimension must match the vector dimension expected by the database schema.
521
+
522
+ ## Fleet API
523
+
524
+ Fleets let you group color-scoped worker chatbots and use a conductor to graft memory across workers.
525
+
526
+ ```ts
527
+ import {
528
+ MemoGrafterFleet,
529
+ OpenAIEmbedAdapter,
530
+ OpenAILLMAdapter,
531
+ } from "memo-grafter";
532
+
533
+ const fleet = new MemoGrafterFleet(
534
+ {
535
+ db: {
536
+ connectionString: process.env.DATABASE_URL!,
537
+ },
538
+ llm: new OpenAILLMAdapter("gpt-4o"),
539
+ embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
540
+ },
541
+ {
542
+ id: "support-fleet",
543
+ name: "Support Fleet",
544
+ }
545
+ );
546
+
547
+ await fleet.initialize();
548
+
549
+ const conductor = fleet.createConductor();
550
+ const billing = await fleet.createWorker({ color: "billing" });
551
+ const technical = await fleet.createWorker({ color: "technical" });
552
+
553
+ await billing.invoke("The customer needs help understanding invoice credits.");
554
+ await conductor.graftColorIntoAgent("billing", technical);
555
+
556
+ const answer = await technical.invoke(
557
+ "Use any relevant billing context while helping with this technical issue."
558
+ );
559
+
560
+ console.log(answer);
561
+
562
+ await fleet.close();
563
+ ```
564
+
565
+ The worker color `conductor` is reserved.
566
+
567
+ Prompt-guided fleet grafting:
568
+
569
+ ```ts
570
+ await conductor.graftByPrompt("invoice credit policy", technical, {
571
+ minSimilarity: 0.6,
572
+ limit: 3,
573
+ });
574
+ ```
575
+
576
+ ## Example Project
577
+
578
+ This repository includes a runnable example:
579
+
580
+ ```text
581
+ examples/chatbot-memory-demo
582
+ ```
583
+
584
+ Run it:
585
+
586
+ ```bash
587
+ cd D:/cohort/projects/project-memoGrafter
588
+ npm install
589
+ npm run build
590
+
591
+ cd examples/chatbot-memory-demo
592
+ npm install
593
+ cp .env.example .env
594
+ npm run dev
595
+ ```
596
+
597
+ PowerShell:
598
+
599
+ ```powershell
600
+ Copy-Item .env.example .env
601
+ ```
602
+
603
+ The example creates a travel chatbot and a writing chatbot, transfers Japan travel memory, and asks the writing bot to use that transferred context.
604
+
605
+ ## Troubleshooting
606
+
607
+ ### `DATABASE_URL is not reachable`
608
+
609
+ Check that PostgreSQL is running and the connection string is correct.
610
+
611
+ Confirm `pgvector` is enabled:
612
+
613
+ ```sql
614
+ CREATE EXTENSION IF NOT EXISTS vector;
615
+ ```
616
+
617
+ ### No Topic Nodes Are Created
618
+
619
+ Common causes:
620
+
621
+ - The conversation is too short.
622
+ - `minSegmentMessages` is too high for the demo.
623
+ - The LLM adapter failed.
624
+ - The embedding adapter failed.
625
+ - Queue mode is enabled and background ingestion has not finished yet.
626
+
627
+ For small demos, try:
628
+
629
+ ```ts
630
+ drift: {
631
+ mode: "intent",
632
+ threshold: 0.3,
633
+ minSegmentMessages: 3,
634
+ }
635
+ ```
636
+
637
+ ### Absorb Copies Zero Nodes
638
+
639
+ Inspect the source memory:
640
+
641
+ ```ts
642
+ console.log(await sourceAgent.getActiveNodes());
643
+ ```
644
+
645
+ Then try a lower similarity threshold:
646
+
647
+ ```ts
648
+ await targetAgent.absorbFromAgent(sourceAgent, {
649
+ prompt: "Japan travel preferences",
650
+ minSimilarity: 0.3,
651
+ limit: 3,
652
+ });
653
+ ```
654
+
655
+ ### Redis Warnings
656
+
657
+ Redis is only required when you pass `queue` config. If you do not need background ingestion, remove the `queue` section.
658
+
659
+ ### Browser Runtime Error
660
+
661
+ MemoGrafter is server-side only. Run it in Node.js.
662
+
663
+ ## Production Notes
664
+
665
+ MemoGrafter v0.1.0 is experimental. Treat it as a starting point for prototypes and evaluation, not a finished production memory platform.
666
+
667
+ Practical notes:
668
+
669
+ - Keep secrets in environment variables.
670
+ - Use PostgreSQL with `pgvector` enabled.
671
+ - Tune `tokenBudget` to control prompt size and cost.
672
+ - Use queue mode if ingestion becomes slow.
673
+ - Store your own user/session mapping outside MemoGrafter.
674
+ - Call `close()` during graceful shutdown.
675
+ - Do not expose database credentials or OpenAI keys to browser code.
676
+ - Run your own evaluation before trusting memory transfer behavior in user-facing flows.
677
+
678
+ ## Public API Overview
679
+
680
+ Main exports:
681
+
682
+ - `MemoGrafterAgent`
683
+ - `MemoGrafter`
684
+ - `MemoGrafterFleet`
685
+ - `WorkerAgent`
686
+ - `ConductorAgent`
687
+ - `OpenAILLMAdapter`
688
+ - `OpenAIEmbedAdapter`
689
+ - public shared and fleet types
690
+
691
+ Common `MemoGrafterAgent` methods:
692
+
693
+ - `initialize()`: initialize storage.
694
+ - `invoke(message)`: send a user message and receive an assistant response.
695
+ - `getHistory()`: read local chat history.
696
+ - `getSessionId()`: read the current session ID.
697
+ - `getActiveNodes()`: inspect topic nodes.
698
+ - `getActiveSegments()`: inspect topic segments.
699
+ - `graft(topicIds?)`: preview memory injection.
700
+ - `ingestGraftedNodes(nodes)`: copy provided nodes into this agent.
701
+ - `absorbFromAgent(sourceAgent, options)`: select and copy memory from another agent.
702
+ - `close()`: close database and queue resources.
@@ -0,0 +1,29 @@
1
+ import { GraphStore } from "./store/GraphStore.js";
2
+ import { MemoGrafterFleet } from "./fleet/MemoGrafterFleet.js";
3
+ import type { MemoGrafterFleetOptions } from "./fleet/types.js";
4
+ import type { AbsorbFromAgentOptions, EmbedAdapter, InjectionResult, LLMAdapter, MemoGrafterConfig, Message, TopicNode, TopicSegment } from "./types.js";
5
+ export declare class MemoGrafter {
6
+ readonly llm: LLMAdapter;
7
+ readonly embedder: EmbedAdapter;
8
+ readonly store: GraphStore;
9
+ private readonly ingestPipeline;
10
+ private readonly grafterPipeline;
11
+ private readonly ingestQueue;
12
+ constructor(config: MemoGrafterConfig);
13
+ initialize(): Promise<void>;
14
+ ingest(messages: Message[], sessionId: string): Promise<TopicNode[]>;
15
+ ingestNow(messages: Message[], sessionId: string): Promise<TopicNode[]>;
16
+ enqueueIngest(messages: Message[], sessionId: string): Promise<void>;
17
+ getTopics(sessionId: string): Promise<{
18
+ nodes: TopicNode[];
19
+ segments: TopicSegment[];
20
+ }>;
21
+ inject(sessionId: string, topicIds: string[]): Promise<InjectionResult>;
22
+ ingestGraftedNodes(nodes: TopicNode[], targetSessionId: string): Promise<TopicNode[]>;
23
+ selectNodesForAbsorb(sourceSessionId: string, options: AbsorbFromAgentOptions): Promise<TopicNode[]>;
24
+ absorbNodes(nodes: TopicNode[], targetSessionId: string): Promise<TopicNode[]>;
25
+ createFleet(options?: MemoGrafterFleetOptions): MemoGrafterFleet;
26
+ close(): Promise<void>;
27
+ private assertServerEnvironment;
28
+ }
29
+ //# sourceMappingURL=MemoGrafter.d.ts.map