import path from "node:path"; import { describe, expect, it } from "vitest"; import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js"; import type { OpenClawConfig } from "../config/config.js"; import { resolveMemoryBackendConfig } from "./backend-config.js"; describe("resolveMemoryBackendConfig", () => { it("defaults to builtin backend when config missing", () => { const cfg = { agents: { defaults: { workspace: "/tmp/memory-test" } } } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); expect(resolved.backend).toBe("builtin"); expect(resolved.citations).toBe("auto"); expect(resolved.qmd).toBeUndefined(); }); it("resolves qmd backend with default collections", () => { const cfg = { agents: { defaults: { workspace: "/tmp/memory-test" } }, memory: { backend: "qmd", qmd: {}, }, } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); expect(resolved.backend).toBe("qmd"); expect(resolved.qmd?.collections.length).toBeGreaterThanOrEqual(3); expect(resolved.qmd?.command).toBe("qmd"); expect(resolved.qmd?.searchMode).toBe("search"); expect(resolved.qmd?.update.intervalMs).toBeGreaterThan(0); expect(resolved.qmd?.update.waitForBootSync).toBe(false); expect(resolved.qmd?.update.commandTimeoutMs).toBe(30_000); expect(resolved.qmd?.update.updateTimeoutMs).toBe(120_000); expect(resolved.qmd?.update.embedTimeoutMs).toBe(120_000); const names = new Set((resolved.qmd?.collections ?? []).map((collection) => collection.name)); expect(names.has("memory-root-main")).toBe(true); expect(names.has("memory-alt-main")).toBe(true); expect(names.has("memory-dir-main")).toBe(true); }); it("parses quoted qmd command paths", () => { const cfg = { agents: { defaults: { workspace: "/tmp/memory-test" } }, memory: { backend: "qmd", qmd: { command: '"/Applications/QMD Tools/qmd" --flag', }, }, } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); expect(resolved.qmd?.command).toBe("/Applications/QMD Tools/qmd"); }); it("resolves custom paths relative to workspace", () => { const cfg = { agents: { defaults: { workspace: "/workspace/root" }, list: [{ id: "main", workspace: "/workspace/root" }], }, memory: { backend: "qmd", qmd: { paths: [ { path: "notes", name: "custom-notes", pattern: "**/*.md", }, ], }, }, } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); const custom = resolved.qmd?.collections.find((c) => c.name.startsWith("custom-notes")); expect(custom).toBeDefined(); const workspaceRoot = resolveAgentWorkspaceDir(cfg, "main"); expect(custom?.path).toBe(path.resolve(workspaceRoot, "notes")); }); it("scopes qmd collection names per agent", () => { const cfg = { agents: { defaults: { workspace: "/workspace/root" }, list: [ { id: "main", default: true, workspace: "/workspace/root" }, { id: "dev", workspace: "/workspace/dev" }, ], }, memory: { backend: "qmd", qmd: { includeDefaultMemory: true, paths: [{ path: "notes", name: "workspace", pattern: "**/*.md" }], }, }, } as OpenClawConfig; const mainResolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); const devResolved = resolveMemoryBackendConfig({ cfg, agentId: "dev" }); const mainNames = new Set( (mainResolved.qmd?.collections ?? []).map((collection) => collection.name), ); const devNames = new Set( (devResolved.qmd?.collections ?? []).map((collection) => collection.name), ); expect(mainNames.has("memory-dir-main")).toBe(true); expect(devNames.has("memory-dir-dev")).toBe(true); expect(mainNames.has("workspace-main")).toBe(true); expect(devNames.has("workspace-dev")).toBe(true); }); it("resolves qmd update timeout overrides", () => { const cfg = { agents: { defaults: { workspace: "/tmp/memory-test" } }, memory: { backend: "qmd", qmd: { update: { waitForBootSync: true, commandTimeoutMs: 12_000, updateTimeoutMs: 480_000, embedTimeoutMs: 360_000, }, }, }, } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); expect(resolved.qmd?.update.waitForBootSync).toBe(true); expect(resolved.qmd?.update.commandTimeoutMs).toBe(12_000); expect(resolved.qmd?.update.updateTimeoutMs).toBe(480_000); expect(resolved.qmd?.update.embedTimeoutMs).toBe(360_000); }); it("resolves qmd search mode override", () => { const cfg = { agents: { defaults: { workspace: "/tmp/memory-test" } }, memory: { backend: "qmd", qmd: { searchMode: "vsearch", }, }, } as OpenClawConfig; const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" }); expect(resolved.qmd?.searchMode).toBe("vsearch"); }); });