memorylake-openclaw 1.1.5 → 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 +402 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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:
|
|
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
|
{
|
|
@@ -1033,7 +1246,7 @@ ${context}`
|
|
|
1033
1246
|
}
|
|
1034
1247
|
}
|
|
1035
1248
|
}),
|
|
1036
|
-
{ optional: true }
|
|
1249
|
+
{ optional: true, name: "advanced_web_search" }
|
|
1037
1250
|
);
|
|
1038
1251
|
api.registerTool(
|
|
1039
1252
|
(ctx) => ({
|
|
@@ -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
|
{
|
|
@@ -1160,7 +1419,8 @@ ${context}`
|
|
|
1160
1419
|
};
|
|
1161
1420
|
}
|
|
1162
1421
|
}
|
|
1163
|
-
})
|
|
1422
|
+
}),
|
|
1423
|
+
{ name: "open_data_search" }
|
|
1164
1424
|
);
|
|
1165
1425
|
}
|
|
1166
1426
|
|
|
@@ -1175,6 +1435,7 @@ function registerCli(pctx, cfg) {
|
|
|
1175
1435
|
({ program }) => {
|
|
1176
1436
|
const memorylake = program.command("memorylake").description("MemoryLake memory plugin commands");
|
|
1177
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();
|
|
1178
1439
|
try {
|
|
1179
1440
|
const limit = parseInt(opts.limit, 10);
|
|
1180
1441
|
const results = await provider.search(
|
|
@@ -1182,6 +1443,11 @@ function registerCli(pctx, cfg) {
|
|
|
1182
1443
|
buildSearchOptions(cfg, void 0, limit)
|
|
1183
1444
|
);
|
|
1184
1445
|
if (!results.length) {
|
|
1446
|
+
captureEvent("memorylake.cli.search", {
|
|
1447
|
+
success: true,
|
|
1448
|
+
latency_ms: Date.now() - start,
|
|
1449
|
+
result_count: 0
|
|
1450
|
+
}, cfg);
|
|
1185
1451
|
console.log("No memories found.");
|
|
1186
1452
|
return;
|
|
1187
1453
|
}
|
|
@@ -1191,12 +1457,23 @@ function registerCli(pctx, cfg) {
|
|
|
1191
1457
|
user_id: r.user_id,
|
|
1192
1458
|
created_at: r.created_at
|
|
1193
1459
|
}));
|
|
1460
|
+
captureEvent("memorylake.cli.search", {
|
|
1461
|
+
success: true,
|
|
1462
|
+
latency_ms: Date.now() - start,
|
|
1463
|
+
result_count: results.length
|
|
1464
|
+
}, cfg);
|
|
1194
1465
|
console.log(JSON.stringify(output, null, 2));
|
|
1195
1466
|
} catch (err) {
|
|
1467
|
+
captureEvent("memorylake.cli.search", {
|
|
1468
|
+
success: false,
|
|
1469
|
+
latency_ms: Date.now() - start,
|
|
1470
|
+
error: String(err)
|
|
1471
|
+
}, cfg);
|
|
1196
1472
|
console.error(`Search failed: ${String(err)}`);
|
|
1197
1473
|
}
|
|
1198
1474
|
});
|
|
1199
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();
|
|
1200
1477
|
let effectiveCfg = cfg;
|
|
1201
1478
|
if (opts.agent) {
|
|
1202
1479
|
try {
|
|
@@ -1216,10 +1493,20 @@ function registerCli(pctx, cfg) {
|
|
|
1216
1493
|
}
|
|
1217
1494
|
const effectiveProjectId = opts.projectId || effectiveCfg.projectId;
|
|
1218
1495
|
if (!effectiveProjectId) {
|
|
1496
|
+
captureEvent("memorylake.cli.upload", {
|
|
1497
|
+
success: false,
|
|
1498
|
+
latency_ms: Date.now() - start,
|
|
1499
|
+
error: "missing_project_id"
|
|
1500
|
+
}, effectiveCfg);
|
|
1219
1501
|
console.error("No project ID configured. Use --project-id or set up agent/workspace config.");
|
|
1220
1502
|
return;
|
|
1221
1503
|
}
|
|
1222
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);
|
|
1223
1510
|
console.error("Missing host or apiKey in config. Check your MemoryLake configuration.");
|
|
1224
1511
|
return;
|
|
1225
1512
|
}
|
|
@@ -1231,6 +1518,11 @@ function registerCli(pctx, cfg) {
|
|
|
1231
1518
|
);
|
|
1232
1519
|
uploadFn = uploadModule.uploadAuto;
|
|
1233
1520
|
} catch (err) {
|
|
1521
|
+
captureEvent("memorylake.cli.upload", {
|
|
1522
|
+
success: false,
|
|
1523
|
+
latency_ms: Date.now() - start,
|
|
1524
|
+
error: String(err)
|
|
1525
|
+
}, effectiveCfg);
|
|
1234
1526
|
console.error(`Failed to load upload module: ${String(err)}`);
|
|
1235
1527
|
return;
|
|
1236
1528
|
}
|
|
@@ -1243,15 +1535,34 @@ function registerCli(pctx, cfg) {
|
|
|
1243
1535
|
filePath: absPath,
|
|
1244
1536
|
fileName: path3.basename(absPath)
|
|
1245
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);
|
|
1246
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);
|
|
1247
1552
|
console.error(`Upload failed: ${String(err)}`);
|
|
1248
1553
|
}
|
|
1249
1554
|
});
|
|
1250
1555
|
memorylake.command("stats").description("Show memory statistics from MemoryLake").action(async () => {
|
|
1556
|
+
const start = Date.now();
|
|
1251
1557
|
try {
|
|
1252
1558
|
const memories = await provider.getAll({
|
|
1253
1559
|
user_id: cfg.userId
|
|
1254
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);
|
|
1255
1566
|
console.log(`User: ${cfg.userId}`);
|
|
1256
1567
|
console.log(
|
|
1257
1568
|
`Total memories: ${Array.isArray(memories) ? memories.length : "unknown"}`
|
|
@@ -1260,6 +1571,11 @@ function registerCli(pctx, cfg) {
|
|
|
1260
1571
|
`Auto-recall: ${cfg.autoRecall}, Auto-capture: ${cfg.autoCapture}`
|
|
1261
1572
|
);
|
|
1262
1573
|
} catch (err) {
|
|
1574
|
+
captureEvent("memorylake.cli.stats", {
|
|
1575
|
+
success: false,
|
|
1576
|
+
latency_ms: Date.now() - start,
|
|
1577
|
+
error: String(err)
|
|
1578
|
+
}, cfg);
|
|
1263
1579
|
console.error(`Stats failed: ${String(err)}`);
|
|
1264
1580
|
}
|
|
1265
1581
|
});
|
|
@@ -1273,8 +1589,10 @@ import path5 from "path";
|
|
|
1273
1589
|
|
|
1274
1590
|
// lib/helpers/upload-record.ts
|
|
1275
1591
|
import fs4 from "fs";
|
|
1592
|
+
import os4 from "os";
|
|
1276
1593
|
import path4 from "path";
|
|
1277
1594
|
var UPLOADED_RECORD_FILE = "uploaded.json";
|
|
1595
|
+
var MEDIA_URI_PREFIX = "media://inbound/";
|
|
1278
1596
|
function getUploadedRecord(workspaceDir) {
|
|
1279
1597
|
const filePath = path4.join(workspaceDir, ".memorylake", UPLOADED_RECORD_FILE);
|
|
1280
1598
|
try {
|
|
@@ -1300,14 +1618,22 @@ function needsUpload(record, filePath) {
|
|
|
1300
1618
|
const prev = record[filePath];
|
|
1301
1619
|
return !prev || prev.mtimeMs !== stat.mtimeMs ? stat : null;
|
|
1302
1620
|
}
|
|
1621
|
+
function resolveInboundMediaUri(value) {
|
|
1622
|
+
if (value.startsWith(MEDIA_URI_PREFIX)) {
|
|
1623
|
+
return path4.join(os4.homedir(), ".openclaw", "media", "inbound", value.slice(MEDIA_URI_PREFIX.length));
|
|
1624
|
+
}
|
|
1625
|
+
return value;
|
|
1626
|
+
}
|
|
1303
1627
|
function extractInboundPaths(prompt) {
|
|
1304
1628
|
const sep = "[/\\\\]";
|
|
1305
|
-
const
|
|
1629
|
+
const absRegex = new RegExp(
|
|
1306
1630
|
`(?:[A-Za-z]:${sep}|/)\\S*?media${sep}inbound${sep}.+?\\.[a-zA-Z0-9]{1,6}(?=[^a-zA-Z0-9]|$)`,
|
|
1307
1631
|
"g"
|
|
1308
1632
|
);
|
|
1309
|
-
const
|
|
1310
|
-
|
|
1633
|
+
const uriRegex = /media:\/\/inbound\/.+?\.[a-zA-Z0-9]{1,6}(?=[^a-zA-Z0-9]|$)/g;
|
|
1634
|
+
const absMatches = prompt.match(absRegex) || [];
|
|
1635
|
+
const uriMatches = (prompt.match(uriRegex) || []).map(resolveInboundMediaUri);
|
|
1636
|
+
return [.../* @__PURE__ */ new Set([...absMatches, ...uriMatches])];
|
|
1311
1637
|
}
|
|
1312
1638
|
|
|
1313
1639
|
// lib/hooks/auto-upload.ts
|
|
@@ -1341,6 +1667,7 @@ function registerAutoUpload(pctx) {
|
|
|
1341
1667
|
uploadAutoFn = uploadModule.uploadAuto;
|
|
1342
1668
|
}
|
|
1343
1669
|
for (const { filePath, stat } of filesToUpload) {
|
|
1670
|
+
const uploadStart = Date.now();
|
|
1344
1671
|
try {
|
|
1345
1672
|
await uploadAutoFn({
|
|
1346
1673
|
host: effectiveCfg.host,
|
|
@@ -1352,10 +1679,27 @@ function registerAutoUpload(pctx) {
|
|
|
1352
1679
|
const current = getUploadedRecord(workspaceDir);
|
|
1353
1680
|
current[filePath] = { mtimeMs: stat.mtimeMs };
|
|
1354
1681
|
saveUploadedRecord(workspaceDir, current);
|
|
1682
|
+
captureEvent(
|
|
1683
|
+
"memorylake.hook.upload",
|
|
1684
|
+
{
|
|
1685
|
+
success: true,
|
|
1686
|
+
latency_ms: Date.now() - uploadStart
|
|
1687
|
+
},
|
|
1688
|
+
effectiveCfg
|
|
1689
|
+
);
|
|
1355
1690
|
api.logger.info(
|
|
1356
1691
|
`memorylake-openclaw: auto-uploaded ${path5.basename(filePath)}`
|
|
1357
1692
|
);
|
|
1358
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
|
+
);
|
|
1359
1703
|
api.logger.warn(
|
|
1360
1704
|
`memorylake-openclaw: auto-upload failed for ${filePath}: ${String(err)}`
|
|
1361
1705
|
);
|
|
@@ -1385,12 +1729,15 @@ function registerAutoRecall(pctx) {
|
|
|
1385
1729
|
return;
|
|
1386
1730
|
}
|
|
1387
1731
|
if (!event.prompt) return;
|
|
1732
|
+
const recallStart = Date.now();
|
|
1388
1733
|
const effectiveCfg = resolveConfig(ctx);
|
|
1389
1734
|
const effectiveProvider = getProvider(effectiveCfg);
|
|
1390
1735
|
const sessionId = ctx?.sessionId ?? void 0;
|
|
1391
1736
|
let industries;
|
|
1737
|
+
let cacheHit = false;
|
|
1392
1738
|
if (sessionId && sessionIndustriesCache.has(sessionId)) {
|
|
1393
1739
|
industries = sessionIndustriesCache.get(sessionId);
|
|
1740
|
+
cacheHit = true;
|
|
1394
1741
|
} else {
|
|
1395
1742
|
try {
|
|
1396
1743
|
const projectInfo = await effectiveProvider.getProject();
|
|
@@ -1441,6 +1788,16 @@ When the user's question relates to any of these categories, use the open_data_s
|
|
|
1441
1788
|
if (appendParts.length > 0) {
|
|
1442
1789
|
result.appendSystemContext = appendParts.join("\n\n");
|
|
1443
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
|
+
);
|
|
1444
1801
|
return result;
|
|
1445
1802
|
});
|
|
1446
1803
|
}
|
|
@@ -1716,6 +2073,7 @@ function registerAutoCapture(pctx) {
|
|
|
1716
2073
|
const effectiveCfg = resolveConfig(ctx);
|
|
1717
2074
|
const effectiveProvider = getProvider(effectiveCfg);
|
|
1718
2075
|
const lastSent = sessionWatermarks.get(sessionId) ?? 0;
|
|
2076
|
+
const captureStart = Date.now();
|
|
1719
2077
|
try {
|
|
1720
2078
|
const formattedMessages = [];
|
|
1721
2079
|
let maxTimestamp = lastSent;
|
|
@@ -1742,12 +2100,31 @@ function registerAutoCapture(pctx) {
|
|
|
1742
2100
|
sessionWatermarks.set(sessionId, maxTimestamp);
|
|
1743
2101
|
}
|
|
1744
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
|
+
);
|
|
1745
2113
|
if (capturedCount > 0) {
|
|
1746
2114
|
api.logger.info(
|
|
1747
2115
|
`memorylake-openclaw: auto-captured ${capturedCount} memories from ${formattedMessages.length} new message(s)`
|
|
1748
2116
|
);
|
|
1749
2117
|
}
|
|
1750
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
|
+
);
|
|
1751
2128
|
api.logger.warn(`memorylake-openclaw: capture failed: ${String(err)}`);
|
|
1752
2129
|
}
|
|
1753
2130
|
});
|
|
@@ -1764,6 +2141,15 @@ var memoryPlugin = {
|
|
|
1764
2141
|
const cfg = memoryLakeConfigSchema.parse(api.pluginConfig);
|
|
1765
2142
|
const pctx = createPluginContext(api, cfg);
|
|
1766
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
|
+
);
|
|
1767
2153
|
api.logger.info(
|
|
1768
2154
|
`memorylake-openclaw: registered (user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, autoUpload: ${cfg.autoUpload})`
|
|
1769
2155
|
);
|
|
@@ -1777,6 +2163,15 @@ var memoryPlugin = {
|
|
|
1777
2163
|
api.registerService({
|
|
1778
2164
|
id: "memorylake-openclaw",
|
|
1779
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
|
+
);
|
|
1780
2175
|
api.logger.info(
|
|
1781
2176
|
`memorylake-openclaw: initialized (user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, autoUpload: ${cfg.autoUpload})`
|
|
1782
2177
|
);
|