openclaw-cortex-memory 0.1.0-Alpha.1 → 0.1.0-Alpha.11
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/README.md +118 -28
- package/SKILL.md +112 -31
- package/dist/index.d.ts +48 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +359 -19
- package/dist/index.js.map +1 -1
- package/dist/openclaw.plugin.json +157 -5
- package/dist/src/dedup/three_stage_deduplicator.d.ts +25 -0
- package/dist/src/dedup/three_stage_deduplicator.d.ts.map +1 -0
- package/dist/src/dedup/three_stage_deduplicator.js +225 -0
- package/dist/src/dedup/three_stage_deduplicator.js.map +1 -0
- package/dist/src/engine/memory_engine.d.ts +2 -1
- package/dist/src/engine/memory_engine.d.ts.map +1 -1
- package/dist/src/engine/ts_engine.d.ts +95 -0
- package/dist/src/engine/ts_engine.d.ts.map +1 -1
- package/dist/src/engine/ts_engine.js +869 -33
- package/dist/src/engine/ts_engine.js.map +1 -1
- package/dist/src/engine/types.d.ts +11 -0
- package/dist/src/engine/types.d.ts.map +1 -1
- package/dist/src/graph/ontology.d.ts +53 -0
- package/dist/src/graph/ontology.d.ts.map +1 -0
- package/dist/src/graph/ontology.js +252 -0
- package/dist/src/graph/ontology.js.map +1 -0
- package/dist/src/reflect/reflector.d.ts +7 -0
- package/dist/src/reflect/reflector.d.ts.map +1 -1
- package/dist/src/reflect/reflector.js +75 -1
- package/dist/src/reflect/reflector.js.map +1 -1
- package/dist/src/session/session_end.d.ts +56 -0
- package/dist/src/session/session_end.d.ts.map +1 -1
- package/dist/src/session/session_end.js +270 -55
- package/dist/src/session/session_end.js.map +1 -1
- package/dist/src/store/archive_store.d.ts +115 -0
- package/dist/src/store/archive_store.d.ts.map +1 -0
- package/dist/src/store/archive_store.js +446 -0
- package/dist/src/store/archive_store.js.map +1 -0
- package/dist/src/store/embedding_utils.d.ts +32 -0
- package/dist/src/store/embedding_utils.d.ts.map +1 -0
- package/dist/src/store/embedding_utils.js +173 -0
- package/dist/src/store/embedding_utils.js.map +1 -0
- package/dist/src/store/read_store.d.ts +59 -0
- package/dist/src/store/read_store.d.ts.map +1 -1
- package/dist/src/store/read_store.js +1114 -17
- package/dist/src/store/read_store.js.map +1 -1
- package/dist/src/store/vector_store.d.ts +43 -0
- package/dist/src/store/vector_store.d.ts.map +1 -0
- package/dist/src/store/vector_store.js +186 -0
- package/dist/src/store/vector_store.js.map +1 -0
- package/dist/src/store/write_store.d.ts +45 -0
- package/dist/src/store/write_store.d.ts.map +1 -1
- package/dist/src/store/write_store.js +230 -0
- package/dist/src/store/write_store.js.map +1 -1
- package/dist/src/sync/session_sync.d.ts +52 -2
- package/dist/src/sync/session_sync.d.ts.map +1 -1
- package/dist/src/sync/session_sync.js +474 -22
- package/dist/src/sync/session_sync.js.map +1 -1
- package/dist/src/utils/runtime_env.d.ts +4 -0
- package/dist/src/utils/runtime_env.d.ts.map +1 -0
- package/dist/src/utils/runtime_env.js +51 -0
- package/dist/src/utils/runtime_env.js.map +1 -0
- package/openclaw.plugin.json +157 -5
- package/package.json +21 -6
- package/scripts/cli.js +19 -14
- package/scripts/uninstall.js +22 -5
- package/index.ts +0 -2071
- package/scripts/install.js +0 -27
package/dist/index.js
CHANGED
|
@@ -46,10 +46,14 @@ 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");
|
|
56
|
+
const runtime_env_1 = require("./src/utils/runtime_env");
|
|
53
57
|
const ERROR_CODES = {
|
|
54
58
|
CONNECTION_REFUSED: {
|
|
55
59
|
code: "E001",
|
|
@@ -88,7 +92,66 @@ const MIN_OPENCLAW_VERSION = "2026.3.8";
|
|
|
88
92
|
const MAX_OPENCLAW_VERSION = "2027.0.0";
|
|
89
93
|
const defaultConfig = {
|
|
90
94
|
autoSync: true,
|
|
95
|
+
llmRequiredForWrite: true,
|
|
91
96
|
autoReflect: false,
|
|
97
|
+
autoReflectIntervalMinutes: 30,
|
|
98
|
+
readFusion: {
|
|
99
|
+
enabled: true,
|
|
100
|
+
maxCandidates: 10,
|
|
101
|
+
authoritative: true,
|
|
102
|
+
channelWeights: {
|
|
103
|
+
rules: 1,
|
|
104
|
+
archive: 1.15,
|
|
105
|
+
vector: 1.2,
|
|
106
|
+
graph: 1,
|
|
107
|
+
},
|
|
108
|
+
channelTopK: {
|
|
109
|
+
rules: 8,
|
|
110
|
+
archive: 20,
|
|
111
|
+
vector: 20,
|
|
112
|
+
graph: 12,
|
|
113
|
+
},
|
|
114
|
+
minLexicalHits: 1,
|
|
115
|
+
minSemanticHits: 1,
|
|
116
|
+
lengthNorm: {
|
|
117
|
+
enabled: true,
|
|
118
|
+
pivotChars: 1200,
|
|
119
|
+
strength: 0.75,
|
|
120
|
+
minFactor: 0.45,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
vectorChunking: {
|
|
124
|
+
chunkSize: 600,
|
|
125
|
+
chunkOverlap: 100,
|
|
126
|
+
},
|
|
127
|
+
memoryDecay: {
|
|
128
|
+
enabled: true,
|
|
129
|
+
minFloor: 0.15,
|
|
130
|
+
defaultHalfLifeDays: 90,
|
|
131
|
+
antiDecay: {
|
|
132
|
+
enabled: true,
|
|
133
|
+
maxBoost: 1.6,
|
|
134
|
+
hitWeight: 0.08,
|
|
135
|
+
recentWindowDays: 30,
|
|
136
|
+
},
|
|
137
|
+
halfLifeByEventType: {
|
|
138
|
+
issue: 30,
|
|
139
|
+
fix: 30,
|
|
140
|
+
action_item: 30,
|
|
141
|
+
blocker: 30,
|
|
142
|
+
plan: 60,
|
|
143
|
+
milestone: 60,
|
|
144
|
+
follow_up: 60,
|
|
145
|
+
decision: 120,
|
|
146
|
+
insight: 120,
|
|
147
|
+
retrospective: 120,
|
|
148
|
+
preference: 240,
|
|
149
|
+
constraint: 240,
|
|
150
|
+
requirement: 240,
|
|
151
|
+
dependency: 240,
|
|
152
|
+
assumption: 240,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
92
155
|
enabled: true,
|
|
93
156
|
fallbackToBuiltin: true,
|
|
94
157
|
engineMode: "ts",
|
|
@@ -96,6 +159,7 @@ const defaultConfig = {
|
|
|
96
159
|
let autoSearchCacheBySession = new Map();
|
|
97
160
|
const AUTO_SEARCH_CACHE_TTL = 60000;
|
|
98
161
|
const MAX_AUTO_SEARCH_CACHE_SESSIONS = 200;
|
|
162
|
+
const HOOK_GUARD_TIMEOUT_MS = 2000;
|
|
99
163
|
let config = null;
|
|
100
164
|
let logger;
|
|
101
165
|
let pythonProcess = null;
|
|
@@ -150,6 +214,33 @@ function getSessionCachedAutoSearch(sessionId) {
|
|
|
150
214
|
ageSeconds: Math.floor((Date.now() - cache.timestamp) / 1000),
|
|
151
215
|
};
|
|
152
216
|
}
|
|
217
|
+
function isInternalSession(sessionId) {
|
|
218
|
+
if (!sessionId)
|
|
219
|
+
return false;
|
|
220
|
+
return sessionId.startsWith("slug-generator-") || sessionId.startsWith("fallback:");
|
|
221
|
+
}
|
|
222
|
+
async function runWithTimeout(task, timeoutMs, label) {
|
|
223
|
+
let timeoutHandle = null;
|
|
224
|
+
try {
|
|
225
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
226
|
+
timeoutHandle = setTimeout(() => resolve(null), timeoutMs);
|
|
227
|
+
});
|
|
228
|
+
const result = await Promise.race([task, timeoutPromise]);
|
|
229
|
+
if (result === null) {
|
|
230
|
+
logger.warn(`${label} timed out after ${timeoutMs}ms; skipped to protect gateway responsiveness`);
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
logger.warn(`${label} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
if (timeoutHandle) {
|
|
240
|
+
clearTimeout(timeoutHandle);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
153
244
|
function resolveEngine() {
|
|
154
245
|
if (!config) {
|
|
155
246
|
throw new Error("Configuration not loaded");
|
|
@@ -164,16 +255,44 @@ function resolveEngine() {
|
|
|
164
255
|
projectRoot,
|
|
165
256
|
dbPath: config.dbPath,
|
|
166
257
|
logger,
|
|
258
|
+
embedding: config.embedding,
|
|
259
|
+
reranker: config.reranker,
|
|
260
|
+
llm: config.llm,
|
|
261
|
+
fusion: config.readFusion,
|
|
262
|
+
memoryDecay: config.memoryDecay,
|
|
263
|
+
});
|
|
264
|
+
const vectorStore = (0, vector_store_1.createVectorStore)({
|
|
265
|
+
memoryRoot,
|
|
266
|
+
logger,
|
|
167
267
|
});
|
|
168
268
|
const writeStore = (0, write_store_1.createWriteStore)({
|
|
169
269
|
projectRoot,
|
|
170
270
|
dbPath: config.dbPath,
|
|
171
271
|
logger,
|
|
272
|
+
embedding: config.embedding,
|
|
273
|
+
vectorChunking: config.vectorChunking,
|
|
274
|
+
vectorStore,
|
|
275
|
+
});
|
|
276
|
+
const deduplicator = (0, three_stage_deduplicator_1.createThreeStageDeduplicator)({
|
|
277
|
+
memoryRoot,
|
|
278
|
+
logger,
|
|
279
|
+
});
|
|
280
|
+
const archiveStore = (0, archive_store_1.createArchiveStore)({
|
|
281
|
+
projectRoot,
|
|
282
|
+
memoryRoot,
|
|
283
|
+
logger,
|
|
284
|
+
embedding: config.embedding,
|
|
285
|
+
vectorChunking: config.vectorChunking,
|
|
286
|
+
deduplicator,
|
|
287
|
+
vectorStore,
|
|
172
288
|
});
|
|
173
289
|
const sessionSync = (0, session_sync_1.createSessionSync)({
|
|
174
290
|
projectRoot,
|
|
175
291
|
dbPath: config.dbPath,
|
|
176
292
|
logger,
|
|
293
|
+
llm: config.llm,
|
|
294
|
+
requireLlmForWrite: config.llmRequiredForWrite ?? true,
|
|
295
|
+
archiveStore,
|
|
177
296
|
writeStore,
|
|
178
297
|
});
|
|
179
298
|
const sessionEnd = (0, session_end_1.createSessionEnd)({
|
|
@@ -181,6 +300,10 @@ function resolveEngine() {
|
|
|
181
300
|
dbPath: config.dbPath,
|
|
182
301
|
logger,
|
|
183
302
|
syncMemory: sessionSync.syncMemory,
|
|
303
|
+
syncDailySummaries: sessionSync.syncDailySummaries,
|
|
304
|
+
archiveStore,
|
|
305
|
+
llm: config.llm,
|
|
306
|
+
requireLlmForWrite: config.llmRequiredForWrite ?? true,
|
|
184
307
|
});
|
|
185
308
|
const ruleStore = (0, rule_store_1.createRuleStore)({
|
|
186
309
|
projectRoot,
|
|
@@ -192,14 +315,22 @@ function resolveEngine() {
|
|
|
192
315
|
dbPath: config.dbPath,
|
|
193
316
|
logger,
|
|
194
317
|
ruleStore,
|
|
318
|
+
llm: config.llm,
|
|
195
319
|
});
|
|
196
320
|
memoryEngine = (0, ts_engine_1.createTsEngine)({
|
|
197
321
|
readStore,
|
|
198
322
|
writeStore,
|
|
323
|
+
vectorStore,
|
|
324
|
+
archiveStore,
|
|
199
325
|
sessionSync,
|
|
200
326
|
sessionEnd,
|
|
201
327
|
reflector,
|
|
202
328
|
memoryRoot,
|
|
329
|
+
projectRoot,
|
|
330
|
+
embedding: config.embedding,
|
|
331
|
+
llm: config.llm,
|
|
332
|
+
reranker: config.reranker,
|
|
333
|
+
vectorChunking: config.vectorChunking,
|
|
203
334
|
getCachedAutoSearch: getSessionCachedAutoSearch,
|
|
204
335
|
resolveSessionId: (context, payload) => resolveSessionId(context, payload),
|
|
205
336
|
normalizeIncomingMessage,
|
|
@@ -257,6 +388,15 @@ function sanitizeForLogging(obj) {
|
|
|
257
388
|
}
|
|
258
389
|
return sanitized;
|
|
259
390
|
}
|
|
391
|
+
function logLifecycle(event, details = {}) {
|
|
392
|
+
const payload = sanitizeForLogging({
|
|
393
|
+
event,
|
|
394
|
+
plugin: PLUGIN_ID,
|
|
395
|
+
ts: new Date().toISOString(),
|
|
396
|
+
...details,
|
|
397
|
+
});
|
|
398
|
+
logger.info(`[Lifecycle] ${JSON.stringify(payload)}`);
|
|
399
|
+
}
|
|
260
400
|
function asRecord(value) {
|
|
261
401
|
if (typeof value === "object" && value !== null) {
|
|
262
402
|
return value;
|
|
@@ -381,7 +521,7 @@ function compareVersions(a, b) {
|
|
|
381
521
|
}
|
|
382
522
|
async function checkOpenClawVersion() {
|
|
383
523
|
try {
|
|
384
|
-
const version =
|
|
524
|
+
const version = (0, runtime_env_1.getEnvValue)("OPENCLAW_VERSION");
|
|
385
525
|
if (version) {
|
|
386
526
|
if (compareVersions(version, MIN_OPENCLAW_VERSION) < 0) {
|
|
387
527
|
throw new Error(`Incompatible OpenClaw version: ${version}. Minimum required: ${MIN_OPENCLAW_VERSION}`);
|
|
@@ -415,13 +555,19 @@ function findProjectRoot() {
|
|
|
415
555
|
throw new Error("Cannot find project root directory");
|
|
416
556
|
}
|
|
417
557
|
function findOpenClawConfig() {
|
|
558
|
+
const explicitConfigPath = (0, runtime_env_1.getEnvValue)("OPENCLAW_CONFIG_PATH");
|
|
559
|
+
const stateDir = (0, runtime_env_1.getEnvValue)("OPENCLAW_STATE_DIR");
|
|
560
|
+
const basePath = (0, runtime_env_1.getEnvValue)("OPENCLAW_BASE_PATH");
|
|
561
|
+
const homePath = (0, runtime_env_1.getHomeDir)();
|
|
418
562
|
const possiblePaths = [
|
|
563
|
+
explicitConfigPath,
|
|
564
|
+
stateDir ? path.join(stateDir, "openclaw.json") : "",
|
|
565
|
+
basePath ? path.join(basePath, "openclaw.json") : "",
|
|
419
566
|
path.join(process.cwd(), "openclaw.json"),
|
|
420
|
-
path.join(
|
|
421
|
-
path.join(process.env.OPENCLAW_BASE_PATH || "", "openclaw.json"),
|
|
567
|
+
homePath ? path.join(homePath, ".openclaw", "openclaw.json") : "",
|
|
422
568
|
];
|
|
423
569
|
for (const p of possiblePaths) {
|
|
424
|
-
if (fs.existsSync(p)) {
|
|
570
|
+
if (p && fs.existsSync(p)) {
|
|
425
571
|
return p;
|
|
426
572
|
}
|
|
427
573
|
}
|
|
@@ -476,6 +622,8 @@ function startAutoReflectScheduler() {
|
|
|
476
622
|
if (!config?.autoReflect || autoReflectInterval) {
|
|
477
623
|
return;
|
|
478
624
|
}
|
|
625
|
+
const intervalMinutes = Math.max(5, Math.floor(config.autoReflectIntervalMinutes ?? 30));
|
|
626
|
+
const intervalMs = intervalMinutes * 60 * 1000;
|
|
479
627
|
autoReflectInterval = setInterval(() => {
|
|
480
628
|
if (!isEnabled) {
|
|
481
629
|
return;
|
|
@@ -492,7 +640,7 @@ function startAutoReflectScheduler() {
|
|
|
492
640
|
if (marker === lastAutoReflectArchiveMarker) {
|
|
493
641
|
return;
|
|
494
642
|
}
|
|
495
|
-
if (now - lastAutoReflectRunAt <
|
|
643
|
+
if (now - lastAutoReflectRunAt < intervalMs) {
|
|
496
644
|
return;
|
|
497
645
|
}
|
|
498
646
|
resolveEngine().reflectMemory({}, schedulerContext)
|
|
@@ -507,7 +655,7 @@ function startAutoReflectScheduler() {
|
|
|
507
655
|
}
|
|
508
656
|
})
|
|
509
657
|
.catch(error => logger.warn(`Auto-reflect failed: ${String(error)}`));
|
|
510
|
-
},
|
|
658
|
+
}, intervalMs);
|
|
511
659
|
}
|
|
512
660
|
function stopAutoReflectScheduler() {
|
|
513
661
|
if (autoReflectInterval) {
|
|
@@ -523,6 +671,12 @@ function validateConfig(cfg) {
|
|
|
523
671
|
if (!cfg.embedding?.apiKey || !cfg.embedding?.baseURL) {
|
|
524
672
|
errors.push("embedding.apiKey and embedding.baseURL are required. Please configure third-party embedding endpoint credentials.");
|
|
525
673
|
}
|
|
674
|
+
if (typeof cfg.embedding?.timeoutMs === "number" && (!Number.isFinite(cfg.embedding.timeoutMs) || cfg.embedding.timeoutMs < 1000)) {
|
|
675
|
+
errors.push("embedding.timeoutMs must be a number >= 1000.");
|
|
676
|
+
}
|
|
677
|
+
if (typeof cfg.embedding?.maxRetries === "number" && (!Number.isFinite(cfg.embedding.maxRetries) || cfg.embedding.maxRetries < 1 || cfg.embedding.maxRetries > 8)) {
|
|
678
|
+
errors.push("embedding.maxRetries must be between 1 and 8.");
|
|
679
|
+
}
|
|
526
680
|
if (!cfg.llm?.provider || !cfg.llm?.model) {
|
|
527
681
|
errors.push("llm.provider and llm.model are required. Please configure them in openclaw.json");
|
|
528
682
|
}
|
|
@@ -535,6 +689,88 @@ function validateConfig(cfg) {
|
|
|
535
689
|
if (!cfg.reranker?.apiKey || !cfg.reranker?.baseURL) {
|
|
536
690
|
errors.push("reranker.apiKey and reranker.baseURL are required. Please configure third-party reranker endpoint credentials.");
|
|
537
691
|
}
|
|
692
|
+
if (typeof cfg.autoReflectIntervalMinutes === "number" && (!Number.isFinite(cfg.autoReflectIntervalMinutes) || cfg.autoReflectIntervalMinutes < 5)) {
|
|
693
|
+
errors.push("autoReflectIntervalMinutes must be a number >= 5.");
|
|
694
|
+
}
|
|
695
|
+
if (cfg.readFusion && typeof cfg.readFusion.maxCandidates === "number" && (!Number.isFinite(cfg.readFusion.maxCandidates) || cfg.readFusion.maxCandidates < 2)) {
|
|
696
|
+
errors.push("readFusion.maxCandidates must be a number >= 2.");
|
|
697
|
+
}
|
|
698
|
+
if (cfg.readFusion?.channelWeights) {
|
|
699
|
+
for (const [key, value] of Object.entries(cfg.readFusion.channelWeights)) {
|
|
700
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
701
|
+
errors.push(`readFusion.channelWeights.${key} must be a number > 0.`);
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (cfg.readFusion?.channelTopK) {
|
|
707
|
+
for (const [key, value] of Object.entries(cfg.readFusion.channelTopK)) {
|
|
708
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
709
|
+
errors.push(`readFusion.channelTopK.${key} must be a number >= 1.`);
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (typeof cfg.readFusion?.minLexicalHits === "number" && (!Number.isFinite(cfg.readFusion.minLexicalHits) || cfg.readFusion.minLexicalHits < 0)) {
|
|
715
|
+
errors.push("readFusion.minLexicalHits must be a number >= 0.");
|
|
716
|
+
}
|
|
717
|
+
if (typeof cfg.readFusion?.minSemanticHits === "number" && (!Number.isFinite(cfg.readFusion.minSemanticHits) || cfg.readFusion.minSemanticHits < 0)) {
|
|
718
|
+
errors.push("readFusion.minSemanticHits must be a number >= 0.");
|
|
719
|
+
}
|
|
720
|
+
if (cfg.readFusion?.lengthNorm) {
|
|
721
|
+
const ln = cfg.readFusion.lengthNorm;
|
|
722
|
+
if (typeof ln.pivotChars === "number" && (!Number.isFinite(ln.pivotChars) || ln.pivotChars <= 0)) {
|
|
723
|
+
errors.push("readFusion.lengthNorm.pivotChars must be > 0.");
|
|
724
|
+
}
|
|
725
|
+
if (typeof ln.strength === "number" && (!Number.isFinite(ln.strength) || ln.strength <= 0)) {
|
|
726
|
+
errors.push("readFusion.lengthNorm.strength must be > 0.");
|
|
727
|
+
}
|
|
728
|
+
if (typeof ln.minFactor === "number" && (!Number.isFinite(ln.minFactor) || ln.minFactor <= 0 || ln.minFactor > 1)) {
|
|
729
|
+
errors.push("readFusion.lengthNorm.minFactor must be within (0,1].");
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
if (cfg.vectorChunking) {
|
|
733
|
+
if (typeof cfg.vectorChunking.chunkSize === "number" && (!Number.isFinite(cfg.vectorChunking.chunkSize) || cfg.vectorChunking.chunkSize < 200)) {
|
|
734
|
+
errors.push("vectorChunking.chunkSize must be >= 200.");
|
|
735
|
+
}
|
|
736
|
+
if (typeof cfg.vectorChunking.chunkOverlap === "number" && (!Number.isFinite(cfg.vectorChunking.chunkOverlap) || cfg.vectorChunking.chunkOverlap < 0)) {
|
|
737
|
+
errors.push("vectorChunking.chunkOverlap must be >= 0.");
|
|
738
|
+
}
|
|
739
|
+
if (typeof cfg.vectorChunking.chunkSize === "number" &&
|
|
740
|
+
typeof cfg.vectorChunking.chunkOverlap === "number" &&
|
|
741
|
+
cfg.vectorChunking.chunkOverlap >= cfg.vectorChunking.chunkSize) {
|
|
742
|
+
errors.push("vectorChunking.chunkOverlap must be smaller than chunkSize.");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (cfg.memoryDecay) {
|
|
746
|
+
if (typeof cfg.memoryDecay.minFloor === "number" && (!Number.isFinite(cfg.memoryDecay.minFloor) || cfg.memoryDecay.minFloor < 0 || cfg.memoryDecay.minFloor > 1)) {
|
|
747
|
+
errors.push("memoryDecay.minFloor must be within [0,1].");
|
|
748
|
+
}
|
|
749
|
+
if (typeof cfg.memoryDecay.defaultHalfLifeDays === "number" && (!Number.isFinite(cfg.memoryDecay.defaultHalfLifeDays) || cfg.memoryDecay.defaultHalfLifeDays <= 0)) {
|
|
750
|
+
errors.push("memoryDecay.defaultHalfLifeDays must be > 0.");
|
|
751
|
+
}
|
|
752
|
+
const mapping = cfg.memoryDecay.halfLifeByEventType;
|
|
753
|
+
if (mapping && typeof mapping === "object") {
|
|
754
|
+
for (const [key, value] of Object.entries(mapping)) {
|
|
755
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
756
|
+
errors.push(`memoryDecay.halfLifeByEventType.${key} must be > 0.`);
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
const anti = cfg.memoryDecay.antiDecay;
|
|
762
|
+
if (anti) {
|
|
763
|
+
if (typeof anti.maxBoost === "number" && (!Number.isFinite(anti.maxBoost) || anti.maxBoost < 1)) {
|
|
764
|
+
errors.push("memoryDecay.antiDecay.maxBoost must be >= 1.");
|
|
765
|
+
}
|
|
766
|
+
if (typeof anti.hitWeight === "number" && (!Number.isFinite(anti.hitWeight) || anti.hitWeight < 0)) {
|
|
767
|
+
errors.push("memoryDecay.antiDecay.hitWeight must be >= 0.");
|
|
768
|
+
}
|
|
769
|
+
if (typeof anti.recentWindowDays === "number" && (!Number.isFinite(anti.recentWindowDays) || anti.recentWindowDays <= 0)) {
|
|
770
|
+
errors.push("memoryDecay.antiDecay.recentWindowDays must be > 0.");
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
538
774
|
return errors;
|
|
539
775
|
}
|
|
540
776
|
function getApiHostAndPort() {
|
|
@@ -720,14 +956,14 @@ async function startPythonServiceInternal() {
|
|
|
720
956
|
}
|
|
721
957
|
logger.info("Starting Cortex Memory Python service...");
|
|
722
958
|
const env = {
|
|
723
|
-
...
|
|
959
|
+
...(0, runtime_env_1.getProcessEnvCopy)(),
|
|
724
960
|
CORTEX_MEMORY_EMBEDDING_PROVIDER: config.embedding.provider,
|
|
725
961
|
CORTEX_MEMORY_EMBEDDING_MODEL: config.embedding.model,
|
|
726
962
|
CORTEX_MEMORY_LLM_PROVIDER: config.llm.provider,
|
|
727
963
|
CORTEX_MEMORY_LLM_MODEL: config.llm.model,
|
|
728
964
|
CORTEX_MEMORY_RERANKER_PROVIDER: config.reranker.provider || "",
|
|
729
965
|
CORTEX_MEMORY_RERANKER_MODEL: config.reranker.model,
|
|
730
|
-
CORTEX_MEMORY_DB_PATH: config.dbPath || path.join(
|
|
966
|
+
CORTEX_MEMORY_DB_PATH: config.dbPath || path.join((0, runtime_env_1.getHomeDir)(), ".openclaw", "agents", "main", "lancedb_store"),
|
|
731
967
|
};
|
|
732
968
|
if (config.embedding.apiKey) {
|
|
733
969
|
env.CORTEX_MEMORY_EMBEDDING_API_KEY = config.embedding.apiKey;
|
|
@@ -870,7 +1106,7 @@ function stopPythonService() {
|
|
|
870
1106
|
stopPythonServiceAsync();
|
|
871
1107
|
}
|
|
872
1108
|
function getBaseUrl() {
|
|
873
|
-
return config?.apiUrl ?? "http://
|
|
1109
|
+
return config?.apiUrl ?? "http://localhost:8765";
|
|
874
1110
|
}
|
|
875
1111
|
async function waitForService(maxAttempts = 30) {
|
|
876
1112
|
const apiUrl = getBaseUrl();
|
|
@@ -1365,10 +1601,18 @@ async function onTimerPythonHandler(payload, _context) {
|
|
|
1365
1601
|
}
|
|
1366
1602
|
}
|
|
1367
1603
|
async function onMessageHandler(payload, context) {
|
|
1368
|
-
|
|
1604
|
+
const sessionId = resolveSessionId(context, payload);
|
|
1605
|
+
if (isInternalSession(sessionId)) {
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
await runWithTimeout(resolveEngine().onMessage(payload, context), HOOK_GUARD_TIMEOUT_MS, "onMessage hook");
|
|
1369
1609
|
}
|
|
1370
1610
|
async function onSessionEndHandler(payload, context) {
|
|
1371
|
-
|
|
1611
|
+
const sessionId = resolveSessionId(context, payload);
|
|
1612
|
+
if (isInternalSession(sessionId)) {
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
await runWithTimeout(resolveEngine().onSessionEnd(payload, context), HOOK_GUARD_TIMEOUT_MS, "onSessionEnd hook");
|
|
1372
1616
|
}
|
|
1373
1617
|
async function onTimerHandler(payload, context) {
|
|
1374
1618
|
await resolveEngine().onTimer(payload, context);
|
|
@@ -1497,6 +1741,26 @@ function registerTools() {
|
|
|
1497
1741
|
return resolveEngine().syncMemory(args, params.context);
|
|
1498
1742
|
},
|
|
1499
1743
|
},
|
|
1744
|
+
{
|
|
1745
|
+
name: "backfill_embeddings",
|
|
1746
|
+
description: "Backfill missing embeddings for active/archive records",
|
|
1747
|
+
parameters: {
|
|
1748
|
+
type: "object",
|
|
1749
|
+
properties: {
|
|
1750
|
+
layer: { type: "string", enum: ["active", "archive", "all"], description: "Target layer to backfill" },
|
|
1751
|
+
batch_size: { type: "integer", description: "Batch size per processing window" },
|
|
1752
|
+
max_retries: { type: "integer", description: "Max retry count for failed records" },
|
|
1753
|
+
retry_failed_only: { type: "boolean", description: "Only retry failed records" },
|
|
1754
|
+
rebuild_mode: { type: "string", enum: ["incremental", "vector_only", "full"], description: "Rebuild mode" },
|
|
1755
|
+
},
|
|
1756
|
+
required: [],
|
|
1757
|
+
additionalProperties: false,
|
|
1758
|
+
},
|
|
1759
|
+
execute: async (params) => {
|
|
1760
|
+
const args = params.args || params;
|
|
1761
|
+
return resolveEngine().backfillEmbeddings(args, params.context);
|
|
1762
|
+
},
|
|
1763
|
+
},
|
|
1500
1764
|
{
|
|
1501
1765
|
name: "delete_memory",
|
|
1502
1766
|
description: "Delete a memory by ID",
|
|
@@ -1529,10 +1793,39 @@ function registerTools() {
|
|
|
1529
1793
|
},
|
|
1530
1794
|
];
|
|
1531
1795
|
for (const tool of tools) {
|
|
1532
|
-
|
|
1796
|
+
registerToolCompat(tool);
|
|
1533
1797
|
registeredTools.push(tool.name);
|
|
1534
1798
|
}
|
|
1535
1799
|
}
|
|
1800
|
+
function registerToolCompat(tool) {
|
|
1801
|
+
if (!api)
|
|
1802
|
+
return;
|
|
1803
|
+
const execute = async (params) => tool.execute({
|
|
1804
|
+
args: params?.args || {},
|
|
1805
|
+
context: params.context,
|
|
1806
|
+
});
|
|
1807
|
+
const handler = async (...params) => {
|
|
1808
|
+
const first = params[0];
|
|
1809
|
+
const second = params[1];
|
|
1810
|
+
if (first && typeof first === "object" && "context" in first) {
|
|
1811
|
+
return execute({
|
|
1812
|
+
args: first.args || {},
|
|
1813
|
+
context: first.context,
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
return execute({
|
|
1817
|
+
args: first || {},
|
|
1818
|
+
context: (second || {}),
|
|
1819
|
+
});
|
|
1820
|
+
};
|
|
1821
|
+
api.registerTool({
|
|
1822
|
+
name: tool.name,
|
|
1823
|
+
description: tool.description,
|
|
1824
|
+
parameters: tool.parameters,
|
|
1825
|
+
execute,
|
|
1826
|
+
handler,
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1536
1829
|
function unregisterTools() {
|
|
1537
1830
|
if (!api || !api.unregisterTool)
|
|
1538
1831
|
return;
|
|
@@ -1637,6 +1930,7 @@ async function enable() {
|
|
|
1637
1930
|
return;
|
|
1638
1931
|
}
|
|
1639
1932
|
logger.info("Enabling Cortex Memory plugin...");
|
|
1933
|
+
logLifecycle("enable_start");
|
|
1640
1934
|
try {
|
|
1641
1935
|
unregisterFallbackTools();
|
|
1642
1936
|
if (shouldUsePythonRuntime()) {
|
|
@@ -1648,10 +1942,12 @@ async function enable() {
|
|
|
1648
1942
|
registerHooks();
|
|
1649
1943
|
startAutoReflectScheduler();
|
|
1650
1944
|
logger.info("Cortex Memory plugin enabled successfully");
|
|
1945
|
+
logLifecycle("enable_success", { registeredTools: registeredTools.length, registeredHooks: registeredHooks.length });
|
|
1651
1946
|
}
|
|
1652
1947
|
catch (error) {
|
|
1653
1948
|
const message = error instanceof Error ? error.message : String(error);
|
|
1654
1949
|
logger.error(`Failed to enable Cortex Memory plugin: ${message}`);
|
|
1950
|
+
logLifecycle("enable_failed", { error: message });
|
|
1655
1951
|
throw error;
|
|
1656
1952
|
}
|
|
1657
1953
|
}
|
|
@@ -1661,6 +1957,7 @@ async function disable() {
|
|
|
1661
1957
|
return;
|
|
1662
1958
|
}
|
|
1663
1959
|
logger.info("Disabling Cortex Memory plugin...");
|
|
1960
|
+
logLifecycle("disable_start");
|
|
1664
1961
|
unregisterHooks();
|
|
1665
1962
|
unregisterTools();
|
|
1666
1963
|
unregisterFallbackTools();
|
|
@@ -1673,13 +1970,15 @@ async function disable() {
|
|
|
1673
1970
|
if (config?.fallbackToBuiltin && builtinMemory) {
|
|
1674
1971
|
logger.info("Falling back to OpenClaw builtin memory system");
|
|
1675
1972
|
registerFallbackTools();
|
|
1973
|
+
logLifecycle("fallback_enabled", { fallbackTools: registeredFallbackTools.length });
|
|
1676
1974
|
}
|
|
1677
1975
|
logger.info("Cortex Memory plugin disabled successfully");
|
|
1976
|
+
logLifecycle("disable_success", { fallbackEnabled: registeredFallbackTools.length > 0 });
|
|
1678
1977
|
}
|
|
1679
1978
|
function registerFallbackTools() {
|
|
1680
1979
|
if (!api || !builtinMemory)
|
|
1681
1980
|
return;
|
|
1682
|
-
|
|
1981
|
+
registerToolCompat({
|
|
1683
1982
|
name: "search_memory",
|
|
1684
1983
|
description: "Search memory (using builtin system - Cortex Memory disabled)",
|
|
1685
1984
|
parameters: {
|
|
@@ -1691,10 +1990,10 @@ function registerFallbackTools() {
|
|
|
1691
1990
|
required: ["query"],
|
|
1692
1991
|
additionalProperties: false,
|
|
1693
1992
|
},
|
|
1694
|
-
execute: async ({ args, context }) => searchMemoryWithFallback(args, context),
|
|
1993
|
+
execute: async ({ args, context }) => searchMemoryWithFallback((args || {}), context),
|
|
1695
1994
|
});
|
|
1696
1995
|
registeredFallbackTools.push("search_memory");
|
|
1697
|
-
|
|
1996
|
+
registerToolCompat({
|
|
1698
1997
|
name: "store_event",
|
|
1699
1998
|
description: "Store event (using builtin system - Cortex Memory disabled)",
|
|
1700
1999
|
parameters: {
|
|
@@ -1705,10 +2004,10 @@ function registerFallbackTools() {
|
|
|
1705
2004
|
required: ["summary"],
|
|
1706
2005
|
additionalProperties: false,
|
|
1707
2006
|
},
|
|
1708
|
-
execute: async ({ args, context }) => storeEventWithFallback(args, context),
|
|
2007
|
+
execute: async ({ args, context }) => storeEventWithFallback((args || {}), context),
|
|
1709
2008
|
});
|
|
1710
2009
|
registeredFallbackTools.push("store_event");
|
|
1711
|
-
|
|
2010
|
+
registerToolCompat({
|
|
1712
2011
|
name: "cortex_memory_status",
|
|
1713
2012
|
description: "Get the current status of the Cortex Memory plugin",
|
|
1714
2013
|
parameters: {
|
|
@@ -1717,7 +2016,7 @@ function registerFallbackTools() {
|
|
|
1717
2016
|
required: [],
|
|
1718
2017
|
additionalProperties: false,
|
|
1719
2018
|
},
|
|
1720
|
-
execute: async ({ args, context }) => getPluginStatus(args, context),
|
|
2019
|
+
execute: async ({ args, context }) => getPluginStatus(args || {}, context),
|
|
1721
2020
|
});
|
|
1722
2021
|
registeredFallbackTools.push("cortex_memory_status");
|
|
1723
2022
|
}
|
|
@@ -1742,6 +2041,7 @@ function getStatus() {
|
|
|
1742
2041
|
}
|
|
1743
2042
|
async function unregister() {
|
|
1744
2043
|
logger.info("Unregistering Cortex Memory plugin...");
|
|
2044
|
+
logLifecycle("unregister_start");
|
|
1745
2045
|
stopConfigWatcher();
|
|
1746
2046
|
stopAutoReflectScheduler();
|
|
1747
2047
|
unregisterHooks();
|
|
@@ -1768,6 +2068,7 @@ async function unregister() {
|
|
|
1768
2068
|
stopAutoReflectScheduler();
|
|
1769
2069
|
configPath = null;
|
|
1770
2070
|
logger.info("Cortex Memory plugin unregistered successfully");
|
|
2071
|
+
logLifecycle("unregister_success");
|
|
1771
2072
|
}
|
|
1772
2073
|
function register(pluginApi, userConfig) {
|
|
1773
2074
|
if (isInitializing || isRegistered) {
|
|
@@ -1803,9 +2104,41 @@ function register(pluginApi, userConfig) {
|
|
|
1803
2104
|
dbPath: effectiveConfig.dbPath,
|
|
1804
2105
|
autoSync: effectiveConfig.autoSync ?? defaultConfig.autoSync,
|
|
1805
2106
|
autoReflect: effectiveConfig.autoReflect ?? defaultConfig.autoReflect,
|
|
2107
|
+
autoReflectIntervalMinutes: effectiveConfig.autoReflectIntervalMinutes ?? defaultConfig.autoReflectIntervalMinutes,
|
|
2108
|
+
readFusion: {
|
|
2109
|
+
enabled: effectiveConfig.readFusion?.enabled ?? defaultConfig.readFusion?.enabled,
|
|
2110
|
+
maxCandidates: effectiveConfig.readFusion?.maxCandidates ?? defaultConfig.readFusion?.maxCandidates,
|
|
2111
|
+
authoritative: effectiveConfig.readFusion?.authoritative ?? defaultConfig.readFusion?.authoritative,
|
|
2112
|
+
channelWeights: effectiveConfig.readFusion?.channelWeights ?? defaultConfig.readFusion?.channelWeights,
|
|
2113
|
+
channelTopK: effectiveConfig.readFusion?.channelTopK ?? defaultConfig.readFusion?.channelTopK,
|
|
2114
|
+
minLexicalHits: effectiveConfig.readFusion?.minLexicalHits ?? defaultConfig.readFusion?.minLexicalHits,
|
|
2115
|
+
minSemanticHits: effectiveConfig.readFusion?.minSemanticHits ?? defaultConfig.readFusion?.minSemanticHits,
|
|
2116
|
+
lengthNorm: {
|
|
2117
|
+
enabled: effectiveConfig.readFusion?.lengthNorm?.enabled ?? defaultConfig.readFusion?.lengthNorm?.enabled,
|
|
2118
|
+
pivotChars: effectiveConfig.readFusion?.lengthNorm?.pivotChars ?? defaultConfig.readFusion?.lengthNorm?.pivotChars,
|
|
2119
|
+
strength: effectiveConfig.readFusion?.lengthNorm?.strength ?? defaultConfig.readFusion?.lengthNorm?.strength,
|
|
2120
|
+
minFactor: effectiveConfig.readFusion?.lengthNorm?.minFactor ?? defaultConfig.readFusion?.lengthNorm?.minFactor,
|
|
2121
|
+
},
|
|
2122
|
+
},
|
|
2123
|
+
vectorChunking: {
|
|
2124
|
+
chunkSize: effectiveConfig.vectorChunking?.chunkSize ?? defaultConfig.vectorChunking?.chunkSize,
|
|
2125
|
+
chunkOverlap: effectiveConfig.vectorChunking?.chunkOverlap ?? defaultConfig.vectorChunking?.chunkOverlap,
|
|
2126
|
+
},
|
|
2127
|
+
memoryDecay: {
|
|
2128
|
+
enabled: effectiveConfig.memoryDecay?.enabled ?? defaultConfig.memoryDecay?.enabled,
|
|
2129
|
+
minFloor: effectiveConfig.memoryDecay?.minFloor ?? defaultConfig.memoryDecay?.minFloor,
|
|
2130
|
+
defaultHalfLifeDays: effectiveConfig.memoryDecay?.defaultHalfLifeDays ?? defaultConfig.memoryDecay?.defaultHalfLifeDays,
|
|
2131
|
+
halfLifeByEventType: effectiveConfig.memoryDecay?.halfLifeByEventType ?? defaultConfig.memoryDecay?.halfLifeByEventType,
|
|
2132
|
+
antiDecay: {
|
|
2133
|
+
enabled: effectiveConfig.memoryDecay?.antiDecay?.enabled ?? defaultConfig.memoryDecay?.antiDecay?.enabled,
|
|
2134
|
+
maxBoost: effectiveConfig.memoryDecay?.antiDecay?.maxBoost ?? defaultConfig.memoryDecay?.antiDecay?.maxBoost,
|
|
2135
|
+
hitWeight: effectiveConfig.memoryDecay?.antiDecay?.hitWeight ?? defaultConfig.memoryDecay?.antiDecay?.hitWeight,
|
|
2136
|
+
recentWindowDays: effectiveConfig.memoryDecay?.antiDecay?.recentWindowDays ?? defaultConfig.memoryDecay?.antiDecay?.recentWindowDays,
|
|
2137
|
+
},
|
|
2138
|
+
},
|
|
1806
2139
|
enabled: effectiveConfig.enabled ?? defaultConfig.enabled,
|
|
1807
2140
|
fallbackToBuiltin: effectiveConfig.fallbackToBuiltin ?? defaultConfig.fallbackToBuiltin,
|
|
1808
|
-
apiUrl: effectiveConfig.apiUrl ?? "http://
|
|
2141
|
+
apiUrl: effectiveConfig.apiUrl ?? "http://localhost:8765",
|
|
1809
2142
|
engineMode: "ts",
|
|
1810
2143
|
};
|
|
1811
2144
|
memoryEngine = null;
|
|
@@ -1840,6 +2173,11 @@ function register(pluginApi, userConfig) {
|
|
|
1840
2173
|
isRegistered = true;
|
|
1841
2174
|
logger.info("Cortex Memory plugin registered successfully");
|
|
1842
2175
|
logger.info(`Cortex Memory engine mode: ${resolveEngine().mode}`);
|
|
2176
|
+
logLifecycle("register_success", {
|
|
2177
|
+
engineMode: config.engineMode,
|
|
2178
|
+
enabled: isEnabled,
|
|
2179
|
+
hasBuiltinFallback: Boolean(builtinMemory),
|
|
2180
|
+
});
|
|
1843
2181
|
if (isEnabled) {
|
|
1844
2182
|
registerTools();
|
|
1845
2183
|
registerHooks();
|
|
@@ -1853,11 +2191,13 @@ function register(pluginApi, userConfig) {
|
|
|
1853
2191
|
logger.info("Falling back to builtin memory");
|
|
1854
2192
|
isEnabled = false;
|
|
1855
2193
|
registerFallbackTools();
|
|
2194
|
+
logLifecycle("fallback_after_init_error", { fallbackTools: registeredFallbackTools.length, error: message });
|
|
1856
2195
|
}
|
|
1857
2196
|
});
|
|
1858
2197
|
}
|
|
1859
2198
|
else if (config?.fallbackToBuiltin && builtinMemory) {
|
|
1860
2199
|
registerFallbackTools();
|
|
2200
|
+
logLifecycle("fallback_registered_on_start", { fallbackTools: registeredFallbackTools.length });
|
|
1861
2201
|
}
|
|
1862
2202
|
}
|
|
1863
2203
|
async function initializeAsync() {
|