memorylake-openclaw 1.1.6 → 1.1.7

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.js CHANGED
@@ -238,6 +238,98 @@ function registerMemoryPromptSection(pctx, cfg) {
238
238
  // lib/tools/memory-tools.ts
239
239
  import { Type } from "@sinclair/typebox";
240
240
 
241
+ // lib/telemetry.ts
242
+ import { createHash } from "crypto";
243
+ var PLUGIN_VERSION = true ? "1.1.7" : "dev";
244
+ var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
245
+ var POSTHOG_API_KEY = process.env.MEMORYLAKE_POSTHOG_API_KEY?.trim() ?? "";
246
+ var POSTHOG_HOST = normalizePosthogHost(
247
+ process.env.MEMORYLAKE_POSTHOG_HOST?.trim() || DEFAULT_POSTHOG_HOST
248
+ );
249
+ var FLUSH_INTERVAL_MS = 5e3;
250
+ var FLUSH_THRESHOLD = 10;
251
+ var eventQueue = [];
252
+ var flushTimer;
253
+ var telemetryEnabled;
254
+ var exitHandlerInstalled = false;
255
+ function normalizePosthogHost(value) {
256
+ const trimmed = value.replace(/\/+$/, "");
257
+ return trimmed.endsWith("/i/v0/e") ? `${trimmed}/` : `${trimmed}/i/v0/e/`;
258
+ }
259
+ function isTelemetryEnabled() {
260
+ if (telemetryEnabled !== void 0) return telemetryEnabled;
261
+ telemetryEnabled = !!POSTHOG_API_KEY;
262
+ return telemetryEnabled;
263
+ }
264
+ function getDistinctId(apiKey = "") {
265
+ return createHash("sha256").update(apiKey).digest("hex");
266
+ }
267
+ function ensureFlushTimer() {
268
+ if (flushTimer) return;
269
+ flushTimer = setInterval(flushEvents, FLUSH_INTERVAL_MS);
270
+ if (typeof flushTimer === "object" && "unref" in flushTimer) {
271
+ flushTimer.unref();
272
+ }
273
+ }
274
+ function ensureExitHandler() {
275
+ if (exitHandlerInstalled) return;
276
+ exitHandlerInstalled = true;
277
+ process.on("beforeExit", async () => {
278
+ if (eventQueue.length === 0) return;
279
+ const batch = eventQueue;
280
+ eventQueue = [];
281
+ const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
282
+ try {
283
+ await fetch(POSTHOG_HOST, {
284
+ method: "POST",
285
+ headers: { "Content-Type": "application/json" },
286
+ body,
287
+ signal: AbortSignal.timeout(3e3)
288
+ });
289
+ } catch {
290
+ }
291
+ });
292
+ }
293
+ function flushEvents() {
294
+ if (eventQueue.length === 0) return;
295
+ const batch = eventQueue;
296
+ eventQueue = [];
297
+ const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
298
+ fetch(POSTHOG_HOST, {
299
+ method: "POST",
300
+ headers: { "Content-Type": "application/json" },
301
+ body,
302
+ signal: AbortSignal.timeout(3e3)
303
+ }).catch(() => {
304
+ });
305
+ }
306
+ function captureEvent(eventName, properties = {}, ctx) {
307
+ if (!isTelemetryEnabled()) return;
308
+ try {
309
+ const distinctId = getDistinctId(ctx.apiKey ?? "");
310
+ eventQueue.push({
311
+ event: eventName,
312
+ distinct_id: distinctId,
313
+ properties: {
314
+ source: "OPENCLAW",
315
+ language: "node",
316
+ plugin_version: PLUGIN_VERSION,
317
+ node_version: process.version,
318
+ os: process.platform,
319
+ $process_person_profile: false,
320
+ $lib: "posthog-node",
321
+ ...properties
322
+ }
323
+ });
324
+ ensureFlushTimer();
325
+ ensureExitHandler();
326
+ if (eventQueue.length >= FLUSH_THRESHOLD) {
327
+ flushEvents();
328
+ }
329
+ } catch {
330
+ }
331
+ }
332
+
241
333
  // lib/provider.ts
242
334
  import got from "got";
243
335
 
@@ -473,7 +565,7 @@ function getProvider(effectiveCfg) {
473
565
  }
474
566
 
475
567
  // lib/utils/builders.ts
476
- var PLUGIN_VERSION = true ? "1.1.6" : "dev";
568
+ var PLUGIN_VERSION2 = true ? "1.1.7" : "dev";
477
569
  function buildDocumentContext(results, maxChunkLength = 1e4) {
478
570
  const parts = [];
479
571
  for (const result of results) {
@@ -552,7 +644,7 @@ function buildAddOptions(effectiveCfg, userIdOverride, sessionId) {
552
644
  const opts = {
553
645
  user_id: userIdOverride || effectiveCfg.userId,
554
646
  infer: true,
555
- metadata: { source: "OPENCLAW", plugin_version: PLUGIN_VERSION }
647
+ metadata: { source: "OPENCLAW", plugin_version: PLUGIN_VERSION2 }
556
648
  };
557
649
  if (sessionId) opts.chat_session_id = sessionId;
558
650
  return opts;
@@ -588,6 +680,7 @@ function registerMemoryTools(pctx, cfg) {
588
680
  )
589
681
  }),
590
682
  async execute(_toolCallId, params) {
683
+ const start = Date.now();
591
684
  const effectiveCfg = resolveConfig(ctx);
592
685
  const effectiveProvider = getProvider(effectiveCfg);
593
686
  const { query, limit, userId } = params;
@@ -601,6 +694,8 @@ function registerMemoryTools(pctx, cfg) {
601
694
  const sections = [];
602
695
  let memoryCount = 0;
603
696
  let docCount = 0;
697
+ let conflictCount = 0;
698
+ let conflictFetchFailed = false;
604
699
  let sanitizedMemories = [];
605
700
  if (memoryResult.status === "fulfilled" && memoryResult.value.length > 0) {
606
701
  const results = memoryResult.value;
@@ -621,6 +716,7 @@ ${text}`);
621
716
  const effectiveUserId = userId ?? effectiveCfg.userId;
622
717
  const conflicts = await effectiveProvider.listConflicts(conflictMemoryIds, effectiveUserId);
623
718
  if (conflicts.length > 0) {
719
+ conflictCount = conflicts.length;
624
720
  const conflictText = buildConflictContext(conflicts);
625
721
  sections.push(`## Memory Conflicts
626
722
  The following memories have unresolved conflicts. Review and help the user resolve them if relevant:
@@ -628,6 +724,7 @@ The following memories have unresolved conflicts. Review and help the user resol
628
724
  ${conflictText}`);
629
725
  }
630
726
  } catch (err) {
727
+ conflictFetchFailed = true;
631
728
  sections.push(`## Memory Conflicts
632
729
  Failed to fetch conflicts: ${String(err)}`);
633
730
  }
@@ -647,6 +744,20 @@ ${context}`);
647
744
  sections.push(`## Documents
648
745
  Document search failed: ${String(docResult.reason)}`);
649
746
  }
747
+ const allFailed = memoryResult.status === "rejected" && docResult.status === "rejected";
748
+ const partialSuccess = !allFailed && (memoryResult.status === "rejected" || docResult.status === "rejected" || conflictFetchFailed);
749
+ captureEvent(
750
+ "memorylake.tool.retrieve_context",
751
+ {
752
+ success: !allFailed,
753
+ partial_success: partialSuccess,
754
+ latency_ms: Date.now() - start,
755
+ memory_count: memoryCount,
756
+ document_count: docCount,
757
+ conflict_count: conflictCount
758
+ },
759
+ effectiveCfg
760
+ );
650
761
  if (memoryCount === 0 && docCount === 0) {
651
762
  return {
652
763
  content: [
@@ -691,6 +802,7 @@ Document search failed: ${String(docResult.reason)}`);
691
802
  )
692
803
  }),
693
804
  async execute(_toolCallId, params) {
805
+ const start = Date.now();
694
806
  const effectiveCfg = resolveConfig(ctx);
695
807
  const effectiveProvider = getProvider(effectiveCfg);
696
808
  const { text, userId } = params;
@@ -700,6 +812,15 @@ Document search failed: ${String(docResult.reason)}`);
700
812
  buildAddOptions(effectiveCfg, userId, ctx?.sessionId)
701
813
  );
702
814
  const count = result.results?.length ?? 0;
815
+ captureEvent(
816
+ "memorylake.tool.memory_store",
817
+ {
818
+ success: true,
819
+ latency_ms: Date.now() - start,
820
+ result_count: count
821
+ },
822
+ effectiveCfg
823
+ );
703
824
  return {
704
825
  content: [
705
826
  {
@@ -713,6 +834,15 @@ Document search failed: ${String(docResult.reason)}`);
713
834
  }
714
835
  };
715
836
  } catch (err) {
837
+ captureEvent(
838
+ "memorylake.tool.memory_store",
839
+ {
840
+ success: false,
841
+ latency_ms: Date.now() - start,
842
+ error: String(err)
843
+ },
844
+ effectiveCfg
845
+ );
716
846
  return {
717
847
  content: [
718
848
  {
@@ -740,12 +870,22 @@ Document search failed: ${String(docResult.reason)}`);
740
870
  )
741
871
  }),
742
872
  async execute(_toolCallId, params) {
873
+ const start = Date.now();
743
874
  const effectiveCfg = resolveConfig(ctx);
744
875
  const effectiveProvider = getProvider(effectiveCfg);
745
876
  const { userId } = params;
746
877
  try {
747
878
  const uid = userId || effectiveCfg.userId;
748
879
  const memories = await effectiveProvider.getAll({ user_id: uid });
880
+ captureEvent(
881
+ "memorylake.tool.memory_list",
882
+ {
883
+ success: true,
884
+ latency_ms: Date.now() - start,
885
+ result_count: memories.length
886
+ },
887
+ effectiveCfg
888
+ );
749
889
  if (!memories || memories.length === 0) {
750
890
  return {
751
891
  content: [
@@ -774,6 +914,15 @@ ${text}`
774
914
  details: { count: memories.length, memories: sanitized }
775
915
  };
776
916
  } catch (err) {
917
+ captureEvent(
918
+ "memorylake.tool.memory_list",
919
+ {
920
+ success: false,
921
+ latency_ms: Date.now() - start,
922
+ error: String(err)
923
+ },
924
+ effectiveCfg
925
+ );
777
926
  return {
778
927
  content: [
779
928
  {
@@ -797,11 +946,20 @@ ${text}`
797
946
  memoryId: Type.String({ description: "Memory ID to delete" })
798
947
  }),
799
948
  async execute(_toolCallId, params) {
949
+ const start = Date.now();
800
950
  const effectiveCfg = resolveConfig(ctx);
801
951
  const effectiveProvider = getProvider(effectiveCfg);
802
952
  const { memoryId } = params;
803
953
  try {
804
954
  await effectiveProvider.delete(memoryId);
955
+ captureEvent(
956
+ "memorylake.tool.memory_forget",
957
+ {
958
+ success: true,
959
+ latency_ms: Date.now() - start
960
+ },
961
+ effectiveCfg
962
+ );
805
963
  return {
806
964
  content: [
807
965
  { type: "text", text: `Memory ${memoryId} forgotten.` }
@@ -809,6 +967,15 @@ ${text}`
809
967
  details: { action: "deleted", id: memoryId }
810
968
  };
811
969
  } catch (err) {
970
+ captureEvent(
971
+ "memorylake.tool.memory_forget",
972
+ {
973
+ success: false,
974
+ latency_ms: Date.now() - start,
975
+ error: String(err)
976
+ },
977
+ effectiveCfg
978
+ );
812
979
  return {
813
980
  content: [
814
981
  {
@@ -863,6 +1030,7 @@ function registerDocumentTools(pctx) {
863
1030
  })
864
1031
  }),
865
1032
  async execute(_toolCallId, params) {
1033
+ const start = Date.now();
866
1034
  const effectiveCfg = resolveConfig(ctx);
867
1035
  const effectiveProvider = getProvider(effectiveCfg);
868
1036
  const { documentId } = params;
@@ -892,6 +1060,14 @@ function registerDocumentTools(pctx) {
892
1060
  }
893
1061
  }
894
1062
  fs3.renameSync(tempPath, localPath);
1063
+ captureEvent(
1064
+ "memorylake.tool.document_download",
1065
+ {
1066
+ success: true,
1067
+ latency_ms: Date.now() - start
1068
+ },
1069
+ effectiveCfg
1070
+ );
895
1071
  return {
896
1072
  content: [
897
1073
  {
@@ -905,6 +1081,15 @@ You MUST now call the message tool with action="send" and media set to this loca
905
1081
  details: { documentId, localPath }
906
1082
  };
907
1083
  } catch (err) {
1084
+ captureEvent(
1085
+ "memorylake.tool.document_download",
1086
+ {
1087
+ success: false,
1088
+ latency_ms: Date.now() - start,
1089
+ error: String(err)
1090
+ },
1091
+ effectiveCfg
1092
+ );
908
1093
  return {
909
1094
  content: [
910
1095
  {
@@ -973,6 +1158,7 @@ function registerSearchTools(pctx, cfg) {
973
1158
  )
974
1159
  }),
975
1160
  async execute(_toolCallId, params) {
1161
+ const start = Date.now();
976
1162
  const effectiveCfg = resolveConfig(ctx);
977
1163
  const effectiveProvider = getProvider(effectiveCfg);
978
1164
  const {
@@ -997,6 +1183,15 @@ function registerSearchTools(pctx, cfg) {
997
1183
  } : void 0
998
1184
  });
999
1185
  if (!response.results || response.results.length === 0) {
1186
+ captureEvent(
1187
+ "memorylake.tool.advanced_web_search",
1188
+ {
1189
+ success: true,
1190
+ latency_ms: Date.now() - start,
1191
+ result_count: 0
1192
+ },
1193
+ effectiveCfg
1194
+ );
1000
1195
  return {
1001
1196
  content: [
1002
1197
  { type: "text", text: "No relevant web results found." }
@@ -1005,6 +1200,15 @@ function registerSearchTools(pctx, cfg) {
1005
1200
  };
1006
1201
  }
1007
1202
  const context = buildWebSearchContext(response.results);
1203
+ captureEvent(
1204
+ "memorylake.tool.advanced_web_search",
1205
+ {
1206
+ success: true,
1207
+ latency_ms: Date.now() - start,
1208
+ result_count: response.results.length
1209
+ },
1210
+ effectiveCfg
1211
+ );
1008
1212
  return {
1009
1213
  content: [
1010
1214
  {
@@ -1021,6 +1225,15 @@ ${context}`
1021
1225
  }
1022
1226
  };
1023
1227
  } catch (err) {
1228
+ captureEvent(
1229
+ "memorylake.tool.advanced_web_search",
1230
+ {
1231
+ success: false,
1232
+ latency_ms: Date.now() - start,
1233
+ error: String(err)
1234
+ },
1235
+ effectiveCfg
1236
+ );
1024
1237
  return {
1025
1238
  content: [
1026
1239
  {
@@ -1076,6 +1289,7 @@ ${context}`
1076
1289
  )
1077
1290
  }),
1078
1291
  async execute(_toolCallId, params) {
1292
+ const start = Date.now();
1079
1293
  const effectiveCfg = resolveConfig(ctx);
1080
1294
  const effectiveProvider = getProvider(effectiveCfg);
1081
1295
  const {
@@ -1087,6 +1301,15 @@ ${context}`
1087
1301
  } = params;
1088
1302
  const dataset = normalizeOpenDataCategory(rawDataset);
1089
1303
  if (!dataset) {
1304
+ captureEvent(
1305
+ "memorylake.tool.open_data_search",
1306
+ {
1307
+ success: false,
1308
+ latency_ms: Date.now() - start,
1309
+ error: "unsupported_dataset"
1310
+ },
1311
+ effectiveCfg
1312
+ );
1090
1313
  return {
1091
1314
  content: [
1092
1315
  {
@@ -1102,6 +1325,15 @@ ${context}`
1102
1325
  if (projectInfo.industries.length > 0) {
1103
1326
  const allowedIds = projectInfo.industries.map((ind) => ind.id);
1104
1327
  if (!allowedIds.includes(dataset)) {
1328
+ captureEvent(
1329
+ "memorylake.tool.open_data_search",
1330
+ {
1331
+ success: false,
1332
+ latency_ms: Date.now() - start,
1333
+ error: "dataset_not_allowed"
1334
+ },
1335
+ effectiveCfg
1336
+ );
1105
1337
  const allowed = projectInfo.industries.map((ind) => `${ind.id} (${ind.name})`).join(", ");
1106
1338
  return {
1107
1339
  content: [
@@ -1125,6 +1357,15 @@ ${context}`
1125
1357
  end_date: endDate
1126
1358
  });
1127
1359
  if (!response.results || response.results.length === 0) {
1360
+ captureEvent(
1361
+ "memorylake.tool.open_data_search",
1362
+ {
1363
+ success: true,
1364
+ latency_ms: Date.now() - start,
1365
+ result_count: 0
1366
+ },
1367
+ effectiveCfg
1368
+ );
1128
1369
  return {
1129
1370
  content: [
1130
1371
  { type: "text", text: "No relevant open data results found." }
@@ -1133,6 +1374,15 @@ ${context}`
1133
1374
  };
1134
1375
  }
1135
1376
  const context = buildOpenDataContext(response.results);
1377
+ captureEvent(
1378
+ "memorylake.tool.open_data_search",
1379
+ {
1380
+ success: true,
1381
+ latency_ms: Date.now() - start,
1382
+ result_count: response.results.length
1383
+ },
1384
+ effectiveCfg
1385
+ );
1136
1386
  return {
1137
1387
  content: [
1138
1388
  {
@@ -1149,6 +1399,15 @@ ${context}`
1149
1399
  }
1150
1400
  };
1151
1401
  } catch (err) {
1402
+ captureEvent(
1403
+ "memorylake.tool.open_data_search",
1404
+ {
1405
+ success: false,
1406
+ latency_ms: Date.now() - start,
1407
+ error: String(err)
1408
+ },
1409
+ effectiveCfg
1410
+ );
1152
1411
  return {
1153
1412
  content: [
1154
1413
  {
@@ -1176,6 +1435,7 @@ function registerCli(pctx, cfg) {
1176
1435
  ({ program }) => {
1177
1436
  const memorylake = program.command("memorylake").description("MemoryLake memory plugin commands");
1178
1437
  memorylake.command("search").description("Search memories in MemoryLake").argument("<query>", "Search query").option("--limit <n>", "Max results", String(cfg.topK)).action(async (query, opts) => {
1438
+ const start = Date.now();
1179
1439
  try {
1180
1440
  const limit = parseInt(opts.limit, 10);
1181
1441
  const results = await provider.search(
@@ -1183,6 +1443,11 @@ function registerCli(pctx, cfg) {
1183
1443
  buildSearchOptions(cfg, void 0, limit)
1184
1444
  );
1185
1445
  if (!results.length) {
1446
+ captureEvent("memorylake.cli.search", {
1447
+ success: true,
1448
+ latency_ms: Date.now() - start,
1449
+ result_count: 0
1450
+ }, cfg);
1186
1451
  console.log("No memories found.");
1187
1452
  return;
1188
1453
  }
@@ -1192,12 +1457,23 @@ function registerCli(pctx, cfg) {
1192
1457
  user_id: r.user_id,
1193
1458
  created_at: r.created_at
1194
1459
  }));
1460
+ captureEvent("memorylake.cli.search", {
1461
+ success: true,
1462
+ latency_ms: Date.now() - start,
1463
+ result_count: results.length
1464
+ }, cfg);
1195
1465
  console.log(JSON.stringify(output, null, 2));
1196
1466
  } catch (err) {
1467
+ captureEvent("memorylake.cli.search", {
1468
+ success: false,
1469
+ latency_ms: Date.now() - start,
1470
+ error: String(err)
1471
+ }, cfg);
1197
1472
  console.error(`Search failed: ${String(err)}`);
1198
1473
  }
1199
1474
  });
1200
1475
  memorylake.command("upload").description("Upload files or directories to MemoryLake").argument("<path>", "File or directory path to upload").option("--agent <id>", "Agent ID (resolves workspace and per-agent projectId)").option("--project-id <id>", "Override project ID (takes precedence over --agent)").action(async (targetPath, opts) => {
1476
+ const start = Date.now();
1201
1477
  let effectiveCfg = cfg;
1202
1478
  if (opts.agent) {
1203
1479
  try {
@@ -1217,10 +1493,20 @@ function registerCli(pctx, cfg) {
1217
1493
  }
1218
1494
  const effectiveProjectId = opts.projectId || effectiveCfg.projectId;
1219
1495
  if (!effectiveProjectId) {
1496
+ captureEvent("memorylake.cli.upload", {
1497
+ success: false,
1498
+ latency_ms: Date.now() - start,
1499
+ error: "missing_project_id"
1500
+ }, effectiveCfg);
1220
1501
  console.error("No project ID configured. Use --project-id or set up agent/workspace config.");
1221
1502
  return;
1222
1503
  }
1223
1504
  if (!effectiveCfg.host || !effectiveCfg.apiKey) {
1505
+ captureEvent("memorylake.cli.upload", {
1506
+ success: false,
1507
+ latency_ms: Date.now() - start,
1508
+ error: "missing_host_or_api_key"
1509
+ }, effectiveCfg);
1224
1510
  console.error("Missing host or apiKey in config. Check your MemoryLake configuration.");
1225
1511
  return;
1226
1512
  }
@@ -1232,6 +1518,11 @@ function registerCli(pctx, cfg) {
1232
1518
  );
1233
1519
  uploadFn = uploadModule.uploadAuto;
1234
1520
  } catch (err) {
1521
+ captureEvent("memorylake.cli.upload", {
1522
+ success: false,
1523
+ latency_ms: Date.now() - start,
1524
+ error: String(err)
1525
+ }, effectiveCfg);
1235
1526
  console.error(`Failed to load upload module: ${String(err)}`);
1236
1527
  return;
1237
1528
  }
@@ -1244,15 +1535,34 @@ function registerCli(pctx, cfg) {
1244
1535
  filePath: absPath,
1245
1536
  fileName: path3.basename(absPath)
1246
1537
  });
1538
+ captureEvent("memorylake.cli.upload", {
1539
+ success: true,
1540
+ latency_ms: Date.now() - start,
1541
+ agent_override: !!opts.agent,
1542
+ project_override: !!opts.projectId
1543
+ }, effectiveCfg);
1247
1544
  } catch (err) {
1545
+ captureEvent("memorylake.cli.upload", {
1546
+ success: false,
1547
+ latency_ms: Date.now() - start,
1548
+ error: String(err),
1549
+ agent_override: !!opts.agent,
1550
+ project_override: !!opts.projectId
1551
+ }, effectiveCfg);
1248
1552
  console.error(`Upload failed: ${String(err)}`);
1249
1553
  }
1250
1554
  });
1251
1555
  memorylake.command("stats").description("Show memory statistics from MemoryLake").action(async () => {
1556
+ const start = Date.now();
1252
1557
  try {
1253
1558
  const memories = await provider.getAll({
1254
1559
  user_id: cfg.userId
1255
1560
  });
1561
+ captureEvent("memorylake.cli.stats", {
1562
+ success: true,
1563
+ latency_ms: Date.now() - start,
1564
+ result_count: Array.isArray(memories) ? memories.length : 0
1565
+ }, cfg);
1256
1566
  console.log(`User: ${cfg.userId}`);
1257
1567
  console.log(
1258
1568
  `Total memories: ${Array.isArray(memories) ? memories.length : "unknown"}`
@@ -1261,6 +1571,11 @@ function registerCli(pctx, cfg) {
1261
1571
  `Auto-recall: ${cfg.autoRecall}, Auto-capture: ${cfg.autoCapture}`
1262
1572
  );
1263
1573
  } catch (err) {
1574
+ captureEvent("memorylake.cli.stats", {
1575
+ success: false,
1576
+ latency_ms: Date.now() - start,
1577
+ error: String(err)
1578
+ }, cfg);
1264
1579
  console.error(`Stats failed: ${String(err)}`);
1265
1580
  }
1266
1581
  });
@@ -1352,6 +1667,7 @@ function registerAutoUpload(pctx) {
1352
1667
  uploadAutoFn = uploadModule.uploadAuto;
1353
1668
  }
1354
1669
  for (const { filePath, stat } of filesToUpload) {
1670
+ const uploadStart = Date.now();
1355
1671
  try {
1356
1672
  await uploadAutoFn({
1357
1673
  host: effectiveCfg.host,
@@ -1363,10 +1679,27 @@ function registerAutoUpload(pctx) {
1363
1679
  const current = getUploadedRecord(workspaceDir);
1364
1680
  current[filePath] = { mtimeMs: stat.mtimeMs };
1365
1681
  saveUploadedRecord(workspaceDir, current);
1682
+ captureEvent(
1683
+ "memorylake.hook.upload",
1684
+ {
1685
+ success: true,
1686
+ latency_ms: Date.now() - uploadStart
1687
+ },
1688
+ effectiveCfg
1689
+ );
1366
1690
  api.logger.info(
1367
1691
  `memorylake-openclaw: auto-uploaded ${path5.basename(filePath)}`
1368
1692
  );
1369
1693
  } catch (err) {
1694
+ captureEvent(
1695
+ "memorylake.hook.upload",
1696
+ {
1697
+ success: false,
1698
+ latency_ms: Date.now() - uploadStart,
1699
+ error: String(err)
1700
+ },
1701
+ effectiveCfg
1702
+ );
1370
1703
  api.logger.warn(
1371
1704
  `memorylake-openclaw: auto-upload failed for ${filePath}: ${String(err)}`
1372
1705
  );
@@ -1396,12 +1729,15 @@ function registerAutoRecall(pctx) {
1396
1729
  return;
1397
1730
  }
1398
1731
  if (!event.prompt) return;
1732
+ const recallStart = Date.now();
1399
1733
  const effectiveCfg = resolveConfig(ctx);
1400
1734
  const effectiveProvider = getProvider(effectiveCfg);
1401
1735
  const sessionId = ctx?.sessionId ?? void 0;
1402
1736
  let industries;
1737
+ let cacheHit = false;
1403
1738
  if (sessionId && sessionIndustriesCache.has(sessionId)) {
1404
1739
  industries = sessionIndustriesCache.get(sessionId);
1740
+ cacheHit = true;
1405
1741
  } else {
1406
1742
  try {
1407
1743
  const projectInfo = await effectiveProvider.getProject();
@@ -1452,6 +1788,16 @@ When the user's question relates to any of these categories, use the open_data_s
1452
1788
  if (appendParts.length > 0) {
1453
1789
  result.appendSystemContext = appendParts.join("\n\n");
1454
1790
  }
1791
+ captureEvent(
1792
+ "memorylake.hook.recall",
1793
+ {
1794
+ success: true,
1795
+ cache_hit: cacheHit,
1796
+ industries_count: industries?.length ?? 0,
1797
+ latency_ms: Date.now() - recallStart
1798
+ },
1799
+ effectiveCfg
1800
+ );
1455
1801
  return result;
1456
1802
  });
1457
1803
  }
@@ -1727,6 +2073,7 @@ function registerAutoCapture(pctx) {
1727
2073
  const effectiveCfg = resolveConfig(ctx);
1728
2074
  const effectiveProvider = getProvider(effectiveCfg);
1729
2075
  const lastSent = sessionWatermarks.get(sessionId) ?? 0;
2076
+ const captureStart = Date.now();
1730
2077
  try {
1731
2078
  const formattedMessages = [];
1732
2079
  let maxTimestamp = lastSent;
@@ -1753,12 +2100,31 @@ function registerAutoCapture(pctx) {
1753
2100
  sessionWatermarks.set(sessionId, maxTimestamp);
1754
2101
  }
1755
2102
  const capturedCount = result.results?.length ?? 0;
2103
+ captureEvent(
2104
+ "memorylake.hook.capture",
2105
+ {
2106
+ success: true,
2107
+ captured_count: capturedCount,
2108
+ latency_ms: Date.now() - captureStart,
2109
+ message_count: formattedMessages.length
2110
+ },
2111
+ effectiveCfg
2112
+ );
1756
2113
  if (capturedCount > 0) {
1757
2114
  api.logger.info(
1758
2115
  `memorylake-openclaw: auto-captured ${capturedCount} memories from ${formattedMessages.length} new message(s)`
1759
2116
  );
1760
2117
  }
1761
2118
  } catch (err) {
2119
+ captureEvent(
2120
+ "memorylake.hook.capture",
2121
+ {
2122
+ success: false,
2123
+ latency_ms: Date.now() - captureStart,
2124
+ error: String(err)
2125
+ },
2126
+ effectiveCfg
2127
+ );
1762
2128
  api.logger.warn(`memorylake-openclaw: capture failed: ${String(err)}`);
1763
2129
  }
1764
2130
  });
@@ -1775,6 +2141,15 @@ var memoryPlugin = {
1775
2141
  const cfg = memoryLakeConfigSchema.parse(api.pluginConfig);
1776
2142
  const pctx = createPluginContext(api, cfg);
1777
2143
  registerMemoryPromptSection(pctx, cfg);
2144
+ captureEvent(
2145
+ "memorylake.plugin.registered",
2146
+ {
2147
+ auto_recall: cfg.autoRecall,
2148
+ auto_capture: cfg.autoCapture,
2149
+ auto_upload: cfg.autoUpload
2150
+ },
2151
+ cfg
2152
+ );
1778
2153
  api.logger.info(
1779
2154
  `memorylake-openclaw: registered (user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, autoUpload: ${cfg.autoUpload})`
1780
2155
  );
@@ -1788,6 +2163,15 @@ var memoryPlugin = {
1788
2163
  api.registerService({
1789
2164
  id: "memorylake-openclaw",
1790
2165
  start: () => {
2166
+ captureEvent(
2167
+ "memorylake.plugin.initialized",
2168
+ {
2169
+ auto_recall: cfg.autoRecall,
2170
+ auto_capture: cfg.autoCapture,
2171
+ auto_upload: cfg.autoUpload
2172
+ },
2173
+ cfg
2174
+ );
1791
2175
  api.logger.info(
1792
2176
  `memorylake-openclaw: initialized (user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, autoUpload: ${cfg.autoUpload})`
1793
2177
  );