import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { resolveMemoryWikiConfig } from "./config.js"; import { buildWikiPromptSection, createWikiPromptSectionBuilder } from "./prompt-section.js"; let suiteRoot = ""; beforeAll(async () => { suiteRoot = await fs.mkdtemp(path.join(os.tmpdir(), "memory-wiki-prompt-suite-")); }); afterAll(async () => { if (suiteRoot) { await fs.rm(suiteRoot, { recursive: true, force: true }); } }); describe("buildWikiPromptSection", () => { it("prefers shared memory corpus guidance when memory tools are available", () => { const lines = buildWikiPromptSection({ availableTools: new Set(["memory_search", "memory_get", "wiki_search", "wiki_get"]), }); expect(lines.join("\n")).toContain("`memory_search` with `corpus=all`"); expect(lines.join("\n")).toContain("`memory_get` with `corpus=wiki` or `corpus=all`"); expect(lines.join("\n")).toContain("wiki-specific ranking or provenance details"); }); it("stays empty when no wiki or memory-adjacent tools are registered", () => { expect(buildWikiPromptSection({ availableTools: new Set(["web_search"]) })).toEqual([]); }); it("can append a compact compiled digest snapshot when enabled", async () => { const rootDir = path.join(suiteRoot, "digest-enabled"); await fs.mkdir(path.join(rootDir, ".openclaw-wiki", "cache"), { recursive: true }); await fs.writeFile( path.join(rootDir, ".openclaw-wiki", "cache", "agent-digest.json"), JSON.stringify( { claimCount: 8, contradictionClusters: [{ key: "claim.alpha.db" }], pages: [ { title: "Alpha", kind: "entity", claimCount: 3, questions: ["Still active?"], contradictions: ["Conflicts with source.beta"], topClaims: [ { text: "Alpha uses PostgreSQL for production writes.", status: "supported", confidence: 0.91, freshnessLevel: "fresh", }, ], }, ], }, null, 2, ), "utf8", ); const builder = createWikiPromptSectionBuilder( resolveMemoryWikiConfig({ vault: { path: rootDir }, context: { includeCompiledDigestPrompt: true }, }), ); const lines = builder({ availableTools: new Set(["web_search"]) }); expect(lines.join("\n")).toContain("## Compiled Wiki Snapshot"); expect(lines.join("\n")).toContain( "Alpha: entity, 3 claims, 1 open questions, 1 contradiction notes", ); expect(lines.join("\n")).toContain("Alpha uses PostgreSQL for production writes."); }); it("keeps the digest snapshot disabled by default", async () => { const rootDir = path.join(suiteRoot, "digest-disabled"); await fs.mkdir(path.join(rootDir, ".openclaw-wiki", "cache"), { recursive: true }); await fs.writeFile( path.join(rootDir, ".openclaw-wiki", "cache", "agent-digest.json"), JSON.stringify({ claimCount: 1, pages: [{ title: "Alpha", kind: "entity", claimCount: 1, topClaims: [] }], }), "utf8", ); const builder = createWikiPromptSectionBuilder( resolveMemoryWikiConfig({ vault: { path: rootDir }, }), ); expect(builder({ availableTools: new Set(["web_search"]) })).toEqual([]); }); it("stabilizes digest prompt ordering for prompt-cache-friendly output", async () => { const rootDir = path.join(suiteRoot, "digest-stable"); const digestPath = path.join(rootDir, ".openclaw-wiki", "cache", "agent-digest.json"); await fs.mkdir(path.dirname(digestPath), { recursive: true }); const builder = createWikiPromptSectionBuilder( resolveMemoryWikiConfig({ vault: { path: rootDir }, context: { includeCompiledDigestPrompt: true }, }), ); const firstDigest = { claimCount: 6, contradictionClusters: [{ key: "claim.alpha.db" }], pages: [ { title: "Zulu", kind: "concept", claimCount: 2, questions: [], contradictions: [], topClaims: [ { text: "Zulu fallback note.", confidence: 0.3, freshnessLevel: "stale", }, ], }, { title: "Alpha", kind: "entity", claimCount: 4, questions: ["Still active?"], contradictions: ["Conflicts with source.beta"], topClaims: [ { text: "Alpha was renamed in 2026.", confidence: 0.42, freshnessLevel: "aging", }, { text: "Alpha uses PostgreSQL for production writes.", confidence: 0.91, freshnessLevel: "fresh", }, ], }, ], }; const secondDigest = { ...firstDigest, pages: [ { ...firstDigest.pages[1], topClaims: firstDigest.pages[1].topClaims.toReversed(), }, firstDigest.pages[0], ], }; await fs.writeFile(digestPath, JSON.stringify(firstDigest, null, 2), "utf8"); const firstLines = builder({ availableTools: new Set(["web_search"]) }); await fs.writeFile(digestPath, JSON.stringify(secondDigest, null, 2), "utf8"); const secondLines = builder({ availableTools: new Set(["web_search"]) }); expect(firstLines).toEqual(secondLines); expect(firstLines.join("\n")).toContain( "Alpha uses PostgreSQL for production writes. (confidence 0.91, freshness fresh)", ); expect(firstLines.join("\n")).toContain( "Alpha was renamed in 2026. (confidence 0.42, freshness aging)", ); }); });