openclaw-cortex-memory 0.1.0-Alpha.3 → 0.1.0-Alpha.5

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 (55) hide show
  1. package/README.md +101 -18
  2. package/SKILL.md +79 -9
  3. package/dist/index.d.ts +18 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +159 -7
  6. package/dist/index.js.map +1 -1
  7. package/dist/openclaw.plugin.json +101 -1
  8. package/dist/src/dedup/three_stage_deduplicator.d.ts +25 -0
  9. package/dist/src/dedup/three_stage_deduplicator.d.ts.map +1 -0
  10. package/dist/src/dedup/three_stage_deduplicator.js +225 -0
  11. package/dist/src/dedup/three_stage_deduplicator.js.map +1 -0
  12. package/dist/src/engine/ts_engine.d.ts +36 -0
  13. package/dist/src/engine/ts_engine.d.ts.map +1 -1
  14. package/dist/src/engine/ts_engine.js +197 -32
  15. package/dist/src/engine/ts_engine.js.map +1 -1
  16. package/dist/src/engine/types.d.ts +4 -0
  17. package/dist/src/engine/types.d.ts.map +1 -1
  18. package/dist/src/graph/ontology.d.ts +53 -0
  19. package/dist/src/graph/ontology.d.ts.map +1 -0
  20. package/dist/src/graph/ontology.js +252 -0
  21. package/dist/src/graph/ontology.js.map +1 -0
  22. package/dist/src/reflect/reflector.d.ts +7 -0
  23. package/dist/src/reflect/reflector.d.ts.map +1 -1
  24. package/dist/src/reflect/reflector.js +75 -1
  25. package/dist/src/reflect/reflector.js.map +1 -1
  26. package/dist/src/session/session_end.d.ts +55 -0
  27. package/dist/src/session/session_end.d.ts.map +1 -1
  28. package/dist/src/session/session_end.js +237 -51
  29. package/dist/src/session/session_end.js.map +1 -1
  30. package/dist/src/store/archive_store.d.ts +89 -0
  31. package/dist/src/store/archive_store.d.ts.map +1 -0
  32. package/dist/src/store/archive_store.js +242 -0
  33. package/dist/src/store/archive_store.js.map +1 -0
  34. package/dist/src/store/read_store.d.ts +39 -0
  35. package/dist/src/store/read_store.d.ts.map +1 -1
  36. package/dist/src/store/read_store.js +796 -15
  37. package/dist/src/store/read_store.js.map +1 -1
  38. package/dist/src/store/vector_store.d.ts +30 -0
  39. package/dist/src/store/vector_store.d.ts.map +1 -0
  40. package/dist/src/store/vector_store.js +127 -0
  41. package/dist/src/store/vector_store.js.map +1 -0
  42. package/dist/src/store/write_store.d.ts +8 -0
  43. package/dist/src/store/write_store.d.ts.map +1 -1
  44. package/dist/src/store/write_store.js +70 -0
  45. package/dist/src/store/write_store.js.map +1 -1
  46. package/dist/src/sync/session_sync.d.ts +7 -0
  47. package/dist/src/sync/session_sync.d.ts.map +1 -1
  48. package/dist/src/sync/session_sync.js +120 -10
  49. package/dist/src/sync/session_sync.js.map +1 -1
  50. package/openclaw.plugin.json +101 -1
  51. package/package.json +16 -5
  52. package/scripts/cli.js +6 -1
  53. package/scripts/uninstall.js +15 -4
  54. package/index.ts +0 -2142
  55. package/scripts/install.js +0 -27
package/dist/index.js CHANGED
@@ -46,10 +46,13 @@ const net = __importStar(require("net"));
46
46
  const ts_engine_1 = require("./src/engine/ts_engine");
47
47
  const read_store_1 = require("./src/store/read_store");
48
48
  const write_store_1 = require("./src/store/write_store");
49
+ const archive_store_1 = require("./src/store/archive_store");
50
+ const vector_store_1 = require("./src/store/vector_store");
49
51
  const session_sync_1 = require("./src/sync/session_sync");
50
52
  const session_end_1 = require("./src/session/session_end");
51
53
  const rule_store_1 = require("./src/rules/rule_store");
52
54
  const reflector_1 = require("./src/reflect/reflector");
