فهرست منبع

Fix auto-capture pairing and cleanup

Lukas Goldschmidt 1 ماه پیش
والد
کامیت
a219af265d
1فایلهای تغییر یافته به همراه97 افزوده شده و 6 حذف شده
  1. 97 6
      hook/handler.ts

+ 97 - 6
hook/handler.ts

@@ -3,6 +3,8 @@ import os from "os";
 import path from "path";
 
 const CHAT_LOG_FILE = "/tmp/openclaw-chat.log";
+const SESSIONS_INDEX_PATH =
+  "/home/lucky/.openclaw/agents/main/sessions/sessions.json";
 
 // ---------------------------------------------------------------------------
 // Config — openclaw does NOT inject cfg into hook events.
@@ -179,7 +181,82 @@ function getAudioPath(context: any): string | undefined {
   return undefined;
 }
 
-function readLastAssistantMessage(sessionKey?: string): string | undefined {
+function cleanAssistantText(text: string): string {
+  return text.replace(/^\s*\[\[reply_to_current\]\]\s*/i, "").trim();
+}
+
+function resolveSessionFileFromIndex(sessionKey?: string): string | undefined {
+  if (!sessionKey) return undefined;
+  try {
+    if (!fs.existsSync(SESSIONS_INDEX_PATH)) return undefined;
+    const data = fs.readFileSync(SESSIONS_INDEX_PATH, "utf8");
+    const parsed = JSON.parse(data);
+    const entry = parsed?.[sessionKey];
+    if (entry?.sessionFile) {
+      return entry.sessionFile as string;
+    }
+  } catch {
+    return undefined;
+  }
+  return undefined;
+}
+
+function readLastAssistantFromSessionFile(
+  sessionFile: string,
+  beforeTimestampMs?: number
+): string | undefined {
+  try {
+    if (!fs.existsSync(sessionFile)) return undefined;
+    const data = fs.readFileSync(sessionFile, "utf8");
+    const lines = data.split(/\r?\n/).filter(Boolean);
+    for (let i = lines.length - 1; i >= 0; i--) {
+      try {
+        const entry = JSON.parse(lines[i]);
+        if (entry?.type !== "message") continue;
+        if (entry?.message?.role !== "assistant") continue;
+        if (beforeTimestampMs && entry?.timestamp) {
+          const ts = Date.parse(entry.timestamp);
+          if (!Number.isNaN(ts) && ts >= beforeTimestampMs) {
+            continue;
+          }
+        }
+        const content = entry.message?.content;
+        let text = "";
+        if (typeof content === "string") text = content;
+        else if (Array.isArray(content)) {
+          for (const block of content) {
+            if (typeof block === "string") text += block;
+            else if (typeof block?.text === "string") text += block.text;
+            else if (typeof block?.value === "string") text += block.value;
+          }
+        }
+        text = cleanAssistantText(text.trim());
+        if (text && text !== "HEARTBEAT_OK") {
+          return text;
+        }
+      } catch {
+        // skip malformed lines
+      }
+    }
+  } catch {
+    return undefined;
+  }
+  return undefined;
+}
+
+function readLastAssistantMessage(
+  sessionKey?: string,
+  beforeTimestampMs?: number
+): string | undefined {
+  const sessionFile = resolveSessionFileFromIndex(sessionKey);
+  if (sessionFile) {
+    const fromSession = readLastAssistantFromSessionFile(
+      sessionFile,
+      beforeTimestampMs
+    );
+    if (fromSession) return fromSession;
+  }
+
   try {
     if (!fs.existsSync(CHAT_LOG_FILE)) return undefined;
     const payload = fs.readFileSync(CHAT_LOG_FILE, "utf8");
@@ -201,8 +278,12 @@ function readLastAssistantMessage(sessionKey?: string): string | undefined {
           continue;
         }
         const assistantText = candidate?.content;
-        if (typeof assistantText === "string" && assistantText.trim()) {
-          return assistantText.trim();
+        if (
+          typeof assistantText === "string" &&
+          assistantText.trim() &&
+          assistantText.trim() !== "HEARTBEAT_OK"
+        ) {
+          return cleanAssistantText(assistantText.trim());
         }
       } catch {
         // skip malformed lines
@@ -219,12 +300,16 @@ function readLastAssistantMessage(sessionKey?: string): string | undefined {
             continue;
           }
           const assistantText = candidate?.content;
-          if (typeof assistantText === "string" && assistantText.trim()) {
+          if (
+            typeof assistantText === "string" &&
+            assistantText.trim() &&
+            assistantText.trim() !== "HEARTBEAT_OK"
+          ) {
             console.warn(
               "[mem0-auto-capture] assistant lookup fallback to global latest",
               { requestedSessionKey: sessionKey, logSessionKey: entry?.sessionKey }
             );
-            return assistantText.trim();
+            return cleanAssistantText(assistantText.trim());
           }
         } catch {
           // skip malformed lines
@@ -553,7 +638,13 @@ export default async function handler(event: HookEvent) {
     }
     if (!shouldCapture) return;
 
-    const assistantMessage = readLastAssistantMessage(event.sessionKey);
+    const eventTs = event.timestamp
+      ? new Date(event.timestamp as any).getTime()
+      : Date.now();
+    const assistantMessage = readLastAssistantMessage(
+      event.sessionKey,
+      eventTs
+    );
     const userCaptureText = recent.join("\n");
 
     const captureMessages: Array<{ role: "user" | "assistant"; content: string }> = [