mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-16 19:51:11 +00:00
180 lines
5.8 KiB
TypeScript
180 lines
5.8 KiB
TypeScript
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)",
|
|
);
|
|
});
|
|
});
|