@ppagent/memory 0.4.4 → 0.4.6

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/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 complete raw conversation messages in a pluggable vector store (LanceDB or SQLite/sqlite-vec, auto-detected per platform), builds importance-aware Topic summaries, returns dynamically budgeted 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.
3
+ > `@ppagent/memory` is an independent TypeScript/Node.js long-term memory package for AI agents. It stores semantic raw conversation history in a pluggable vector store (LanceDB or SQLite/sqlite-vec, auto-detected per platform), strips historical image payloads, builds importance-aware Topic summaries, returns dynamically budgeted 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
 
@@ -154,8 +154,10 @@ const memory = new MemoryManager({
154
154
  topicCompactionSyncRatio: 1.25,
155
155
  contextUsageRatio: 0.75,
156
156
  precompressionRatio: 0.75,
157
- compressionBatchRatio: 0.5,
157
+ compressionBatchRatio: 0.7,
158
158
  compressionBatchTokenLimit: 0,
159
+ compressionMaxRetries: 2,
160
+ compressionRetryBaseDelayMs: 500,
159
161
  topicSummaryMaxTokens: 2048,
160
162
  defaultModelContextTokens: 256 * 1024,
161
163
  maxHistoryAgeMs: 0,
@@ -327,7 +329,7 @@ Embedding fallback behavior:
327
329
  HTTP and retry fields:
328
330
 
329
331
  - `httpTimeoutMs?: number` - timeout per LLM or embedding HTTP attempt. Default: `60000`.
330
- - `httpMaxRetries?: number` - retry count after the first attempt for network errors, timeout/abort, HTTP `429`, and HTTP `5xx`. Default: `2`.
332
+ - `httpMaxRetries?: number` - retry count after the first attempt for network errors, timeout/abort, HTTP `429`, HTTP `5xx`, and invalid JSON in a successful HTTP response. Default: `2`.
331
333
  - `embeddingBatchSize?: number` - max texts per embedding request. Default: `20`.
332
334
  - `embeddingConcurrency?: number` - concurrent embedding batches. Default: `2`.
333
335
 
@@ -337,14 +339,22 @@ Conversation memory fields:
337
339
  - `compressedContextRatio?: number` - maximum fraction of the usable model-history window assigned to Topics. Default: `0.10`. The effective Topic budget is the smaller of this ratio and `compressedContextTokenLimit`.
338
340
  - `topicCompactionSyncRatio?: number` - a cold-start Topic overage blocks `getHistoryWindow` only after it exceeds this multiple of the effective Topic budget, unless Topic plus raw history already exceeds the usable window. Default: `1.25`.
339
341
  - `contextUsageRatio?: number` - fraction of the current model context available to conversation history. Default: `0.75`.
340
- - `precompressionRatio?: number` - start background raw-message compression when raw usage reaches this fraction of its dynamic budget. Default: `0.75`.
341
- - `compressionBatchRatio?: number` - target fraction of the raw-message budget compressed in one batch. Default: `0.5`.
342
+ - `precompressionRatio?: number` - start background raw-message compression when raw usage reaches this fraction of its dynamic budget. Default: `0.60`, leaving enough headroom for normal runs while compression finishes.
343
+ - `compressionBatchRatio?: number` - target fraction of the current uncompressed raw-message tokens compressed from the oldest edge in one batch. Default: `0.7`, leaving the newest approximately `0.3` verbatim; complete conversation-group boundaries are atomic.
342
344
  - `compressionBatchTokenLimit?: number` - optional hard limit for one compression batch. Default: `0` (ratio only).
345
+ - `compressionMaxRetries?: number` - result-level retry count after the first compression-model attempt when the returned content is malformed, missing a summary, or empty. Default: `2`. Transport failures do not multiply this count because the HTTP layer already owns bounded retries.
346
+ - `compressionRetryBaseDelayMs?: number` - exponential-backoff base for result-level compression retries. Default: `500`; set `0` to retry immediately.
347
+ - `backgroundCompressionMaxRetries?: number` - whole-task retries after a background compression still fails (including exhausted HTTP attempts). Default: `2`, so at most three task waves run.
348
+ - `backgroundCompressionRetryBaseDelayMs?: number` - exponential-backoff base for whole-task background retries. Default: `1000`; set `0` to retry immediately.
349
+ - `onCompressionEvent?: (event) => void | Promise<void>` - receives contained raw/Topic compression `start`, `retry`, `success`, and `failure` lifecycle events with mode, attempts, token counts, latency, and error text. Callback failures never fail memory work.
343
350
  - `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`.
344
351
  - `defaultModelContextTokens?: number` - used when `getHistoryWindow` receives no model size; a warning is logged. Default: `262144`.
345
352
  - `maxHistoryAgeMs?: number` - maximum Topic and raw-message age restored during lazy cold start. Default: `0` (all history).
346
353
  - `sessionIdleTtlMs?: number` - idle time before a session cache is released. Persistent data is not deleted. Default: `1800000`.
347
354
  - `sessionSweepIntervalMs?: number` - idle cache sweep interval. Default: `60000`.
355
+ - `autoMigrateLegacyDataOnInit?: boolean` - run the idempotent 0.4 storage migration in the background once per data store, including full historical-image stripping. Default: `true`; a sidecar marker prevents a full scan on every restart.
356
+ - `autoResumeCompressionOnInit?: boolean` - scan persisted sessions in the background and resume raw windows that were eligible but not compressed before shutdown/failure. Default: `true`.
357
+ - `restoreConcurrency?: number` - bounded startup migration/recovery scan concurrency. Default: `8`.
348
358
  - `maxConcurrentCompressions?: number` - global semaphore limit for concurrent compression and knowledge ingestion tasks. Default: `3`.
349
359
  - `entitySimilarityThreshold?: number` - graph entity similarity threshold. Default: `0.92`.
350
360
  - `defaultSearchLimit?: number` - default `search` result limit. Default: `10`.
@@ -374,12 +384,15 @@ The package intentionally separates durable base writes from expensive graph con
374
384
  `updateChat(messages, opts)`:
375
385
 
376
386
  - Registers its write synchronously, so a caller may intentionally fire-and-forget it and a following `getHistoryWindow` will still wait for that write.
377
- - Calculates tokens over `content`, `parts`, `payload`, `contextPayload`, and `metadata`, embeds only the searchable text, and upserts raw messages by stable `messageId` before resolving.
378
- - `contextPayload` is a replay-only host payload: it is stored and returned unchanged and counts toward the raw budget, but is excluded from embedding, FTS, Topic-summary input, and conversation graph extraction.
379
- - Raw-message token usage always counts the complete stored `metadata`. When a raw batch is summarized, common tool-call/tool-result fields are removed only from the temporary LLM compression input; persisted metadata and uncompressed `recentMessages` remain unchanged.
387
+ - Recursively strips known historical image blocks (`image*` content parts and `file` parts with `image/*` media types) from `parts`, `payload`, `contextPayload`, and `metadata`, while preserving adjacent text, tool protocol, and non-image files. Legacy image rows are lazily repaired and written back when a session is first hydrated; the manual migration command performs the same repair.
388
+ - Persists optional `compressionGroupId` / `compressionRole` hints in a reserved internal metadata namespace and removes that namespace again on read. Host metadata remains unchanged.
389
+ - Calculates tokens over the sanitized `content`, `parts`, `payload`, `contextPayload`, and `metadata`, embeds only the searchable text, and upserts raw messages by stable `messageId` before resolving. If image removal changes a host payload, any host-supplied usage is recalculated against the stored form.
390
+ - `contextPayload` is a replay-only host payload: its non-image structure is stored and returned and counts toward the raw budget, but it is excluded from embedding, FTS, Topic-summary input, and conversation graph extraction.
391
+ - Raw-message token usage counts the complete sanitized stored `metadata`. When a raw batch is summarized, common tool-call/tool-result fields are removed only from the temporary LLM compression input; persisted non-image metadata and uncompressed `recentMessages` remain unchanged.
380
392
  - Creates or updates the session record.
381
393
  - Updates the in-memory session cache.
382
- - Once `getHistoryWindow` has supplied the current model size, reaching the precompression threshold starts background compression.
394
+ - Reaching the dynamic precompression threshold starts background compression. A failed task is retried with finite exponential backoff, and an unfinished eligible tail is discovered again during the next startup scan.
395
+ - Compression selects an oldest prefix of complete conversation groups. Explicit group ids are authoritative; older rows fall back to `user`/`assistant`/`tool`/`system` role inference. The newest complete group is kept verbatim whenever another group exists.
383
396
  - Topic storage and cache replacement finish before conversation graph extraction; graph work remains asynchronous.
384
397
 
385
398
  `flushChat(sessionId?, opts?)`:
@@ -394,7 +407,7 @@ The package intentionally separates durable base writes from expensive graph con
394
407
 
395
408
  - Lazily hydrates the session from persistent Topics plus raw messages after the newest Topic boundary.
396
409
  - Waits for registered message writes. If the hard raw budget is exceeded, it also waits for or starts compression until the returned context fits.
397
- - Returns `{ compressionRevision, compressedContext, recentMessages, usage }`. `recentMessages` preserves the `RawMessage` input shape, including `messageId`, `parts`, `payload`, `contextPayload`, `metadata`, and `createdAt`. `compressionRevision` changes when the returned Topic/raw compression boundary changes and is intended for host observability rather than optimistic locking.
410
+ - Returns `{ compressionRevision, compressedContext, recentMessages, usage }`. `recentMessages` preserves the sanitized `RawMessage` input shape, including `messageId`, non-image `parts`, `payload`, `contextPayload`, `metadata`, and `createdAt`. `compressionRevision` changes when the returned Topic/raw compression boundary changes and is intended for host observability rather than optimistic locking.
398
411
  - The effective Topic budget is `min(compressedContextTokenLimit, usableContextTokens * compressedContextRatio)`; the remaining usable history budget is reserved for raw messages.
399
412
  - Cold hydration always restores all persisted Topics and never silently truncates them. Each rollup summarizes the oldest approximately half of the current Topic tokens; a single oversized Topic is re-summarized by itself.
400
413
  - A small Topic-only overage returns immediately and schedules a transient background rollup for the next read. It blocks only when the overage exceeds `topicCompactionSyncRatio` or Topic plus raw history cannot fit the usable window.
@@ -424,9 +437,11 @@ Use `wait: true` when the next line of code must immediately call `searchKnowled
424
437
  - `sessionId?: string` - session id.
425
438
  - `type?: "text" | "image" | "file"` - default: `"text"`.
426
439
  - `content: string` - required plain text used for embedding and retrieval.
427
- - `parts?: ContentPart[]` - optional multimodal content parts; stored serialized.
428
- - `payload?: unknown` - host-framework message payload stored and returned without interpretation.
429
- - `contextPayload?: unknown` - replay-only host context stored and returned without interpretation. It counts toward the raw history budget but is excluded from retrieval, compression summaries, and graph extraction.
440
+ - `parts?: ContentPart[]` - optional multimodal content parts; non-image parts are stored serialized.
441
+ - `payload?: unknown` - host-framework message payload stored and returned after recursive historical-image stripping.
442
+ - `contextPayload?: unknown` - replay-only host context stored and returned after recursive historical-image stripping. Its remaining content counts toward the raw history budget but is excluded from retrieval, compression summaries, and graph extraction.
443
+ - `compressionGroupId?: string` - stable id shared by a user message and all assistant/tool messages in the same complete turn. Compression never splits this group.
444
+ - `compressionRole?: "user" | "assistant" | "tool" | "system"` - explicit role used for compatible grouping when no group id is supplied.
430
445
  - `usage?: number` - token count; estimated with `tiktoken` if omitted.
431
446
  - `metadata?: Record<string, unknown>` - custom metadata stored as JSON.
432
447
  - `createdAt?: number` - Unix milliseconds; default is current time.
@@ -523,7 +538,7 @@ Creates the manager and resolves defaults. It does not connect to storage until
523
538
 
524
539
  ### `init(): Promise<void>`
525
540
 
526
- 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.
541
+ Initializes tiktoken, the vector store (backend auto-detection happens here), Grafeo, and the facts cache. It then starts non-blocking startup maintenance: a marker-guarded full legacy/image migration and a bounded scan that resumes eligible unfinished compression. Conversation sessions remain available immediately and are evicted after the configured idle timeout. Always call before using read/write APIs.
527
542
 
528
543
  ### `updateChat(messages, opts?): Promise<void>`
529
544
 
@@ -622,7 +637,7 @@ Returns the complete model-history window:
622
637
 
623
638
  - `compressionRevision?: string` - lightweight identifier for the current Topic/raw compression boundary. Background or blocking compression changes it; ordinary raw appends are not guaranteed to do so.
624
639
  - `compressedContext: string` - chronological Topic summaries for the current model-size budget. A soft cold-start overage may be returned once while its transient rollup runs in the background.
625
- - `recentMessages: MemoryRawMessage[]` - all currently uncompressed raw messages in chronological order, preserving the host payload, replay-only context payload, and metadata.
640
+ - `recentMessages: MemoryRawMessage[]` - all currently uncompressed raw messages in chronological order, preserving sanitized non-image host payload, replay-only context payload, and metadata.
626
641
  - `usage` - model size, usable history size, compressed usage, and dynamic raw-message budget/usage.
627
642
 
628
643
  Pass the active model's context size on every read. Omitting it uses `defaultModelContextTokens` (256K by default) and logs a warning.
@@ -732,7 +747,7 @@ Lists documents, optionally filtered by:
732
747
 
733
748
  ### `destroy(): Promise<void>`
734
749
 
735
- Waits for registered writes, compression, graph work, and storage maintenance, then closes Grafeo and the vector store. It does not delete data.
750
+ Waits for registered writes, startup recovery, finite background compression retries, graph work, and storage maintenance, then closes Grafeo and the vector store. It does not delete data.
736
751
 
737
752
  ## Common Recipes
738
753
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppagent/memory",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "独立记忆系统模块,向量存储支持 LanceDB / SQLite(sqlite-vec) 双后端自动切换 + Grafeo 知识图谱",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",