@ppagent/memory 0.3.1 → 0.4.1

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/index.d.ts CHANGED
@@ -27,7 +27,7 @@ interface Paginated<T> {
27
27
  * 多模态消息的单个内容块,与 OpenAI content part 对齐
28
28
  */
29
29
  interface ContentPart {
30
- type: "text" | "image_url" | "file_url";
30
+ type: string;
31
31
  /** type 为 "text" 时的文本内容 */
32
32
  text?: string;
33
33
  /** type 为 "image_url" 时的图片信息 */
@@ -39,6 +39,8 @@ interface ContentPart {
39
39
  url: string;
40
40
  name?: string;
41
41
  };
42
+ /** 保留宿主框架自定义 content part,写入和回读时不丢字段。 */
43
+ [key: string]: unknown;
42
44
  }
43
45
  interface RawMessage {
44
46
  messageId?: string;
@@ -57,6 +59,8 @@ interface RawMessage {
57
59
  * 序列化后存入 LanceDB 的 parts 字段。
58
60
  */
59
61
  parts?: ContentPart[];
62
+ /** 宿主框架的原始消息载荷;记忆框架仅透明保存和回读。 */
63
+ payload?: unknown;
60
64
  usage?: number;
61
65
  metadata?: Record<string, unknown>;
62
66
  createdAt?: number;
@@ -72,6 +76,8 @@ interface StoredMessage {
72
76
  content: string;
73
77
  /** JSON.stringify(ContentPart[]),纯文本消息为 "[]" */
74
78
  parts: string;
79
+ /** JSON.stringify(payload),未提供时为 undefined。 */
80
+ payload?: string;
75
81
  usage: number;
76
82
  metadata: string;
77
83
  vector: number[];
@@ -84,9 +90,17 @@ interface Topic {
84
90
  chatId: string;
85
91
  /** 压缩时自动生成的主题标题(一句话),存量数据可能为空串 */
86
92
  title: string;
87
- detail: string;
93
+ /** 唯一的压缩正文。长度由内容重要性动态决定。 */
88
94
  summary: string;
89
- concise: string;
95
+ /** 压缩结果的 token 数;旧数据缺失时由本地 tokenizer 回填。 */
96
+ tokens: number;
97
+ /** 本 Topic 覆盖的首尾原始消息 id,便于同毫秒边界精确恢复。 */
98
+ startMessageId?: string;
99
+ endMessageId?: string;
100
+ /** @deprecated 仅用于读取尚未迁移的 0.3.x 数据。 */
101
+ detail?: string;
102
+ /** @deprecated 仅用于读取尚未迁移的 0.3.x 数据。 */
103
+ concise?: string;
90
104
  startTime: number;
91
105
  endTime: number;
92
106
  createdAt: number;
@@ -100,8 +114,12 @@ interface Fact {
100
114
  chatId: string;
101
115
  sessionId: string;
102
116
  userId: string;
117
+ /** 同一 level/owner 内用于 upsert 的稳定键;旧数据可能为空。 */
118
+ key?: string;
103
119
  content: string;
104
120
  createdAt: number;
121
+ /** 最近一次同 key 更新时刻;旧数据回落 createdAt。 */
122
+ updatedAt?: number;
105
123
  }
106
124
  interface EntityMeta {
107
125
  messageId?: string;
@@ -179,9 +197,9 @@ interface UpdateEntityOptions {
179
197
  interface CompressOutput {
180
198
  /** 自动生成的主题标题(一句话) */
181
199
  title: string;
182
- detail: string;
183
200
  summary: string;
184
- concise: string;
201
+ /** 模型报告的摘要输出 token;缺失时由本地 tokenizer 计算。 */
202
+ tokens?: number;
185
203
  entities: Array<{
186
204
  name: string;
187
205
  type: string;
@@ -198,10 +216,54 @@ interface CompressOutput {
198
216
  interface SessionEntry {
199
217
  messages: StoredMessage[];
200
218
  totalTokens: number;
219
+ topics: Topic[];
220
+ topicTokens: number;
201
221
  ids: {
202
222
  chatId: string;
203
223
  userId: string;
204
224
  };
225
+ lastModelContextTokens?: number;
226
+ lastAccessAt: number;
227
+ }
228
+ /** getHistoryWindow 返回的原始消息;字段形态与 updateChat 输入保持一致。 */
229
+ interface MemoryRawMessage {
230
+ messageId: string;
231
+ talkerId: string;
232
+ chatId: string;
233
+ userId: string;
234
+ sessionId: string;
235
+ type: MessageType;
236
+ content: string;
237
+ parts?: ContentPart[];
238
+ payload?: unknown;
239
+ usage: number;
240
+ metadata?: Record<string, unknown>;
241
+ createdAt: number;
242
+ }
243
+ interface MemoryContextWindowUsage {
244
+ modelContextTokens: number;
245
+ usableContextTokens: number;
246
+ compressedTokenLimit: number;
247
+ compressedTokens: number;
248
+ rawTokenLimit: number;
249
+ rawTokens: number;
250
+ }
251
+ type MemoryBlockingCompressionReason = "pending" | "raw" | "topics";
252
+ interface MemoryBlockingCompressionEvent {
253
+ sessionId: string;
254
+ phase: "start" | "end";
255
+ reason: MemoryBlockingCompressionReason;
256
+ }
257
+ interface GetHistoryWindowOptions {
258
+ /** 仅当前读取确实被压缩阻塞时调用;回调异常不会影响记忆读取。 */
259
+ onBlockingCompression?: (event: MemoryBlockingCompressionEvent) => void;
260
+ }
261
+ /** 固定预算的压缩记忆 + 近期未压缩原始消息。 */
262
+ interface MemoryContextWindow {
263
+ sessionId: string;
264
+ compressedContext: string;
265
+ recentMessages: MemoryRawMessage[];
266
+ usage: MemoryContextWindowUsage;
205
267
  }
206
268
  /** 是否为文档构建知识图谱:true/false 显式控制,"auto" 由内置 LLM 判定 */
207
269
  type BuildGraphMode = boolean | "auto";
@@ -264,6 +326,8 @@ interface AddDocumentOptions {
264
326
  userId?: string;
265
327
  chatId?: string;
266
328
  sessionId?: string;
329
+ /** 内容哈希去重范围;默认 session(兼容旧行为)。 */
330
+ scope?: SearchScope;
267
331
  /** 不传则从首个 H1 / sourceName 推断 */
268
332
  title?: string;
269
333
  sourceName?: string;
@@ -333,16 +397,46 @@ interface MemoryConfig {
333
397
  embeddingBatchSize?: number;
334
398
  /** embedding 批次并发数(默认 2)。*/
335
399
  embeddingConcurrency?: number;
400
+ /** 压缩 Topic 的全局存储上限,默认 16K。 */
401
+ compressedContextTokenLimit?: number;
402
+ /** Topic 最多占本次可用模型上下文的比例,默认 0.10。 */
403
+ compressedContextRatio?: number;
404
+ /** Topic 超过本次有效预算多少倍后必须同步归并,默认 1.25。 */
405
+ topicCompactionSyncRatio?: number;
406
+ /** 模型上下文中允许历史记忆使用的比例,默认 0.75。 */
407
+ contextUsageRatio?: number;
408
+ /** 原始消息达到其可用预算的此比例时后台预压缩,默认 0.75。 */
409
+ precompressionRatio?: number;
410
+ /** 单次压缩目标占原始消息预算的比例,默认 0.5。 */
411
+ compressionBatchRatio?: number;
412
+ /** 单次压缩硬上限;0 表示只受 compressionBatchRatio 控制。 */
413
+ compressionBatchTokenLimit?: number;
414
+ /** 单条 Topic 摘要硬上限,实际长度由重要性决定,默认 2048。 */
415
+ topicSummaryMaxTokens?: number;
416
+ /** 未传 getHistoryWindow 模型窗口时使用,默认 256K。 */
417
+ defaultModelContextTokens?: number;
418
+ /** 冷启动最多恢复多久以前的压缩 Topic;0 表示永久。 */
419
+ maxHistoryAgeMs?: number;
420
+ /** 会话缓存空闲释放时间,默认 30 分钟;<=0 关闭。 */
421
+ sessionIdleTtlMs?: number;
422
+ /** 空闲会话扫描周期,默认 1 分钟。 */
423
+ sessionSweepIntervalMs?: number;
424
+ /** @deprecated 0.3.x 原始消息固定阈值;仅为配置兼容保留。 */
336
425
  sessionTokenLimit?: number;
426
+ /** @deprecated 使用 compressedContextTokenLimit。 */
337
427
  historyWindowTokenLimit?: number;
428
+ /** @deprecated 三级 Topic 窗口已移除。 */
338
429
  topicRatio?: [number, number, number];
430
+ /** @deprecated 使用 topicSummaryMaxTokens。 */
339
431
  detailMaxTokens?: number;
432
+ /** 文档摘要仍使用此限制;对话 Topic 使用 topicSummaryMaxTokens。 */
340
433
  summaryMaxTokens?: number;
434
+ /** @deprecated 三级 Topic 窗口已移除。 */
341
435
  conciseMaxTokens?: number;
342
436
  maxConcurrentCompressions?: number;
343
437
  entitySimilarityThreshold?: number;
344
438
  defaultSearchLimit?: number;
345
- /** 每次召回相当于多少毫秒的时间权重加成(默认 3_600_000 即 1 小时)*/
439
+ /** @deprecated 连续历史窗口不再按召回热度重排。 */
346
440
  recallBoostMs?: number;
347
441
  /** 切块策略,目前仅 "markdown-heading"(默认)*/
348
442
  chunkStrategy?: "markdown-heading";
@@ -573,7 +667,14 @@ declare class MemoryManager {
573
667
  private readonly knowledgeManager;
574
668
  private readonly sessionMap;
575
669
  private optimizeTimer?;
670
+ private sessionSweepTimer?;
576
671
  private optimizeRunning;
672
+ private optimizeTask?;
673
+ private destroyTask?;
674
+ private readonly hydration;
675
+ private readonly pendingWrites;
676
+ private readonly topicCompactions;
677
+ private warnedDefaultModelContext;
577
678
  constructor(config: MemoryConfig);
578
679
  init(): Promise<void>;
579
680
  /** 后台压实的统一入口:防重入(上一轮未结束则跳过),失败仅告警不影响服务。*/
@@ -583,13 +684,17 @@ declare class MemoryManager {
583
684
  * @param retentionMs 保留多久内的历史版本,默认取配置 optimizeVersionRetentionMs
584
685
  */
585
686
  optimizeStorage(retentionMs?: number): Promise<StorageOptimizeResult[]>;
586
- private restoreFromStorage;
687
+ private ensureSessionHydrated;
688
+ private isSessionBusy;
689
+ private waitForPendingWrites;
690
+ private queueSessionWrite;
587
691
  updateChat(messages: RawMessage[], opts?: UpdateChatOptions): Promise<void>;
692
+ private doUpdateChat;
588
693
  flushChat(sessionId?: string, opts?: {
589
694
  wait?: boolean;
590
695
  waitGraph?: boolean;
591
696
  }): Promise<void>;
592
- updateFacts(content: string, level: FactLevel, userId: string, chatId: string, sessionId?: string): Promise<void>;
697
+ updateFacts(content: string, level: FactLevel, userId: string, chatId: string, sessionId?: string, key?: string): Promise<void>;
593
698
  updateEntity(entities: Entity[], relations: Relation[], context?: UpdateEntityOptions): Promise<void>;
594
699
  search(opts: SearchOptions): Promise<SearchResult[]>;
595
700
  ask(opts: SearchOptions & {
@@ -605,7 +710,10 @@ declare class MemoryManager {
605
710
  * 返回 user 级(userId) ∪ chat 级(chatId),按时间正序拼接。
606
711
  */
607
712
  getFactsForContext(userId: string, chatId: string): Promise<string>;
608
- getHistoryWindow(sessionId: string): string;
713
+ getHistoryWindow(sessionId: string, modelContextTokens?: number, options?: GetHistoryWindowOptions): Promise<MemoryContextWindow>;
714
+ private compactTopicsForBudget;
715
+ private notifyBlockingCompression;
716
+ private calculateWindowUsage;
609
717
  private buildScopeFilter;
610
718
  private deserializeSession;
611
719
  private serializeSession;
@@ -691,7 +799,7 @@ declare class MemoryManager {
691
799
  /** 由 chatId 反查所属 userId:优先用会话表映射,兜底用 chat 级 fact 自身。 */
692
800
  private resolveChatOwner;
693
801
  /** 手动新增一条事实 */
694
- addFact(content: string, level: FactLevel, userId: string, chatId: string, sessionId?: string): Promise<void>;
802
+ addFact(content: string, level: FactLevel, userId: string, chatId: string, sessionId?: string, key?: string): Promise<void>;
695
803
  /** 删除单条事实,返回是否命中 */
696
804
  deleteFact(factId: string): Promise<boolean>;
697
805
  /**
@@ -742,9 +850,32 @@ declare class MemoryManager {
742
850
  chatId?: string;
743
851
  sessionId?: string;
744
852
  } | undefined, page: PageParams): Promise<Paginated<Document>>;
745
- destroy(): void;
853
+ destroy(): Promise<void>;
746
854
  }
747
855
 
856
+ interface MemoryContextBudget {
857
+ modelContextTokens: number;
858
+ usableContextTokens: number;
859
+ compressedTokenLimit: number;
860
+ rawTokenLimit: number;
861
+ }
862
+ /**
863
+ * 统一计算一次 history window 的 Topic / raw 预算。
864
+ *
865
+ * Topic 同时受全局质量上限和当前模型比例约束;最后保留至少 1 token raw 空间,
866
+ * 避免小窗口模型被固定 Topic 上限完全挤空。
867
+ */
868
+ declare function calculateContextBudget(config: Pick<ResolvedConfig, "contextUsageRatio" | "compressedContextRatio" | "compressedContextTokenLimit">, modelContextTokens: number): MemoryContextBudget;
869
+
870
+ interface MemoryMigrationReport {
871
+ provider: string;
872
+ topicsScanned: number;
873
+ topicsUpdated: number;
874
+ messagesScanned: number;
875
+ messagesUpdated: number;
876
+ factsScanned: number;
877
+ factsUpdated: number;
878
+ }
748
879
  /**
749
880
  * 记忆系统的存储域层:保持原 LanceService 的公开方法面,内部组合
750
881
  * VectorStoreProvider 的通用原语实现。业务逻辑(混合检索融合、话题回退、
@@ -766,7 +897,12 @@ declare class MemoryStore {
766
897
  */
767
898
  optimizeStorage(retentionMs?: number): Promise<StorageOptimizeResult[]>;
768
899
  addMessages(messages: StoredMessage[]): Promise<void>;
900
+ /** 0.3.x → 0.4.x 数据回填;幂等,不调用 LLM、不删除原始消息。 */
901
+ migrateLegacyData(): Promise<MemoryMigrationReport>;
902
+ /** message_id 稳定时更新原行,否则新增;用于流式 assistant 消息最终态覆盖。 */
903
+ upsertMessages(messages: StoredMessage[]): Promise<void>;
769
904
  getMessagesSince(sessionId: string, since: number, limit?: number): Promise<StoredMessage[]>;
905
+ getMessagesAfterBoundary(sessionId: string, endTime: number, endMessageId?: string): Promise<StoredMessage[]>;
770
906
  getLatestMessages(sessionId: string, limit: number): Promise<StoredMessage[]>;
771
907
  /** 取某会话的全部消息(按 createdAt 升序),供管理面板分页切片使用 */
772
908
  getAllMessagesBySession(sessionId: string): Promise<StoredMessage[]>;
@@ -782,7 +918,10 @@ declare class MemoryStore {
782
918
  private hybridSearch;
783
919
  private keyColumnOf;
784
920
  addTopic(topic: Topic): Promise<void>;
921
+ updateTopic(topic: Topic): Promise<void>;
785
922
  updateTopicRecallCount(summaryId: string, count: number): Promise<void>;
923
+ incrementTopicRecallCounts(topics: Topic[]): Promise<void>;
924
+ getTopicsBySession(sessionId: string, since?: number): Promise<Topic[]>;
786
925
  getRecentTopics(chatId: string, userId: string, n1: number, n2: number, n3: number): Promise<{
787
926
  detail: Topic[];
788
927
  summary: Topic[];
@@ -791,7 +930,9 @@ declare class MemoryStore {
791
930
  /** 全量读取 topics(管理面板列表用,不做 recall 加权排序,按 endTime 倒序)*/
792
931
  getAllTopics(): Promise<Topic[]>;
793
932
  deleteTopicsBySession(sessionId: string): Promise<void>;
933
+ deleteTopicsByIds(summaryIds: string[]): Promise<void>;
794
934
  saveFact(fact: Fact): Promise<void>;
935
+ updateFact(fact: Fact): Promise<void>;
795
936
  getAllFacts(): Promise<Fact[]>;
796
937
  /** 删除单条 fact */
797
938
  deleteFact(factId: string): Promise<void>;
@@ -864,4 +1005,4 @@ type RelationType = (typeof DEFAULT_RELATION_TYPES)[number];
864
1005
  declare const KIND_CONVERSATION = "conversation";
865
1006
  declare const KIND_KNOWLEDGE = "knowledge";
866
1007
 
867
- export { type AddDocumentOptions, type BuildGraphMode, type Chunk, type ChunkHit, type ChunkPiece, type CompressOutput, type ContentPart, DEFAULT_NODE_TYPES, DEFAULT_RELATION_TYPES, type Document, type DomainIds, type Entity, type EntityMeta, type Fact, type FactLevel, type Filter, type FilterCondition, KIND_CONVERSATION, KIND_KNOWLEDGE, type KnowledgeSearchOptions, type KnowledgeSearchResult, type MemoryConfig, MemoryManager, MemoryStore, type MessageType, type NodeType, type PageParams, type Paginated, type ProviderCapabilities, type ProviderKind, type RawMessage, type Relation, type RelationType, type SearchMode, type SearchOptions, type SearchResult, type SearchScope, type Session, type SessionEntry, type SessionSearchOptions, type SessionView, type StorageOptimizeResult, type StoredMessage, type Topic, type UpdateChatOptions, type UpdateEntityOptions, type UpdateSessionOptions, type VectorStoreProvider };
1008
+ export { type AddDocumentOptions, type BuildGraphMode, type Chunk, type ChunkHit, type ChunkPiece, type CompressOutput, type ContentPart, DEFAULT_NODE_TYPES, DEFAULT_RELATION_TYPES, type Document, type DomainIds, type Entity, type EntityMeta, type Fact, type FactLevel, type Filter, type FilterCondition, type GetHistoryWindowOptions, KIND_CONVERSATION, KIND_KNOWLEDGE, type KnowledgeSearchOptions, type KnowledgeSearchResult, type MemoryBlockingCompressionEvent, type MemoryBlockingCompressionReason, type MemoryConfig, type MemoryContextBudget, type MemoryContextWindow, type MemoryContextWindowUsage, MemoryManager, type MemoryMigrationReport, type MemoryRawMessage, MemoryStore, type MessageType, type NodeType, type PageParams, type Paginated, type ProviderCapabilities, type ProviderKind, type RawMessage, type Relation, type RelationType, type SearchMode, type SearchOptions, type SearchResult, type SearchScope, type Session, type SessionEntry, type SessionSearchOptions, type SessionView, type StorageOptimizeResult, type StoredMessage, type Topic, type UpdateChatOptions, type UpdateEntityOptions, type UpdateSessionOptions, type VectorStoreProvider, calculateContextBudget };