55
+ const three_stage_deduplicator_1 = require("./src/dedup/three_stage_deduplicator");
53
56
  const ERROR_CODES = {
54
57
  CONNECTION_REFUSED: {
55
58
  code: "E001",
@@ -89,6 +92,40 @@ const MAX_OPENCLAW_VERSION = "2027.0.0";
89
92
  const defaultConfig = {
90
93
  autoSync: true,
91
94
  autoReflect: false,
95
+ autoReflectIntervalMinutes: 30,
96
+ readFusion: {
97
+ enabled: true,
98
+ maxCandidates: 10,
99
+ authoritative: true,
100
+ },
101
+ memoryDecay: {
102
+ enabled: true,
103
+ minFloor: 0.15,
104
+ defaultHalfLifeDays: 90,
105
+ antiDecay: {
106
+ enabled: true,
107
+ maxBoost: 1.6,
108
+ hitWeight: 0.08,
109
+ recentWindowDays: 30,
110
+ },
111
+ halfLifeByEventType: {
112
+ issue: 30,
113
+ fix: 30,
114
+ action_item: 30,
115
+ blocker: 30,
116
+ plan: 60,
117
+ milestone: 60,
118
+ follow_up: 60,
119
+ decision: 120,
120
+ insight: 120,
121
+ retrospective: 120,
122
+ preference: 240,
123
+ constraint: 240,
124
+ requirement: 240,
125
+ dependency: 240,
126
+ assumption: 240,
127
+ },
128
+ },
92
129
  enabled: true,
93
130
  fallbackToBuiltin: true,
94
131
  engineMode: "ts",
@@ -192,11 +229,33 @@ function resolveEngine() {
192
229
  projectRoot,
193
230
  dbPath: config.dbPath,
194
231
  logger,
232
+ embedding: config.embedding,
233
+ reranker: config.reranker,
234
+ llm: config.llm,
235
+ fusion: config.readFusion,
236
+ memoryDecay: config.memoryDecay,
195
237
  });
196
238
  const writeStore = (0, write_store_1.createWriteStore)({
197
239
  projectRoot,
198
240
  dbPath: config.dbPath,
199
241
  logger,
242
+ embedding: config.embedding,
243
+ });
244
+ const vectorStore = (0, vector_store_1.createVectorStore)({
245
+ memoryRoot,
246
+ logger,
247
+ });
248
+ const deduplicator = (0, three_stage_deduplicator_1.createThreeStageDeduplicator)({
249
+ memoryRoot,
250
+ logger,
251
+ });
252
+ const archiveStore = (0, archive_store_1.createArchiveStore)({
253
+ projectRoot,
254
+ memoryRoot,
255
+ logger,
256
+ embedding: config.embedding,
257
+ deduplicator,
258
+ vectorStore,
200
259
  });
201
260
  const sessionSync = (0, session_sync_1.createSessionSync)({
202
261
  projectRoot,
@@ -209,6 +268,9 @@ function resolveEngine() {
209
268
  dbPath: config.dbPath,
210
269
  logger,
211
270
  syncMemory: sessionSync.syncMemory,
271
+ syncDailySummaries: sessionSync.syncDailySummaries,
272
+ archiveStore,
273
+ llm: config.llm,
212
274
  });
213
275
  const ruleStore = (0, rule_store_1.createRuleStore)({
214
276
  projectRoot,
@@ -220,14 +282,17 @@ function resolveEngine() {
220
282
  dbPath: config.dbPath,
221
283
  logger,
222
284
  ruleStore,
285
+ llm: config.llm,
223
286
  });
224
287
  memoryEngine = (0, ts_engine_1.createTsEngine)({
225
288
  readStore,
226
289
  writeStore,
290
+ archiveStore,
227
291
  sessionSync,
228
292
  sessionEnd,
229
293
  reflector,
230
294
  memoryRoot,
295
+ projectRoot,
231
296
  getCachedAutoSearch: getSessionCachedAutoSearch,
232
297
  resolveSessionId: (context, payload) => resolveSessionId(context, payload),
233
298
  normalizeIncomingMessage,
@@ -285,6 +350,15 @@ function sanitizeForLogging(obj) {
285
350
  }
286
351
  return sanitized;
287
352
  }
353
+ function logLifecycle(event, details = {}) {
354
+ const payload = sanitizeForLogging({
355
+ event,
356
+ plugin: PLUGIN_ID,
357
+ ts: new Date().toISOString(),
358
+ ...details,
359
+ });
360
+ logger.info(`[Lifecycle] ${JSON.stringify(payload)}`);
361
+ }
288
362
  function asRecord(value) {
289
363
  if (typeof value === "object" && value !== null) {
290
364
  return value;
@@ -443,13 +517,19 @@ function findProjectRoot() {
443
517
  throw new Error("Cannot find project root directory");
444
518
  }
445
519
  function findOpenClawConfig() {
520
+ const explicitConfigPath = process.env.OPENCLAW_CONFIG_PATH || "";
521
+ const stateDir = process.env.OPENCLAW_STATE_DIR || "";
522
+ const basePath = process.env.OPENCLAW_BASE_PATH || "";
523
+ const homePath = process.env.USERPROFILE || process.env.HOME || "";
446
524
  const possiblePaths = [
525
+ explicitConfigPath,
526
+ stateDir ? path.join(stateDir, "openclaw.json") : "",
527
+ basePath ? path.join(basePath, "openclaw.json") : "",
447
528
  path.join(process.cwd(), "openclaw.json"),
448
- path.join(process.env.USERPROFILE || process.env.HOME || "", ".openclaw", "openclaw.json"),
449
- path.join(process.env.OPENCLAW_BASE_PATH || "", "openclaw.json"),
529
+ homePath ? path.join(homePath, ".openclaw", "openclaw.json") : "",
450
530
  ];
451
531
  for (const p of possiblePaths) {
452
- if (fs.existsSync(p)) {
532
+ if (p && fs.existsSync(p)) {
453
533
  return p;
454
534
  }
455
535
  }
@@ -504,6 +584,8 @@ function startAutoReflectScheduler() {
504
584
  if (!config?.autoReflect || autoReflectInterval) {
505
585
  return;
506
586
  }
587
+ const intervalMinutes = Math.max(5, Math.floor(config.autoReflectIntervalMinutes ?? 30));
588
+ const intervalMs = intervalMinutes * 60 * 1000;
507
589
  autoReflectInterval = setInterval(() => {
508
590
  if (!isEnabled) {
509
591
  return;
@@ -520,7 +602,7 @@ function startAutoReflectScheduler() {
520
602
  if (marker === lastAutoReflectArchiveMarker) {
521
603
  return;
522
604
  }
523
- if (now - lastAutoReflectRunAt < 5 * 60 * 1000) {
605
+ if (now - lastAutoReflectRunAt < intervalMs) {
524
606
  return;
525
607
  }
526
608
  resolveEngine().reflectMemory({}, schedulerContext)
@@ -535,7 +617,7 @@ function startAutoReflectScheduler() {
535
617
  }
536
618
  })
537
619
  .catch(error => logger.warn(`Auto-reflect failed: ${String(error)}`));
538
- }, 5 * 60 * 1000);
620
+ }, intervalMs);
539
621
  }
540
622
  function stopAutoReflectScheduler() {
541
623
  if (autoReflectInterval) {
@@ -563,6 +645,41 @@ function validateConfig(cfg) {
563
645
  if (!cfg.reranker?.apiKey || !cfg.reranker?.baseURL) {
564
646
  errors.push("reranker.apiKey and reranker.baseURL are required. Please configure third-party reranker endpoint credentials.");
565
647
  }
648
+ if (typeof cfg.autoReflectIntervalMinutes === "number" && (!Number.isFinite(cfg.autoReflectIntervalMinutes) || cfg.autoReflectIntervalMinutes < 5)) {
649
+ errors.push("autoReflectIntervalMinutes must be a number >= 5.");
650
+ }
651
+ if (cfg.readFusion && typeof cfg.readFusion.maxCandidates === "number" && (!Number.isFinite(cfg.readFusion.maxCandidates) || cfg.readFusion.maxCandidates < 2)) {
652
+ errors.push("readFusion.maxCandidates must be a number >= 2.");
653
+ }
654
+ if (cfg.memoryDecay) {
655
+ if (typeof cfg.memoryDecay.minFloor === "number" && (!Number.isFinite(cfg.memoryDecay.minFloor) || cfg.memoryDecay.minFloor < 0 || cfg.memoryDecay.minFloor > 1)) {
656
+ errors.push("memoryDecay.minFloor must be within [0,1].");
657
+ }
658
+ if (typeof cfg.memoryDecay.defaultHalfLifeDays === "number" && (!Number.isFinite(cfg.memoryDecay.defaultHalfLifeDays) || cfg.memoryDecay.defaultHalfLifeDays <= 0)) {
659
+ errors.push("memoryDecay.defaultHalfLifeDays must be > 0.");
660
+ }
661
+ const mapping = cfg.memoryDecay.halfLifeByEventType;
662
+ if (mapping && typeof mapping === "object") {
663
+ for (const [key, value] of Object.entries(mapping)) {
664
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
665
+ errors.push(`memoryDecay.halfLifeByEventType.${key} must be > 0.`);
666
+ break;
667
+ }
668
+ }
669
+ }
670
+ const anti = cfg.memoryDecay.antiDecay;
671
+ if (anti) {
672
+ if (typeof anti.maxBoost === "number" && (!Number.isFinite(anti.maxBoost) || anti.maxBoost < 1)) {
673
+ errors.push("memoryDecay.antiDecay.maxBoost must be >= 1.");
674
+ }
675
+ if (typeof anti.hitWeight === "number" && (!Number.isFinite(anti.hitWeight) || anti.hitWeight < 0)) {
676
+ errors.push("memoryDecay.antiDecay.hitWeight must be >= 0.");
677
+ }
678
+ if (typeof anti.recentWindowDays === "number" && (!Number.isFinite(anti.recentWindowDays) || anti.recentWindowDays <= 0)) {
679
+ errors.push("memoryDecay.antiDecay.recentWindowDays must be > 0.");
680
+ }
681
+ }
682
+ }
566
683
  return errors;
567
684
  }
568
685
  function getApiHostAndPort() {
@@ -1393,13 +1510,15 @@ async function onTimerPythonHandler(payload, _context) {
1393
1510
  }
1394
1511
  }
1395
1512
  async function onMessageHandler(payload, context) {
1396
- if (isInternalSession(context.sessionId)) {
1513
+ const sessionId = resolveSessionId(context, payload);
1514
+ if (isInternalSession(sessionId)) {
1397
1515
  return;
1398
1516
  }
1399
1517
  await runWithTimeout(resolveEngine().onMessage(payload, context), HOOK_GUARD_TIMEOUT_MS, "onMessage hook");
1400
1518
  }
1401
1519
  async function onSessionEndHandler(payload, context) {
1402
- if (isInternalSession(context.sessionId)) {
1520
+ const sessionId = resolveSessionId(context, payload);
1521
+ if (isInternalSession(sessionId)) {
1403
1522
  return;
1404
1523
  }
1405
1524
  await runWithTimeout(resolveEngine().onSessionEnd(payload, context), HOOK_GUARD_TIMEOUT_MS, "onSessionEnd hook");
@@ -1700,6 +1819,7 @@ async function enable() {
1700
1819
  return;
1701
1820
  }
1702
1821
  logger.info("Enabling Cortex Memory plugin...");
1822
+ logLifecycle("enable_start");
1703
1823
  try {
1704
1824
  unregisterFallbackTools();
1705
1825
  if (shouldUsePythonRuntime()) {
@@ -1711,10 +1831,12 @@ async function enable() {
1711
1831
  registerHooks();
1712
1832
  startAutoReflectScheduler();
1713
1833
  logger.info("Cortex Memory plugin enabled successfully");
1834
+ logLifecycle("enable_success", { registeredTools: registeredTools.length, registeredHooks: registeredHooks.length });
1714
1835
  }
1715
1836
  catch (error) {
1716
1837
  const message = error instanceof Error ? error.message : String(error);
1717
1838
  logger.error(`Failed to enable Cortex Memory plugin: ${message}`);
1839
+ logLifecycle("enable_failed", { error: message });
1718
1840
  throw error;
1719
1841
  }
1720
1842
  }
@@ -1724,6 +1846,7 @@ async function disable() {
1724
1846
  return;
1725
1847
  }
1726
1848
  logger.info("Disabling Cortex Memory plugin...");
1849
+ logLifecycle("disable_start");
1727
1850
  unregisterHooks();
1728
1851
  unregisterTools();
1729
1852
  unregisterFallbackTools();
@@ -1736,8 +1859,10 @@ async function disable() {
1736
1859
  if (config?.fallbackToBuiltin && builtinMemory) {
1737
1860
  logger.info("Falling back to OpenClaw builtin memory system");
1738
1861
  registerFallbackTools();
1862
+ logLifecycle("fallback_enabled", { fallbackTools: registeredFallbackTools.length });
1739
1863
  }
1740
1864
  logger.info("Cortex Memory plugin disabled successfully");
1865
+ logLifecycle("disable_success", { fallbackEnabled: registeredFallbackTools.length > 0 });
1741
1866
  }
1742
1867
  function registerFallbackTools() {
1743
1868
  if (!api || !builtinMemory)
@@ -1805,6 +1930,7 @@ function getStatus() {
1805
1930
  }
1806
1931
  async function unregister() {
1807
1932
  logger.info("Unregistering Cortex Memory plugin...");
1933
+ logLifecycle("unregister_start");
1808
1934
  stopConfigWatcher();
1809
1935
  stopAutoReflectScheduler();
1810
1936
  unregisterHooks();
@@ -1831,6 +1957,7 @@ async function unregister() {
1831
1957
  stopAutoReflectScheduler();
1832
1958
  configPath = null;
1833
1959
  logger.info("Cortex Memory plugin unregistered successfully");
1960
+ logLifecycle("unregister_success");
1834
1961
  }
1835
1962
  function register(pluginApi, userConfig) {
1836
1963
  if (isInitializing || isRegistered) {
@@ -1866,6 +1993,24 @@ function register(pluginApi, userConfig) {
1866
1993
  dbPath: effectiveConfig.dbPath,
1867
1994
  autoSync: effectiveConfig.autoSync ?? defaultConfig.autoSync,
1868
1995
  autoReflect: effectiveConfig.autoReflect ?? defaultConfig.autoReflect,
1996
+ autoReflectIntervalMinutes: effectiveConfig.autoReflectIntervalMinutes ?? defaultConfig.autoReflectIntervalMinutes,
1997
+ readFusion: {
1998
+ enabled: effectiveConfig.readFusion?.enabled ?? defaultConfig.readFusion?.enabled,
1999
+ maxCandidates: effectiveConfig.readFusion?.maxCandidates ?? defaultConfig.readFusion?.maxCandidates,
2000
+ authoritative: effectiveConfig.readFusion?.authoritative ?? defaultConfig.readFusion?.authoritative,
2001
+ },
2002
+ memoryDecay: {
2003
+ enabled: effectiveConfig.memoryDecay?.enabled ?? defaultConfig.memoryDecay?.enabled,
2004
+ minFloor: effectiveConfig.memoryDecay?.minFloor ?? defaultConfig.memoryDecay?.minFloor,
2005
+ defaultHalfLifeDays: effectiveConfig.memoryDecay?.defaultHalfLifeDays ?? defaultConfig.memoryDecay?.defaultHalfLifeDays,
2006
+ halfLifeByEventType: effectiveConfig.memoryDecay?.halfLifeByEventType ?? defaultConfig.memoryDecay?.halfLifeByEventType,
2007
+ antiDecay: {
2008
+ enabled: effectiveConfig.memoryDecay?.antiDecay?.enabled ?? defaultConfig.memoryDecay?.antiDecay?.enabled,
2009
+ maxBoost: effectiveConfig.memoryDecay?.antiDecay?.maxBoost ?? defaultConfig.memoryDecay?.antiDecay?.maxBoost,
2010
+ hitWeight: effectiveConfig.memoryDecay?.antiDecay?.hitWeight ?? defaultConfig.memoryDecay?.antiDecay?.hitWeight,
2011
+ recentWindowDays: effectiveConfig.memoryDecay?.antiDecay?.recentWindowDays ?? defaultConfig.memoryDecay?.antiDecay?.recentWindowDays,
2012
+ },
2013
+ },
1869
2014
  enabled: effectiveConfig.enabled ?? defaultConfig.enabled,
1870
2015
  fallbackToBuiltin: effectiveConfig.fallbackToBuiltin ?? defaultConfig.fallbackToBuiltin,
1871
2016
  apiUrl: effectiveConfig.apiUrl ?? "http://127.0.0.1:8765",
@@ -1903,6 +2048,11 @@ function register(pluginApi, userConfig) {
1903
2048
  isRegistered = true;
1904
2049
  logger.info("Cortex Memory plugin registered successfully");
1905
2050
  logger.info(`Cortex Memory engine mode: ${resolveEngine().mode}`);
2051
+ logLifecycle("register_success", {
2052
+ engineMode: config.engineMode,
2053
+ enabled: isEnabled,
2054
+ hasBuiltinFallback: Boolean(builtinMemory),
2055
+ });
1906
2056
  if (isEnabled) {
1907
2057
  registerTools();
1908
2058
  registerHooks();
@@ -1916,11 +2066,13 @@ function register(pluginApi, userConfig) {
1916
2066
  logger.info("Falling back to builtin memory");
1917
2067
  isEnabled = false;
1918
2068
  registerFallbackTools();
2069
+ logLifecycle("fallback_after_init_error", { fallbackTools: registeredFallbackTools.length, error: message });
1919
2070
  }
1920
2071
  });
1921
2072
  }
1922
2073
  else if (config?.fallbackToBuiltin && builtinMemory) {
1923
2074
  registerFallbackTools();
2075
+ logLifecycle("fallback_registered_on_start", { fallbackTools: registeredFallbackTools.length });
1924
2076
  }
1925
2077
  }
1926
2078
  async function initializeAsync() {