@ppagent/memory 0.1.4 → 0.4.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.
- package/dist/cli.js +1187 -0
- package/dist/index.d.ts +397 -137
- package/dist/index.js +1372 -853
- package/dist/provider.resolver-2KS2YYNV.js +616 -0
- package/llms.txt +150 -87
- package/package.json +19 -7
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ppagent/memory
|
|
2
2
|
|
|
3
|
-
> `@ppagent/memory` is an independent TypeScript/Node.js long-term memory package for AI agents. It stores conversation
|
|
3
|
+
> `@ppagent/memory` is an independent TypeScript/Node.js long-term memory package for AI agents. It stores complete raw conversation messages in a pluggable vector store (LanceDB or SQLite/sqlite-vec, auto-detected per platform), builds importance-aware Topic summaries, returns fixed-budget Topics plus recent uncompressed messages as one context window, extracts and searches entity relationships with Grafeo, supports cached user/chat facts, and ingests Markdown documents as a searchable knowledge base.
|
|
4
4
|
|
|
5
5
|
This file is written for AI coding agents and assistants. Use it as the primary package guide when generating code that depends on `@ppagent/memory`.
|
|
6
6
|
|
|
@@ -13,8 +13,9 @@ This file is written for AI coding agents and assistants. Use it as the primary
|
|
|
13
13
|
- Source entry during local workspace development: `src/index.ts`
|
|
14
14
|
- Runtime target: Node.js with global `fetch`
|
|
15
15
|
- Storage engines:
|
|
16
|
-
- LanceDB for messages, topics, facts, sessions, documents, and chunks
|
|
16
|
+
- Vector store (dual backend, auto-detected): LanceDB or SQLite (better-sqlite3 + sqlite-vec + FTS5 with jieba Chinese tokenization) for messages, topics, facts, sessions, documents, and chunks. LanceDB requires native prebuilt binaries (unavailable on Intel macOS since 0.23.0); SQLite works everywhere and is the automatic fallback. RRF hybrid-search fusion runs in the shared domain layer, so search behavior is identical across backends.
|
|
17
17
|
- Grafeo for entity/relation graph storage and graph search
|
|
18
|
+
- Runtime configuration principle: `MemoryManager`/`MemoryStore` never read environment variables, config files, or implicit global state; every parameter enters through `MemoryConfig`. The separate manual migration CLI reads only the file explicitly supplied with `--config`.
|
|
18
19
|
- LLM APIs: OpenAI-compatible `/chat/completions`
|
|
19
20
|
- Embedding APIs: OpenAI-compatible `/embeddings`
|
|
20
21
|
|
|
@@ -48,7 +49,7 @@ npm install @ppagent/memory
|
|
|
48
49
|
```ts
|
|
49
50
|
import {
|
|
50
51
|
MemoryManager,
|
|
51
|
-
|
|
52
|
+
MemoryStore,
|
|
52
53
|
DEFAULT_NODE_TYPES,
|
|
53
54
|
DEFAULT_RELATION_TYPES,
|
|
54
55
|
KIND_CONVERSATION,
|
|
@@ -62,11 +63,12 @@ import type {
|
|
|
62
63
|
SearchResult,
|
|
63
64
|
AddDocumentOptions,
|
|
64
65
|
KnowledgeSearchOptions,
|
|
65
|
-
KnowledgeSearchResult,
|
|
66
|
-
|
|
66
|
+
KnowledgeSearchResult,
|
|
67
|
+
MemoryContextWindow,
|
|
68
|
+
} from "@ppagent/memory";
|
|
67
69
|
```
|
|
68
70
|
|
|
69
|
-
Most consumers should only instantiate `MemoryManager`. `
|
|
71
|
+
Most consumers should only instantiate `MemoryManager`. `MemoryStore` (plus the `VectorStoreProvider` / `Filter` types) is exported for advanced storage tests or custom infrastructure work. Breaking change in 0.2.0: `LanceService` was replaced by `MemoryStore` + provider abstraction; string SQL filters were replaced by structured `Filter` objects.
|
|
70
72
|
|
|
71
73
|
## Minimal Example
|
|
72
74
|
|
|
@@ -120,7 +122,7 @@ const answer = await memory.ask({
|
|
|
120
122
|
|
|
121
123
|
console.log(answer);
|
|
122
124
|
|
|
123
|
-
memory.destroy();
|
|
125
|
+
await memory.destroy();
|
|
124
126
|
```
|
|
125
127
|
|
|
126
128
|
## Complete Example
|
|
@@ -147,16 +149,19 @@ const memory = new MemoryManager({
|
|
|
147
149
|
embeddingBatchSize: 20,
|
|
148
150
|
embeddingConcurrency: 2,
|
|
149
151
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
compressedContextTokenLimit: 16 * 1024,
|
|
153
|
+
contextUsageRatio: 0.75,
|
|
154
|
+
precompressionRatio: 0.75,
|
|
155
|
+
compressionBatchRatio: 0.5,
|
|
156
|
+
compressionBatchTokenLimit: 0,
|
|
157
|
+
topicSummaryMaxTokens: 2048,
|
|
158
|
+
defaultModelContextTokens: 256 * 1024,
|
|
159
|
+
maxHistoryAgeMs: 0,
|
|
160
|
+
sessionIdleTtlMs: 30 * 60_000,
|
|
161
|
+
sessionSweepIntervalMs: 60_000,
|
|
162
|
+
maxConcurrentCompressions: 3,
|
|
157
163
|
entitySimilarityThreshold: 0.92,
|
|
158
164
|
defaultSearchLimit: 10,
|
|
159
|
-
recallBoostMs: 3_600_000,
|
|
160
165
|
|
|
161
166
|
chunkStrategy: "markdown-heading",
|
|
162
167
|
chunkMaxTokens: 800,
|
|
@@ -240,7 +245,7 @@ ChatMe 使用 TypeScript 构建,后端包含长期记忆系统。
|
|
|
240
245
|
|
|
241
246
|
## Memory
|
|
242
247
|
|
|
243
|
-
|
|
248
|
+
长期记忆系统使用向量存储(LanceDB 或 SQLite,自动探测)存储向量,使用 Grafeo 存储知识图谱。`,
|
|
244
249
|
userId,
|
|
245
250
|
chatId,
|
|
246
251
|
sessionId,
|
|
@@ -270,7 +275,7 @@ const answer = await memory.ask({
|
|
|
270
275
|
|
|
271
276
|
console.log(answer);
|
|
272
277
|
|
|
273
|
-
memory.destroy();
|
|
278
|
+
await memory.destroy();
|
|
274
279
|
```
|
|
275
280
|
|
|
276
281
|
## Configuration Reference
|
|
@@ -279,9 +284,25 @@ memory.destroy();
|
|
|
279
284
|
|
|
280
285
|
Required storage fields:
|
|
281
286
|
|
|
282
|
-
- `lancedbPath: string` - local LanceDB directory.
|
|
287
|
+
- `lancedbPath: string` - local LanceDB directory (used when the lancedb backend is active; its parent directory also hosts the backend marker file `.memory-provider`).
|
|
283
288
|
- `grafeoPath: string` - Grafeo database path.
|
|
284
289
|
|
|
290
|
+
Optional storage fields:
|
|
291
|
+
|
|
292
|
+
- `provider?: "auto" | "lancedb" | "sqlite"` - vector store backend. Default `"auto"`: probes the @lancedb/lancedb native binding at init and falls back to sqlite when unavailable (e.g. Intel macOS, musl without prebuilds). The first resolved backend is persisted in a marker file; auto mode never silently switches an existing data directory to a different backend (it throws with migration guidance instead).
|
|
293
|
+
- `sqlitePath?: string` - SQLite database file for the sqlite backend. Default: `path.join(path.dirname(lancedbPath), "memory.sqlite3")`, i.e. a `memory.sqlite3` file in the parent directory of `lancedbPath`. Parent directories are created automatically on init.
|
|
294
|
+
|
|
295
|
+
Storage layout example with `lancedbPath: "./data/memory/lance"` and defaults:
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
data/memory/
|
|
299
|
+
├── .memory-provider # backend marker written on first init ("lancedb" or "sqlite")
|
|
300
|
+
├── lance/ # LanceDB tables (lancedb backend only)
|
|
301
|
+
└── memory.sqlite3 # SQLite database (sqlite backend only; plus -wal/-shm files while open)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Backend data files are not interchangeable; switching backends requires an explicit export/import migration.
|
|
305
|
+
|
|
285
306
|
Required LLM fields:
|
|
286
307
|
|
|
287
308
|
- `llmBaseUrl: string` - OpenAI-compatible base URL, for example `https://api.openai.com/v1`.
|
|
@@ -293,7 +314,7 @@ Required embedding fields:
|
|
|
293
314
|
- `embeddingBaseUrl: string` - OpenAI-compatible embedding base URL.
|
|
294
315
|
- `embeddingApiKey: string` - embedding API key.
|
|
295
316
|
- `embeddingModel: string` - embedding model name.
|
|
296
|
-
- `embeddingDimension: number` - vector dimension. This must match the embedding model and existing
|
|
317
|
+
- `embeddingDimension: number` - vector dimension. This must match the embedding model and the existing vector store schema.
|
|
297
318
|
|
|
298
319
|
Embedding fallback behavior:
|
|
299
320
|
|
|
@@ -308,18 +329,23 @@ HTTP and retry fields:
|
|
|
308
329
|
- `embeddingBatchSize?: number` - max texts per embedding request. Default: `20`.
|
|
309
330
|
- `embeddingConcurrency?: number` - concurrent embedding batches. Default: `2`.
|
|
310
331
|
|
|
311
|
-
Conversation memory fields:
|
|
312
|
-
|
|
313
|
-
- `
|
|
314
|
-
- `
|
|
315
|
-
- `
|
|
316
|
-
- `
|
|
317
|
-
- `
|
|
318
|
-
- `
|
|
319
|
-
- `
|
|
320
|
-
- `
|
|
321
|
-
- `
|
|
322
|
-
- `
|
|
332
|
+
Conversation memory fields:
|
|
333
|
+
|
|
334
|
+
- `compressedContextTokenLimit?: number` - fixed token budget for compressed Topics. Default: `16384`; startup logs a warning above `32768`.
|
|
335
|
+
- `contextUsageRatio?: number` - fraction of the current model context available to conversation history. Default: `0.75`.
|
|
336
|
+
- `precompressionRatio?: number` - start background raw-message compression when raw usage reaches this fraction of its dynamic budget. Default: `0.75`.
|
|
337
|
+
- `compressionBatchRatio?: number` - target fraction of the raw-message budget compressed in one batch. Default: `0.5`.
|
|
338
|
+
- `compressionBatchTokenLimit?: number` - optional hard limit for one compression batch. Default: `0` (ratio only).
|
|
339
|
+
- `topicSummaryMaxTokens?: number` - hard maximum for one Topic summary. The LLM uses less for low-value chat and more for facts, experience, decisions, preferences, constraints, and reusable knowledge. Default: `2048`.
|
|
340
|
+
- `defaultModelContextTokens?: number` - used when `getHistoryWindow` receives no model size; a warning is logged. Default: `262144`.
|
|
341
|
+
- `maxHistoryAgeMs?: number` - maximum Topic and raw-message age restored during lazy cold start. Default: `0` (all history).
|
|
342
|
+
- `sessionIdleTtlMs?: number` - idle time before a session cache is released. Persistent data is not deleted. Default: `1800000`.
|
|
343
|
+
- `sessionSweepIntervalMs?: number` - idle cache sweep interval. Default: `60000`.
|
|
344
|
+
- `maxConcurrentCompressions?: number` - global semaphore limit for concurrent compression and knowledge ingestion tasks. Default: `3`.
|
|
345
|
+
- `entitySimilarityThreshold?: number` - graph entity similarity threshold. Default: `0.92`.
|
|
346
|
+
- `defaultSearchLimit?: number` - default `search` result limit. Default: `10`.
|
|
347
|
+
|
|
348
|
+
`sessionTokenLimit`, `historyWindowTokenLimit`, `topicRatio`, `detailMaxTokens`, and `conciseMaxTokens` remain only as deprecated 0.3.x configuration/read compatibility fields. New code should not use them.
|
|
323
349
|
|
|
324
350
|
Knowledge-base fields:
|
|
325
351
|
|
|
@@ -341,21 +367,30 @@ Knowledge-base fields:
|
|
|
341
367
|
|
|
342
368
|
The package intentionally separates durable base writes from expensive graph construction.
|
|
343
369
|
|
|
344
|
-
`updateChat(messages, opts)`:
|
|
345
|
-
|
|
346
|
-
-
|
|
347
|
-
-
|
|
348
|
-
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
370
|
+
`updateChat(messages, opts)`:
|
|
371
|
+
|
|
372
|
+
- Registers its write synchronously, so a caller may intentionally fire-and-forget it and a following `getHistoryWindow` will still wait for that write.
|
|
373
|
+
- Calculates tokens over `content`, `parts`, `payload`, and `metadata`, embeds the searchable text, and upserts raw messages by stable `messageId` before resolving.
|
|
374
|
+
- Creates or updates the session record.
|
|
375
|
+
- Updates the in-memory session cache.
|
|
376
|
+
- Once `getHistoryWindow` has supplied the current model size, reaching the precompression threshold starts background compression.
|
|
377
|
+
- Topic storage and cache replacement finish before conversation graph extraction; graph work remains asynchronous.
|
|
351
378
|
|
|
352
|
-
`flushChat(sessionId?, opts?)`:
|
|
379
|
+
`flushChat(sessionId?, opts?)`:
|
|
353
380
|
|
|
354
|
-
- Forces compression for the current cached messages even if
|
|
381
|
+
- Forces compression for the current cached raw messages even if the dynamic precompression threshold was not reached.
|
|
355
382
|
- `wait: true` waits for topic creation, cache clearing, and history-window rebuild.
|
|
356
383
|
- `wait: true` does not wait for graph extraction/persistence.
|
|
357
384
|
- `waitGraph: true` waits for graph extraction/persistence too.
|
|
358
|
-
- When `waitGraph: true`, graph waiting is bounded by `graphBuildTimeoutMs` and may throw a timeout error.
|
|
385
|
+
- When `waitGraph: true`, graph waiting is bounded by `graphBuildTimeoutMs` and may throw a timeout error.
|
|
386
|
+
|
|
387
|
+
`getHistoryWindow(sessionId, modelContextTokens?)`:
|
|
388
|
+
|
|
389
|
+
- Lazily hydrates the session from persistent Topics plus raw messages after the newest Topic boundary.
|
|
390
|
+
- Waits for registered message writes. If the hard raw budget is exceeded, it also waits for or starts compression until the returned context fits.
|
|
391
|
+
- Returns `{ compressedContext, recentMessages, usage }`. `recentMessages` preserves the `RawMessage` input shape, including `messageId`, `parts`, `payload`, `metadata`, and `createdAt`.
|
|
392
|
+
- Topic budget is fixed by manager configuration; the raw-message budget is recalculated from the supplied model context size.
|
|
393
|
+
- If accumulated Topics exceed their fixed budget, the oldest approximately half are summarized into one Topic. This Topic-to-Topic rollup does not rebuild graph data.
|
|
359
394
|
|
|
360
395
|
`addDocument(opts)`:
|
|
361
396
|
|
|
@@ -381,8 +416,9 @@ Use `wait: true` when the next line of code must immediately call `searchKnowled
|
|
|
381
416
|
- `sessionId?: string` - session id.
|
|
382
417
|
- `type?: "text" | "image" | "file"` - default: `"text"`.
|
|
383
418
|
- `content: string` - required plain text used for embedding and retrieval.
|
|
384
|
-
- `parts?: ContentPart[]` - optional multimodal content parts; stored serialized.
|
|
385
|
-
- `
|
|
419
|
+
- `parts?: ContentPart[]` - optional multimodal content parts; stored serialized.
|
|
420
|
+
- `payload?: unknown` - host-framework message payload stored and returned without interpretation.
|
|
421
|
+
- `usage?: number` - token count; estimated with `tiktoken` if omitted.
|
|
386
422
|
- `metadata?: Record<string, unknown>` - custom metadata stored as JSON.
|
|
387
423
|
- `createdAt?: number` - Unix milliseconds; default is current time.
|
|
388
424
|
|
|
@@ -394,21 +430,23 @@ Use `wait: true` when the next line of code must immediately call `searchKnowled
|
|
|
394
430
|
|
|
395
431
|
`StoredMessage` is persisted message output with required ids, serialized `parts`, serialized `metadata`, generated vector, and `createdAt`.
|
|
396
432
|
|
|
397
|
-
`Topic` is a compressed memory item:
|
|
398
|
-
|
|
399
|
-
- `title` - short topic title.
|
|
400
|
-
- `
|
|
401
|
-
- `
|
|
402
|
-
- `
|
|
403
|
-
- `startTime` and `endTime` - covered message time range.
|
|
404
|
-
- `recallCount` -
|
|
433
|
+
`Topic` is a compressed memory item:
|
|
434
|
+
|
|
435
|
+
- `title` - short topic title.
|
|
436
|
+
- `summary` - the only compressed body; its actual length is importance-aware and bounded by `topicSummaryMaxTokens`.
|
|
437
|
+
- `tokens` - summary token count stored when the Topic is created.
|
|
438
|
+
- `startMessageId` / `endMessageId` - exact raw-message boundaries, in addition to timestamps.
|
|
439
|
+
- `startTime` and `endTime` - covered message time range.
|
|
440
|
+
- `recallCount` - incremented best-effort when search recalls the Topic; it is not used to reorder the continuous history window.
|
|
405
441
|
|
|
406
|
-
`Fact` is a user/chat scoped manual memory:
|
|
442
|
+
`Fact` is a user/chat scoped manual memory:
|
|
407
443
|
|
|
408
444
|
- `level: "user" | "chat"`
|
|
409
445
|
- `userId`, `chatId`, optional `sessionId`
|
|
410
|
-
- `content`
|
|
411
|
-
- `
|
|
446
|
+
- `content`
|
|
447
|
+
- optional stable `key` for immediate cache + database upsert
|
|
448
|
+
- `createdAt`
|
|
449
|
+
- `updatedAt`
|
|
412
450
|
|
|
413
451
|
`Entity` and `Relation` are graph records:
|
|
414
452
|
|
|
@@ -460,13 +498,13 @@ Scopes:
|
|
|
460
498
|
- `scope: "user"` - filter by `userId`; pass `scopeId`.
|
|
461
499
|
- `scope: "all"` - no domain filter; `scopeId` is ignored.
|
|
462
500
|
|
|
463
|
-
Search modes:
|
|
501
|
+
Search modes:
|
|
464
502
|
|
|
465
|
-
- `mode: "fast"` - only
|
|
503
|
+
- `mode: "fast"` - only vector-store hybrid/vector retrieval. No graph search.
|
|
466
504
|
- `mode: "auto"` - conversation search asks the LLM whether graph search is needed; knowledge search triggers graph expansion only when top chunk score is high enough.
|
|
467
|
-
- `mode: "all"` - include graph search and merge graph results with vector/full-text results.
|
|
468
|
-
|
|
469
|
-
For deterministic low-latency calls, use `fast`. For richer entity relationship answers, use `auto` or `all`.
|
|
505
|
+
- `mode: "all"` - include graph search and merge graph results with vector/full-text results.
|
|
506
|
+
|
|
507
|
+
Conversation search always searches both compressed Topics and raw messages, including raw rows already represented by a Topic. For deterministic low-latency calls, use `fast`. For richer entity relationship answers, use `auto` or `all`.
|
|
470
508
|
|
|
471
509
|
## API Reference
|
|
472
510
|
|
|
@@ -474,9 +512,9 @@ For deterministic low-latency calls, use `fast`. For richer entity relationship
|
|
|
474
512
|
|
|
475
513
|
Creates the manager and resolves defaults. It does not connect to storage until `init()`.
|
|
476
514
|
|
|
477
|
-
### `init(): Promise<void>`
|
|
478
|
-
|
|
479
|
-
Initializes tiktoken,
|
|
515
|
+
### `init(): Promise<void>`
|
|
516
|
+
|
|
517
|
+
Initializes tiktoken, the vector store (backend auto-detection happens here), Grafeo, and the facts cache. Conversation sessions are hydrated lazily on first access and evicted after the configured idle timeout. Always call before using read/write APIs.
|
|
480
518
|
|
|
481
519
|
### `updateChat(messages, opts?): Promise<void>`
|
|
482
520
|
|
|
@@ -569,13 +607,19 @@ Context:
|
|
|
569
607
|
- `chatId?: string`
|
|
570
608
|
- `userId?: string`
|
|
571
609
|
|
|
572
|
-
### `getHistoryWindow(sessionId):
|
|
610
|
+
### `getHistoryWindow(sessionId, modelContextTokens?): Promise<MemoryContextWindow>`
|
|
611
|
+
|
|
612
|
+
Returns the complete model-history window:
|
|
613
|
+
|
|
614
|
+
- `compressedContext: string` - chronological Topic summaries within the fixed compressed budget.
|
|
615
|
+
- `recentMessages: MemoryRawMessage[]` - all currently uncompressed raw messages in chronological order, preserving the host payload and metadata.
|
|
616
|
+
- `usage` - model size, usable history size, compressed usage, and dynamic raw-message budget/usage.
|
|
617
|
+
|
|
618
|
+
Pass the active model's context size on every read. Omitting it uses `defaultModelContextTokens` (256K by default) and logs a warning.
|
|
573
619
|
|
|
574
|
-
|
|
620
|
+
### `getRecentMessages(sessionId, limit): Promise<StoredMessage[]>`
|
|
575
621
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
Returns the globally latest `limit` messages for a session in chronological order (oldest to newest within the returned window). The storage query orders by `createdAt` and uses `messageId` as a deterministic same-timestamp tiebreak before applying the limit, so long sessions do not return an early candidate window.
|
|
622
|
+
Returns the globally latest `limit` messages for a session in chronological order (oldest to newest within the returned window). The storage query orders by `createdAt` and uses `messageId` as a deterministic same-timestamp tiebreak before applying the limit, so long sessions do not return an early candidate window.
|
|
579
623
|
|
|
580
624
|
### Session APIs
|
|
581
625
|
|
|
@@ -590,7 +634,8 @@ Returns the globally latest `limit` messages for a session in chronological orde
|
|
|
590
634
|
Session update options:
|
|
591
635
|
|
|
592
636
|
- `title?: string`
|
|
593
|
-
- `metadata?: Record<string, unknown>`
|
|
637
|
+
- `metadata?: Record<string, unknown>`
|
|
638
|
+
- `scope?: "session" | "chat" | "user" | "all"` - content-hash deduplication boundary; default is `session`.
|
|
594
639
|
|
|
595
640
|
Session search options:
|
|
596
641
|
|
|
@@ -628,7 +673,7 @@ Options:
|
|
|
628
673
|
|
|
629
674
|
Deduplication:
|
|
630
675
|
|
|
631
|
-
- Documents are deduplicated by `sha256(content)` within the
|
|
676
|
+
- Documents are deduplicated by `sha256(content)` within the requested scope (`session` by default, or `chat` / `user` / `all`).
|
|
632
677
|
- If a duplicate exists, `addDocument` returns the existing `docId`.
|
|
633
678
|
|
|
634
679
|
Graph behavior:
|
|
@@ -673,11 +718,22 @@ Lists documents, optionally filtered by:
|
|
|
673
718
|
- `chatId`
|
|
674
719
|
- `sessionId`
|
|
675
720
|
|
|
676
|
-
### `destroy(): void
|
|
677
|
-
|
|
678
|
-
|
|
721
|
+
### `destroy(): Promise<void>`
|
|
722
|
+
|
|
723
|
+
Waits for registered writes, compression, graph work, and storage maintenance, then closes Grafeo and the vector store. It does not delete data.
|
|
679
724
|
|
|
680
|
-
## Common Recipes
|
|
725
|
+
## Common Recipes
|
|
726
|
+
|
|
727
|
+
### Migrate A 0.3.x Store
|
|
728
|
+
|
|
729
|
+
Stop all processes that write the store, then run the manual, idempotent migration. It backfills single-field Topic summaries/tokens/boundaries, raw-message usage, and fact timestamps without deleting raw messages or rerunning the LLM.
|
|
730
|
+
|
|
731
|
+
```bash
|
|
732
|
+
ppagent-memory migrate --config ./config.json --dry-run
|
|
733
|
+
ppagent-memory migrate --config ./config.json --backup ./memory-backup
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
The config loader accepts a direct `MemoryConfig`, `memory`, `app.memory.auto`, or `service.memory` object. `--dry-run` migrates a temporary copy. `--backup` copies both supported vector-store files/directories plus Grafeo data and writes rollback guidance before mutating the live store.
|
|
681
737
|
|
|
682
738
|
### Store User And Assistant Messages
|
|
683
739
|
|
|
@@ -691,14 +747,20 @@ await memory.updateChat(
|
|
|
691
747
|
);
|
|
692
748
|
```
|
|
693
749
|
|
|
694
|
-
### Force A Prompt-Ready History Window
|
|
695
|
-
|
|
696
|
-
```ts
|
|
697
|
-
await memory.flushChat("s1", { wait: true });
|
|
698
|
-
const history = memory.getHistoryWindow("s1");
|
|
699
|
-
|
|
700
|
-
const
|
|
701
|
-
|
|
750
|
+
### Force A Prompt-Ready History Window
|
|
751
|
+
|
|
752
|
+
```ts
|
|
753
|
+
await memory.flushChat("s1", { wait: true });
|
|
754
|
+
const history = await memory.getHistoryWindow("s1", 256 * 1024);
|
|
755
|
+
|
|
756
|
+
const promptMessages = [
|
|
757
|
+
{ role: "system", content: `更早对话摘要:\n${history.compressedContext}` },
|
|
758
|
+
...history.recentMessages.map((message) => ({
|
|
759
|
+
role: message.talkerId === "assistant" ? "assistant" : "user",
|
|
760
|
+
content: message.payload ?? message.content,
|
|
761
|
+
})),
|
|
762
|
+
];
|
|
763
|
+
```
|
|
702
764
|
|
|
703
765
|
### Wait For Conversation Graph Data
|
|
704
766
|
|
|
@@ -806,35 +868,36 @@ Conversation graph search only targets conversation graph data. Knowledge graph
|
|
|
806
868
|
## Best Practices
|
|
807
869
|
|
|
808
870
|
- Always call `await memory.init()` before using the manager.
|
|
809
|
-
- Always call `memory.destroy()` during shutdown to close
|
|
871
|
+
- Always call `await memory.destroy()` during shutdown to drain background work and close resources.
|
|
810
872
|
- Use stable `userId`, `chatId`, and `sessionId` values. They define memory isolation and retrieval scope.
|
|
811
873
|
- Use `scope: "user"` for personal memory, `scope: "chat"` for one agent/conversation channel, and `scope: "session"` for one short-lived conversation.
|
|
812
|
-
- Use `getFactsForContext` for stable facts and `getHistoryWindow` for compressed session history.
|
|
874
|
+
- Use `getFactsForContext` for stable facts and `getHistoryWindow` for compressed Topics plus recent raw session history.
|
|
813
875
|
- Use `updateFacts` for explicit facts that should not depend on LLM extraction.
|
|
814
876
|
- Use `updateEntity` when you already know structured entities and relations.
|
|
815
877
|
- Use `flushChat(..., { wait: true })` before reading `getHistoryWindow` in tests or immediate workflows.
|
|
816
878
|
- Use `addDocument(..., { wait: true })` before immediate knowledge search.
|
|
817
879
|
- Use `waitGraph: true` sparingly because graph extraction depends on LLM calls and can be slower.
|
|
818
|
-
- Keep `embeddingDimension` unchanged for an existing
|
|
880
|
+
- Keep `embeddingDimension` unchanged for an existing vector store unless you rebuild the database.
|
|
819
881
|
- Keep examples free of real API keys, tokens, personal data, and proprietary customer content.
|
|
820
882
|
|
|
821
883
|
## Common Pitfalls
|
|
822
884
|
|
|
823
885
|
- Forgetting `init()` before `updateChat` or search.
|
|
824
|
-
-
|
|
886
|
+
- Treating `getHistoryWindow` as synchronous or string-only. Since 0.4 it is async and returns a structured complete window.
|
|
887
|
+
- Omitting stable `messageId` when the host can update an existing assistant message; without it, an update becomes another raw message.
|
|
825
888
|
- Expecting `flushChat(..., { wait: true })` to wait for graph data. Use `waitGraph: true`.
|
|
826
889
|
- Expecting `addDocument(..., { wait: true })` to wait for graph data. Use `waitGraph: true`.
|
|
827
890
|
- Setting `waitGraph: true` without allowing enough `graphBuildTimeoutMs` for large documents.
|
|
828
891
|
- Using `scope: "session"` with a `chatId`, or `scope: "chat"` with a `userId`. `scopeId` must match the selected scope.
|
|
829
892
|
- Searching immediately after `addDocument` without `wait: true`; chunks may still be ingesting.
|
|
830
|
-
- Mixing embedding models with different vector dimensions in the same existing
|
|
893
|
+
- Mixing embedding models with different vector dimensions in the same existing vector store.
|
|
831
894
|
- Treating `metadata` as indexed arbitrary JSON. Store important filter dimensions in stable top-level ids where possible.
|
|
832
895
|
- Using `mode: "all"` for every query. It is richer but can be slower than `fast`.
|
|
833
896
|
|
|
834
897
|
## Security And Privacy
|
|
835
898
|
|
|
836
899
|
- Never hard-code real `llmApiKey` or `embeddingApiKey`.
|
|
837
|
-
- Treat LanceDB and Grafeo files as sensitive data stores.
|
|
900
|
+
- Treat vector store (LanceDB/SQLite) and Grafeo files as sensitive data stores.
|
|
838
901
|
- `content`, `metadata`, facts, and graph `meta` may contain private information.
|
|
839
902
|
- `destroy()` closes resources; it does not scrub data.
|
|
840
903
|
- Implement your own retention/deletion policy around `deleteSession`, `deleteDocument`, `deleteFact`, and storage directory cleanup.
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ppagent/memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "独立记忆系统模块,向量存储支持 LanceDB / SQLite(sqlite-vec) 双后端自动切换 + Grafeo 知识图谱",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ppagent-memory": "dist/cli.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"ppagent-source": "./src/index.ts",
|
|
@@ -25,29 +28,38 @@
|
|
|
25
28
|
"memory",
|
|
26
29
|
"rag",
|
|
27
30
|
"lancedb",
|
|
31
|
+
"sqlite",
|
|
32
|
+
"sqlite-vec",
|
|
28
33
|
"grafeo",
|
|
29
34
|
"vector",
|
|
30
|
-
"graph"
|
|
35
|
+
"graph",
|
|
36
|
+
"hybrid-search"
|
|
31
37
|
],
|
|
32
38
|
"author": "ppagent",
|
|
33
39
|
"license": "Apache-2.0",
|
|
34
40
|
"dependencies": {
|
|
35
41
|
"@dqbd/tiktoken": "^1.0.22",
|
|
36
42
|
"@grafeo-db/js": "^0.5.42",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
43
|
+
"better-sqlite3": "^11.8.1",
|
|
44
|
+
"jieba-wasm": "^2.4.0",
|
|
45
|
+
"sqlite-vec": "^0.1.9",
|
|
39
46
|
"uuid": "^10.0.0"
|
|
40
47
|
},
|
|
41
48
|
"devDependencies": {
|
|
49
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
42
50
|
"@types/node": "^22.0.0",
|
|
43
51
|
"@types/uuid": "^10.0.0",
|
|
44
52
|
"tsup": "^8.3.5",
|
|
45
53
|
"typescript": "^5.8.3",
|
|
46
54
|
"vitest": "^2.0.5"
|
|
47
55
|
},
|
|
56
|
+
"optionalDependencies": {
|
|
57
|
+
"@lancedb/lancedb": "^0.30.0",
|
|
58
|
+
"apache-arrow": "^18.1.0"
|
|
59
|
+
},
|
|
48
60
|
"scripts": {
|
|
49
|
-
"build": "tsup src/index.ts --format esm --dts --out-dir dist --clean",
|
|
50
|
-
"dev": "tsup src/index.ts --format esm --dts --out-dir dist --watch",
|
|
61
|
+
"build": "tsup src/index.ts --format esm --dts --out-dir dist --clean --external @lancedb/lancedb --external apache-arrow && tsup src/cli.ts --format esm --out-dir dist --external @lancedb/lancedb --external apache-arrow",
|
|
62
|
+
"dev": "tsup src/index.ts --format esm --dts --out-dir dist --watch --external @lancedb/lancedb --external apache-arrow",
|
|
51
63
|
"test": "vitest"
|
|
52
64
|
}
|
|
53
65
|
}
|