From b45bb6801cc517f4f7beac6d6e80221362c41c23 Mon Sep 17 00:00:00 2001 From: Thorfinn <136994453+miloudbelarebia@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:21:27 +0100 Subject: [PATCH] fix(doctor): skip embedding provider check when QMD backend is active (openclaw#17295) thanks @miloudbelarebia Verified: - pnpm build - pnpm check (fails on baseline formatting drift in files identical to origin/main) - pnpm test:macmini Co-authored-by: miloudbelarebia <52387093+miloudbelarebia@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + src/commands/doctor-memory-search.test.ts | 23 +++++++++++++++++++++++ src/commands/doctor-memory-search.ts | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 839679eb49..752415c2d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Commands/Doctor: skip embedding-provider warnings when `memory.backend` is `qmd`, because QMD manages embeddings internally and does not require `memorySearch` providers. (#17263) Thanks @miloudbelarebia. - Security/Webhooks: harden Feishu and Zalo webhook ingress with webhook-mode token preconditions, loopback-default Feishu bind host, JSON content-type enforcement, per-path rate limiting, replay dedupe for Zalo events, constant-time Zalo secret comparison, and anomaly status counters. - Security/Plugins: add explicit `plugins.runtime.allowLegacyExec` opt-in to re-enable deprecated `runtime.system.runCommandWithTimeout` for legacy modules while keeping runtime command execution disabled by default. (#20874) Thanks @mbelinky. - Gateway/WebChat: block `sessions.patch` and `sessions.delete` for WebChat clients so session-store mutations stay restricted to non-WebChat operator flows. Thanks @allsmog for reporting. diff --git a/src/commands/doctor-memory-search.test.ts b/src/commands/doctor-memory-search.test.ts index 10c5813206..4a46aad28b 100644 --- a/src/commands/doctor-memory-search.test.ts +++ b/src/commands/doctor-memory-search.test.ts @@ -7,6 +7,7 @@ const resolveDefaultAgentId = vi.hoisted(() => vi.fn(() => "agent-default")); const resolveAgentDir = vi.hoisted(() => vi.fn(() => "/tmp/agent-default")); const resolveMemorySearchConfig = vi.hoisted(() => vi.fn()); const resolveApiKeyForProvider = vi.hoisted(() => vi.fn()); +const resolveMemoryBackendConfig = vi.hoisted(() => vi.fn()); vi.mock("../terminal/note.js", () => ({ note, @@ -25,6 +26,10 @@ vi.mock("../agents/model-auth.js", () => ({ resolveApiKeyForProvider, })); +vi.mock("../memory/backend-config.js", () => ({ + resolveMemoryBackendConfig, +})); + import { noteMemorySearchHealth } from "./doctor-memory-search.js"; import { detectLegacyWorkspaceDirs } from "./doctor-workspace.js"; @@ -50,6 +55,24 @@ describe("noteMemorySearchHealth", () => { resolveAgentDir.mockClear(); resolveMemorySearchConfig.mockReset(); resolveApiKeyForProvider.mockReset(); + resolveMemoryBackendConfig.mockReset(); + resolveMemoryBackendConfig.mockReturnValue({ backend: "builtin", citations: "auto" }); + }); + + it("does not warn when QMD backend is active", async () => { + resolveMemoryBackendConfig.mockReturnValue({ + backend: "qmd", + citations: "auto", + }); + resolveMemorySearchConfig.mockReturnValue({ + provider: "auto", + local: {}, + remote: {}, + }); + + await noteMemorySearchHealth(cfg); + + expect(note).not.toHaveBeenCalled(); }); it("does not warn when remote apiKey is configured for explicit provider", async () => { diff --git a/src/commands/doctor-memory-search.ts b/src/commands/doctor-memory-search.ts index c06876b234..1c6319f908 100644 --- a/src/commands/doctor-memory-search.ts +++ b/src/commands/doctor-memory-search.ts @@ -4,6 +4,7 @@ import { resolveMemorySearchConfig } from "../agents/memory-search.js"; import { resolveApiKeyForProvider } from "../agents/model-auth.js"; import { formatCliCommand } from "../cli/command-format.js"; import type { OpenClawConfig } from "../config/config.js"; +import { resolveMemoryBackendConfig } from "../memory/backend-config.js"; import { note } from "../terminal/note.js"; import { resolveUserPath } from "../utils.js"; @@ -22,6 +23,13 @@ export async function noteMemorySearchHealth(cfg: OpenClawConfig): Promise return; } + // QMD backend handles embeddings internally (e.g. embeddinggemma) — no + // separate embedding provider is needed. Skip the provider check entirely. + const backendConfig = resolveMemoryBackendConfig({ cfg, agentId }); + if (backendConfig.backend === "qmd") { + return; + } + // If a specific provider is configured (not "auto"), check only that one. if (resolved.provider !== "auto") { if (resolved.provider === "local") {