@ppagent/memory 0.1.2 → 0.1.4

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
@@ -371,7 +371,17 @@ interface MemoryConfig {
371
371
  * 不阻塞启动;嵌入式单进程使用时建议保持开启,否则 LanceDB 版本目录会无限膨胀、启动越来越慢。
372
372
  */
373
373
  autoOptimizeOnInit?: boolean;
374
- /** 压实时保留多久内的历史版本(毫秒,默认 0 即仅保留当前版本)。*/
374
+ /**
375
+ * 运行期定期压实的间隔(毫秒,默认 6 小时;设为 0 或负数关闭定时任务)。
376
+ * 长驻服务不重启时版本仍会随写入累积,靠该定时任务周期性回收。
377
+ * 定时器已 unref,不会阻止进程退出;destroy() 会清除。
378
+ */
379
+ autoOptimizeIntervalMs?: number;
380
+ /**
381
+ * 压实时保留多久内的历史版本(毫秒,默认 0 即仅保留当前版本)。
382
+ * 注意:运行期定期压实会对该值强制施加 60 秒下限,避免误删仍被在途查询引用的版本;
383
+ * 启动时的那次压实无在途查询,按原值执行。
384
+ */
375
385
  optimizeVersionRetentionMs?: number;
376
386
  /** 启动时恢复各会话历史窗口的并发数(默认 8,旧行为为逐会话串行)。*/
377
387
  restoreConcurrency?: number;
@@ -523,8 +533,12 @@ declare class MemoryManager {
523
533
  private readonly compressManager;
524
534
  private readonly knowledgeManager;
525
535
  private readonly sessionMap;
536
+ private optimizeTimer?;
537
+ private optimizeRunning;
526
538
  constructor(config: MemoryConfig);
527
539
  init(): Promise<void>;
540
+ /** 后台压实的统一入口:防重入(上一轮未结束则跳过),失败仅告警不影响服务。*/
541
+ private runBackgroundOptimize;
528
542
  /**
529
543
  * 手动触发存储压实与历史版本清理(init 后台会自动执行一次;上层维护任务也可调用)。
530
544
  * @param retentionMs 保留多久内的历史版本,默认取配置 optimizeVersionRetentionMs
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ function resolveConfig(config) {
47
47
  graphExtractConcurrency: config.graphExtractConcurrency ?? 2,
48
48
  graphBuildTimeoutMs: config.graphBuildTimeoutMs ?? 12e4,
49
49
  autoOptimizeOnInit: config.autoOptimizeOnInit ?? true,
50
+ autoOptimizeIntervalMs: config.autoOptimizeIntervalMs ?? 6 * 36e5,
50
51
  optimizeVersionRetentionMs: config.optimizeVersionRetentionMs ?? 0,
51
52
  restoreConcurrency: config.restoreConcurrency ?? 8
52
53
  };
@@ -1251,9 +1252,13 @@ var LanceService = class {
1251
1252
  }
1252
1253
  }
1253
1254
  async getLatestMessages(sessionId, limit) {
1255
+ if (limit <= 0) return [];
1254
1256
  try {
1255
- const rows = await this.messagesTable.query().where(eqFilter("session_id", sessionId)).limit(limit * 3).toArray();
1256
- return rows.sort((a, b) => Number(b.created_at) - Number(a.created_at)).slice(0, limit).reverse().map(rowToMessage);
1257
+ const rows = await this.messagesTable.query().where(eqFilter("session_id", sessionId)).orderBy([
1258
+ { columnName: "created_at", ascending: false },
1259
+ { columnName: "message_id", ascending: false }
1260
+ ]).limit(limit).toArray();
1261
+ return rows.reverse().map(rowToMessage);
1257
1262
  } catch {
1258
1263
  return [];
1259
1264
  }
@@ -2658,6 +2663,8 @@ var MemoryManager = class {
2658
2663
  compressManager;
2659
2664
  knowledgeManager;
2660
2665
  sessionMap = /* @__PURE__ */ new Map();
2666
+ optimizeTimer;
2667
+ optimizeRunning = false;
2661
2668
  constructor(config) {
2662
2669
  this.config = resolveConfig(config);
2663
2670
  this.lance = new LanceService(this.config);
@@ -2693,17 +2700,33 @@ var MemoryManager = class {
2693
2700
  }
2694
2701
  await this.restoreFromStorage();
2695
2702
  if (this.config.autoOptimizeOnInit) {
2696
- void this.optimizeStorage().then((results) => {
2697
- const versions = results.reduce((s, r) => s + r.oldVersionsRemoved, 0);
2698
- const fragments = results.reduce((s, r) => s + r.fragmentsRemoved, 0);
2699
- if (versions > 0 || fragments > 0) {
2700
- console.info(
2701
- `[MemoryManager] \u540E\u53F0\u5B58\u50A8\u538B\u5B9E\u5B8C\u6210\uFF1A\u6E05\u7406\u5386\u53F2\u7248\u672C ${versions} \u4E2A\uFF0C\u5408\u5E76\u788E\u7247 ${fragments} \u4E2A`
2702
- );
2703
- }
2704
- }).catch((err) => {
2705
- console.warn("[MemoryManager] \u540E\u53F0\u5B58\u50A8\u538B\u5B9E\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u670D\u52A1\uFF09:", err);
2706
- });
2703
+ void this.runBackgroundOptimize(this.config.optimizeVersionRetentionMs);
2704
+ }
2705
+ if (this.config.autoOptimizeIntervalMs > 0) {
2706
+ const retention = Math.max(this.config.optimizeVersionRetentionMs, 6e4);
2707
+ this.optimizeTimer = setInterval(() => {
2708
+ void this.runBackgroundOptimize(retention);
2709
+ }, this.config.autoOptimizeIntervalMs);
2710
+ this.optimizeTimer.unref?.();
2711
+ }
2712
+ }
2713
+ /** 后台压实的统一入口:防重入(上一轮未结束则跳过),失败仅告警不影响服务。*/
2714
+ async runBackgroundOptimize(retentionMs) {
2715
+ if (this.optimizeRunning) return;
2716
+ this.optimizeRunning = true;
2717
+ try {
2718
+ const results = await this.optimizeStorage(retentionMs);
2719
+ const versions = results.reduce((s, r) => s + r.oldVersionsRemoved, 0);
2720
+ const fragments = results.reduce((s, r) => s + r.fragmentsRemoved, 0);
2721
+ if (versions > 0 || fragments > 0) {
2722
+ console.info(
2723
+ `[MemoryManager] \u540E\u53F0\u5B58\u50A8\u538B\u5B9E\u5B8C\u6210\uFF1A\u6E05\u7406\u5386\u53F2\u7248\u672C ${versions} \u4E2A\uFF0C\u5408\u5E76\u788E\u7247 ${fragments} \u4E2A`
2724
+ );
2725
+ }
2726
+ } catch (err) {
2727
+ console.warn("[MemoryManager] \u540E\u53F0\u5B58\u50A8\u538B\u5B9E\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u670D\u52A1\uFF09:", err);
2728
+ } finally {
2729
+ this.optimizeRunning = false;
2707
2730
  }
2708
2731
  }
2709
2732
  /**
@@ -3113,6 +3136,10 @@ var MemoryManager = class {
3113
3136
  return page ? this.knowledgeManager.listDocuments(filter, page) : this.knowledgeManager.listDocuments(filter);
3114
3137
  }
3115
3138
  destroy() {
3139
+ if (this.optimizeTimer) {
3140
+ clearInterval(this.optimizeTimer);
3141
+ this.optimizeTimer = void 0;
3142
+ }
3116
3143
  this.grafeo.close();
3117
3144
  }
3118
3145
  };
package/llms.txt CHANGED
@@ -573,9 +573,9 @@ Context:
573
573
 
574
574
  Returns the compressed history window for a session. This is prompt-ready text built from recent `Topic` records using `topicRatio` and `historyWindowTokenLimit`.
575
575
 
576
- ### `getRecentMessages(sessionId, limit): Promise<StoredMessage[]>`
577
-
578
- Returns recent messages for a session.
576
+ ### `getRecentMessages(sessionId, limit): Promise<StoredMessage[]>`
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.
579
579
 
580
580
  ### Session APIs
581
581
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppagent/memory",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "独立记忆系统模块,基于 LanceDB + Grafeo 实现向量存储与知识图谱",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",