From bdb75bd8c78854338236ad08d2f70b783db1cd3a Mon Sep 17 00:00:00 2001 From: SimbaKingjoe <126222269+SimbaKingjoe@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:20:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(active-memory):=20skip=20payload-less=20mem?= =?UTF-8?q?ory=5Fsearch=20toolResults=20in=20tr=E2=80=A6=20(openclaw#68773?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified: - pnpm install --frozen-lockfile - pnpm test extensions/active-memory/index.test.ts - pnpm exec oxfmt --check --threads=1 extensions/active-memory/index.ts extensions/active-memory/index.test.ts CHANGELOG.md - git diff --check origin/main..HEAD - gh pr checks 68773 --repo openclaw/openclaw --required Co-authored-by: SimbaKingjoe <126222269+SimbaKingjoe@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + extensions/active-memory/index.test.ts | 48 ++++++++++++++++++++++++++ extensions/active-memory/index.ts | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adfa721810a..4389cb82c07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai - fix(agents): canonicalize provider aliases in byProvider tool policy lookup [AI]. (#72917) Thanks @pgondhi987. - fix(security): block npm_execpath injection from workspace .env [AI-assisted]. (#73262) Thanks @pgondhi987. - Tools/web_fetch: decode response bodies from raw bytes using declared HTTP, XML, or HTML meta charsets before extraction, so Shift_JIS and other legacy-charset pages no longer return mojibake. Fixes #72916. Thanks @amknight. +- Active Memory: skip payload-less `memory_search` transcript tool results when building debug telemetry, so newer empty entries no longer hide the latest useful debug payload. (#68773) Thanks @SimbaKingjoe. - Channels/Discord: bound message read/search REST calls, route those actions through Gateway execution, and fall back to `CommandTargetSessionKey` for inbound hook session keys so Discord reads do not hang and hooks still fire when `SessionKey` is empty. Fixes #73431. (#73521) Thanks @amknight. - Plugins/media: auto-enable provider plugins referenced by `agents.defaults.imageGenerationModel`, `videoGenerationModel`, and `musicGenerationModel` primary/fallback refs, so configured Google and MiniMax media providers do not stay disabled behind a restrictive plugin allowlist. Thanks @vincentkoc. - Memory-core/dreaming: retry managed dreaming cron registration after startup when the cron service is not reachable yet, so the scheduled Memory Dreaming Promotion sweep recovers without waiting for heartbeat traffic. Fixes #72841. Thanks @amknight. diff --git a/extensions/active-memory/index.test.ts b/extensions/active-memory/index.test.ts index 7ec237b668d..424520be5d9 100644 --- a/extensions/active-memory/index.test.ts +++ b/extensions/active-memory/index.test.ts @@ -1101,6 +1101,54 @@ describe("active-memory plugin", () => { ]); }); + it("skips newest memory_search toolResult entries that carry no debug payload", async () => { + const sessionKey = "agent:main:transcript-debug"; + hoisted.sessionStore[sessionKey] = { sessionId: "s-main", updatedAt: 0 }; + + runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => { + const lines = [ + JSON.stringify({ + message: { + role: "toolResult", + toolName: "memory_search", + details: { debug: { backend: "qmd", hits: 3 } }, + }, + }), + JSON.stringify({ + message: { + role: "toolResult", + toolName: "memory_search", + details: {}, + }, + }), + ]; + await fs.writeFile(params.sessionFile, `${lines.join("\n")}\n`, "utf8"); + return { payloads: [{ text: "wings are fine." }] }; + }); + + await hooks.before_prompt_build( + { prompt: "debug transcript bug", messages: [] }, + { agentId: "main", trigger: "user", sessionKey, messageProvider: "webchat" }, + ); + + const updater = hoisted.updateSessionStore.mock.calls.at(-1)?.[1] as + | ((store: Record>) => void) + | undefined; + const store = { + [sessionKey]: { sessionId: "s-main", updatedAt: 0 }, + } as Record>; + updater?.(store); + const entries = store[sessionKey]?.pluginDebugEntries as + | { pluginId: string; lines: string[] }[] + | undefined; + const debugLine = entries?.[0]?.lines.find((line) => + line.startsWith("🔎 Active Memory Debug:"), + ); + expect(debugLine).toBeDefined(); + expect(debugLine).toContain("backend=qmd"); + expect(debugLine).toContain("hits=3"); + }); + it("replaces stale structured active-memory lines on a later empty run", async () => { const sessionKey = "agent:main:stale-active-memory-lines"; hoisted.sessionStore[sessionKey] = { diff --git a/extensions/active-memory/index.ts b/extensions/active-memory/index.ts index 0677dc14724..a03c8f29910 100644 --- a/extensions/active-memory/index.ts +++ b/extensions/active-memory/index.ts @@ -1234,7 +1234,7 @@ async function readActiveMemorySearchDebug( continue; } const details = asRecord(message.details); - const debug = asRecord(details?.debug) ?? {}; + const debug = asRecord(details?.debug); const warning = normalizeOptionalString(details?.warning); const action = normalizeOptionalString(details?.action); const error = normalizeOptionalString(details?.error);