From 1bc97aee4ecbef0c6560099ff9afa93afde6cdf0 Mon Sep 17 00:00:00 2001 From: "clawsweeper[bot]" <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Sun, 3 May 2026 17:54:39 +0100 Subject: [PATCH] fix(doctor): suppress memory plugin false alarm Fixes #76792. - Trust a checked-ready gateway memory probe when CLI-local memory runtime resolution is unavailable. - Keep the no-active-plugin warning for skipped, unavailable, or not-ready gateway probes. - Add regression coverage for ready, skipped, and not-ready probe cases. Thanks @som-686. --- CHANGELOG.md | 1 + src/commands/doctor-memory-search.test.ts | 57 +++++++++++++++++++++++ src/commands/doctor-memory-search.ts | 3 ++ 3 files changed, 61 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbbd683b44b..ae7a02acec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai - Google Meet: route stateful CLI session commands through the gateway-owned runtime so joined realtime sessions survive after the starting CLI process exits. Fixes #76344. Thanks @coltonharris-wq. - Memory/status: split builtin sqlite-vec store readiness from embedding-provider readiness in `memory status --deep` and `openclaw status`, so local vector-store failures no longer look like provider failures and provider failures no longer hide a healthy local vector store. +- CLI/doctor: trust a ready gateway memory probe when CLI-side active memory backend resolution is unavailable, preventing false "No active memory plugin is registered" warnings for healthy runtime setups. Fixes #76792. Thanks @som-686. - Memory/status: keep plain `openclaw memory status` and `openclaw memory status --json` on the cheap read-only path by reserving vector and embedding provider probes for `--deep` or `--index`. Fixes #76769. Thanks @daruire. - Telegram: suppress stale same-session replies when a newer accepted message arrives before an older in-flight Telegram dispatch finalizes. Fixes #76642. Thanks @chinar-amrutkar. - Control UI/Sessions: avoid full `sessions.list` reloads for chat-turn `sessions.changed` payloads, so large session stores no longer add multi-second delays while chat responses are being delivered. (#76676) Thanks @VACInc. diff --git a/src/commands/doctor-memory-search.test.ts b/src/commands/doctor-memory-search.test.ts index 93b7215342a..6fe75875cc3 100644 --- a/src/commands/doctor-memory-search.test.ts +++ b/src/commands/doctor-memory-search.test.ts @@ -276,6 +276,63 @@ describe("noteMemorySearchHealth", () => { ); }); + it("does not warn when CLI backend resolution is missing but gateway memory probe is ready", async () => { + resolveActiveMemoryBackendConfig.mockReturnValue(null); + resolveMemorySearchConfig.mockReturnValue({ + provider: "auto", + local: {}, + remote: {}, + }); + + await noteMemorySearchHealth(cfg, { + gatewayMemoryProbe: { checked: true, ready: true }, + }); + + expect(resolveApiKeyForProvider).not.toHaveBeenCalled(); + expect(checkQmdBinaryAvailability).not.toHaveBeenCalled(); + expect(note).not.toHaveBeenCalled(); + }); + + it("warns when CLI backend resolution is missing and gateway memory probe was skipped", async () => { + resolveActiveMemoryBackendConfig.mockReturnValue(null); + resolveMemorySearchConfig.mockReturnValue({ + provider: "auto", + local: {}, + remote: {}, + }); + + await noteMemorySearchHealth(cfg, { + gatewayMemoryProbe: { checked: false, ready: false, skipped: true }, + }); + + expect(resolveApiKeyForProvider).not.toHaveBeenCalled(); + expect(checkQmdBinaryAvailability).not.toHaveBeenCalled(); + expect(note).toHaveBeenCalledTimes(1); + expect(String(note.mock.calls[0]?.[0] ?? "")).toContain( + "No active memory plugin is registered", + ); + }); + + it("warns when CLI backend resolution is missing and gateway memory probe is not ready", async () => { + resolveActiveMemoryBackendConfig.mockReturnValue(null); + resolveMemorySearchConfig.mockReturnValue({ + provider: "auto", + local: {}, + remote: {}, + }); + + await noteMemorySearchHealth(cfg, { + gatewayMemoryProbe: { checked: true, ready: false, error: "memory search unavailable" }, + }); + + expect(resolveApiKeyForProvider).not.toHaveBeenCalled(); + expect(checkQmdBinaryAvailability).not.toHaveBeenCalled(); + expect(note).toHaveBeenCalledTimes(1); + expect(String(note.mock.calls[0]?.[0] ?? "")).toContain( + "No active memory plugin is registered", + ); + }); + it("does not warn when QMD backend is active", async () => { const qmdCfg = { memory: { backend: "qmd", qmd: { command: "qmd" } } } as OpenClawConfig; resolveMemorySearchConfig.mockReturnValue({ diff --git a/src/commands/doctor-memory-search.ts b/src/commands/doctor-memory-search.ts index 490ac2f31ec..4cccacdc453 100644 --- a/src/commands/doctor-memory-search.ts +++ b/src/commands/doctor-memory-search.ts @@ -336,6 +336,9 @@ export async function noteMemorySearchHealth( // separate embedding provider is needed. Skip the provider check entirely. const backendConfig = resolveActiveMemoryBackendConfig({ cfg, agentId }); if (!backendConfig) { + if (opts?.gatewayMemoryProbe?.checked && opts.gatewayMemoryProbe.ready) { + return; + } note("No active memory plugin is registered for the current config.", "Memory search"); return; }