|
@@ -63,6 +63,20 @@ function loadPluginCfg() {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
|
|
+// Logging helpers
|
|
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
|
|
+type LogLevel = "log" | "warn" | "error";
|
|
|
|
|
+
|
|
|
|
|
+function logHook(tag: string, detail: Record<string, unknown>, level: LogLevel = "log") {
|
|
|
|
|
+ const payload = { tag, ...detail };
|
|
|
|
|
+ try {
|
|
|
|
|
+ console[level](`[mem0] ${tag}`, JSON.stringify(payload));
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ console[level](`[mem0] ${tag}`, payload);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
// Types
|
|
// Types
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
@@ -251,7 +265,7 @@ async function mem0SearchMemories(
|
|
|
const res = await fetch(`${baseUrl}/memories/search`, {
|
|
const res = await fetch(`${baseUrl}/memories/search`, {
|
|
|
method: "POST",
|
|
method: "POST",
|
|
|
headers: { "Content-Type": "application/json" },
|
|
headers: { "Content-Type": "application/json" },
|
|
|
- body: JSON.stringify({ query, userId }),
|
|
|
|
|
|
|
+ body: JSON.stringify({ query, userId, limit }),
|
|
|
});
|
|
});
|
|
|
if (!res.ok) {
|
|
if (!res.ok) {
|
|
|
console.error(`[mem0-recall] /memories/search returned ${res.status}`);
|
|
console.error(`[mem0-recall] /memories/search returned ${res.status}`);
|
|
@@ -275,7 +289,7 @@ async function mem0SearchKnowledge(
|
|
|
const res = await fetch(`${baseUrl}/knowledge/search`, {
|
|
const res = await fetch(`${baseUrl}/knowledge/search`, {
|
|
|
method: "POST",
|
|
method: "POST",
|
|
|
headers: { "Content-Type": "application/json" },
|
|
headers: { "Content-Type": "application/json" },
|
|
|
- body: JSON.stringify({ query, userId: knowledgeUserId }),
|
|
|
|
|
|
|
+ body: JSON.stringify({ query, userId: knowledgeUserId, limit }),
|
|
|
});
|
|
});
|
|
|
if (!res.ok) {
|
|
if (!res.ok) {
|
|
|
console.error(`[mem0-recall] /knowledge/search returned ${res.status}`);
|
|
console.error(`[mem0-recall] /knowledge/search returned ${res.status}`);
|
|
@@ -395,24 +409,17 @@ const CAPTURE_DEDUP_MS = 60_000;
|
|
|
// Main handler
|
|
// Main handler
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
export default async function handler(event: HookEvent) {
|
|
export default async function handler(event: HookEvent) {
|
|
|
- console.log(
|
|
|
|
|
- "[mem0-FIRE]",
|
|
|
|
|
- JSON.stringify(
|
|
|
|
|
- {
|
|
|
|
|
- type: event.type,
|
|
|
|
|
- action: event.action,
|
|
|
|
|
- sessionKey: event.sessionKey,
|
|
|
|
|
- contextKeys: Object.keys(event.context || {}),
|
|
|
|
|
- content: event.context?.content?.slice(0, 80),
|
|
|
|
|
- messagesLen: event.messages?.length,
|
|
|
|
|
- },
|
|
|
|
|
- null,
|
|
|
|
|
- 2
|
|
|
|
|
- )
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ logHook("fire", {
|
|
|
|
|
+ type: event.type,
|
|
|
|
|
+ action: event.action,
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ contextKeys: Object.keys(event.context || {}),
|
|
|
|
|
+ content: event.context?.content?.slice(0, 80),
|
|
|
|
|
+ messagesLen: event.messages?.length,
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
if (event.type !== "message") {
|
|
if (event.type !== "message") {
|
|
|
- console.log("[mem0-FIRE] bailed: type is not message, got:", event.type);
|
|
|
|
|
|
|
+ logHook("fire-bail", { type: event.type, sessionKey: event.sessionKey }, "warn");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -480,7 +487,11 @@ export default async function handler(event: HookEvent) {
|
|
|
|
|
|
|
|
const { baseUrl, recallLimit, rerankThreshold } = pluginCfg;
|
|
const { baseUrl, recallLimit, rerankThreshold } = pluginCfg;
|
|
|
|
|
|
|
|
- console.log("[mem0-auto-recall] query:", text.slice(0, 120));
|
|
|
|
|
|
|
+ logHook("auto-recall-query", {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ query: text.slice(0, 120),
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
const personalResults = await mem0SearchMemories(
|
|
const personalResults = await mem0SearchMemories(
|
|
|
baseUrl,
|
|
baseUrl,
|
|
@@ -489,9 +500,10 @@ export default async function handler(event: HookEvent) {
|
|
|
recallLimit
|
|
recallLimit
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- console.log("[mem0-auto-recall]", {
|
|
|
|
|
|
|
+ logHook("auto-recall-result", {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
userId,
|
|
userId,
|
|
|
- personalCount: personalResults?.length ?? "error",
|
|
|
|
|
|
|
+ personalCount: personalResults?.length ?? 0,
|
|
|
threshold: rerankThreshold,
|
|
threshold: rerankThreshold,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -501,10 +513,20 @@ export default async function handler(event: HookEvent) {
|
|
|
rerankThreshold
|
|
rerankThreshold
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- if (!injectionBlock) return; // nothing passed the threshold from either endpoint
|
|
|
|
|
|
|
+ if (!injectionBlock) {
|
|
|
|
|
+ logHook("auto-recall-injection-skip", {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ });
|
|
|
|
|
+ return; // nothing passed the threshold from either endpoint
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
event.context.bodyForAgent = `${text}\n\n${injectionBlock}`;
|
|
event.context.bodyForAgent = `${text}\n\n${injectionBlock}`;
|
|
|
- console.log("[mem0-injected-prompt]\n" + event.context.bodyForAgent);
|
|
|
|
|
|
|
+ logHook("auto-recall-injection", {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ snippet: injectionBlock.slice(0, 200),
|
|
|
|
|
+ });
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// ── received: capture ────────────────────────────────────────────────────
|
|
// ── received: capture ────────────────────────────────────────────────────
|
|
@@ -544,29 +566,26 @@ export default async function handler(event: HookEvent) {
|
|
|
const hash = simpleHash(JSON.stringify(captureMessages));
|
|
const hash = simpleHash(JSON.stringify(captureMessages));
|
|
|
const lastCapture = recentlyCaptured.get(hash);
|
|
const lastCapture = recentlyCaptured.get(hash);
|
|
|
if (lastCapture && Date.now() - lastCapture < CAPTURE_DEDUP_MS) {
|
|
if (lastCapture && Date.now() - lastCapture < CAPTURE_DEDUP_MS) {
|
|
|
- console.log("[mem0-auto-capture] skipped duplicate");
|
|
|
|
|
|
|
+ logHook("auto-capture-duplicate", {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ });
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
recentlyCaptured.set(hash, Date.now());
|
|
recentlyCaptured.set(hash, Date.now());
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
|
+ const captureDetail: Record<string, unknown> = {
|
|
|
|
|
+ sessionKey: event.sessionKey,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ captureTrigger,
|
|
|
|
|
+ hasAssistantMessage: !!assistantMessage,
|
|
|
|
|
+ messageCount: captureMessages.length,
|
|
|
|
|
+ };
|
|
|
if (pluginCfg.debugCapture) {
|
|
if (pluginCfg.debugCapture) {
|
|
|
- console.log("[mem0-auto-capture]", {
|
|
|
|
|
- sessionKey: event.sessionKey,
|
|
|
|
|
- userId,
|
|
|
|
|
- captureTrigger,
|
|
|
|
|
- hasAssistantMessage: !!assistantMessage,
|
|
|
|
|
- messages: captureMessages,
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- console.log("[mem0-auto-capture]", {
|
|
|
|
|
- sessionKey: event.sessionKey,
|
|
|
|
|
- userId,
|
|
|
|
|
- captureTrigger,
|
|
|
|
|
- hasAssistantMessage: !!assistantMessage,
|
|
|
|
|
- messageCount: captureMessages.length,
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ captureDetail.messages = captureMessages;
|
|
|
}
|
|
}
|
|
|
|
|
+ logHook("auto-capture", captureDetail);
|
|
|
await fetch(`${pluginCfg.baseUrl}/memories`, {
|
|
await fetch(`${pluginCfg.baseUrl}/memories`, {
|
|
|
method: "POST",
|
|
method: "POST",
|
|
|
headers: { "Content-Type": "application/json" },
|
|
headers: { "Content-Type": "application/json" },
|