Memory/QMD: handle fallback init failures gracefully

This commit is contained in:
Vignesh Natarajan
2026-02-14 15:41:48 -08:00
parent c4dbcc3444
commit 53a8f474ee
3 changed files with 29 additions and 3 deletions

View File

@@ -49,6 +49,7 @@ Docs: https://docs.openclaw.ai
- Memory/QMD: make QMD result JSON parsing resilient to noisy command output by extracting the first JSON array from noisy `stdout`.
- Memory/QMD: treat prefixed `no results found` marker output as an empty result set in qmd JSON parsing. (#11302) Thanks @blazerui.
- Memory/QMD: make `memory status` read-only by skipping QMD boot update/embed side effects for status-only manager checks.
- Memory/QMD: keep original QMD failures when builtin fallback initialization fails (for example missing embedding API keys), instead of replacing them with fallback init errors.
- Memory/QMD: pass result limits to `search`/`vsearch` commands so QMD can cap results earlier.
- Memory/QMD: avoid reading full markdown files when a `from/lines` window is requested in QMD reads.
- Memory/QMD: skip rewriting unchanged session export markdown files during sync to reduce disk churn.

View File

@@ -209,4 +209,22 @@ describe("getMemorySearchManager caching", () => {
expect(results[0]?.path).toBe("MEMORY.md");
expect(fallbackSearch).toHaveBeenCalledTimes(1);
});
it("keeps original qmd error when fallback manager initialization fails", async () => {
const retryAgentId = "retry-agent-no-fallback-auth";
const cfg = {
memory: { backend: "qmd", qmd: {} },
agents: { list: [{ id: retryAgentId, default: true, workspace: "/tmp/workspace" }] },
} as const;
mockPrimary.search.mockRejectedValueOnce(new Error("qmd query failed"));
mockMemoryIndexGet.mockRejectedValueOnce(new Error("No API key found for provider openai"));
const first = await getMemorySearchManager({ cfg, agentId: retryAgentId });
if (!first.manager) {
throw new Error("manager missing");
}
await expect(first.manager.search("hello")).rejects.toThrow("qmd query failed");
});
});

View File

@@ -191,9 +191,16 @@ class FallbackMemoryManager implements MemorySearchManager {
if (this.fallback) {
return this.fallback;
}
const fallback = await this.deps.fallbackFactory();
if (!fallback) {
log.warn("memory fallback requested but builtin index is unavailable");
let fallback: MemorySearchManager | null;
try {
fallback = await this.deps.fallbackFactory();
if (!fallback) {
log.warn("memory fallback requested but builtin index is unavailable");
return null;
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
log.warn(`memory fallback unavailable: ${message}`);
return null;
}
this.fallback = fallback;