mirror of https://github.com/openclaw/openclaw.git
fix(memory): stabilize qmd collection scoping
This commit is contained in:
parent
9c25544e6c
commit
910134b702
|
|
@ -267,7 +267,7 @@ describe("QmdMemoryManager slugified path resolution", () => {
|
|||
"stdout",
|
||||
JSON.stringify([
|
||||
{
|
||||
file: "qmd://vault-main/topics/sub-category/topic-name.md",
|
||||
file: "qmd://vault/topics/sub-category/topic-name.md",
|
||||
score: 0.81,
|
||||
snippet: "@@ -1,1\nvault memory",
|
||||
},
|
||||
|
|
@ -281,7 +281,7 @@ describe("QmdMemoryManager slugified path resolution", () => {
|
|||
const { manager } = await createManager({ cfg });
|
||||
installIndexedPathStub({
|
||||
manager,
|
||||
collection: "vault-main",
|
||||
collection: "vault",
|
||||
normalizedPath: "topics/sub-category/topic-name.md",
|
||||
actualPath: actualRelative,
|
||||
});
|
||||
|
|
@ -291,7 +291,7 @@ describe("QmdMemoryManager slugified path resolution", () => {
|
|||
});
|
||||
expect(results).toEqual([
|
||||
{
|
||||
path: `qmd/vault-main/${actualRelative}`,
|
||||
path: `qmd/vault/${actualRelative}`,
|
||||
startLine: 1,
|
||||
endLine: 1,
|
||||
score: 0.81,
|
||||
|
|
@ -301,7 +301,7 @@ describe("QmdMemoryManager slugified path resolution", () => {
|
|||
]);
|
||||
|
||||
await expect(manager.readFile({ relPath: results[0]!.path })).resolves.toEqual({
|
||||
path: `qmd/vault-main/${actualRelative}`,
|
||||
path: `qmd/vault/${actualRelative}`,
|
||||
text: "vault memory",
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1742,7 +1742,7 @@ describe("QmdMemoryManager", () => {
|
|||
.filter((args: string[]) => args[0] === "search");
|
||||
expect(searchCalls).toEqual([
|
||||
["search", "test", "--json", "-n", String(maxResults), "-c", "workspace-main"],
|
||||
["search", "test", "--json", "-n", String(maxResults), "-c", "notes"],
|
||||
["search", "test", "--json", "-n", String(maxResults), "-c", "notes-main"],
|
||||
]);
|
||||
await manager.close();
|
||||
});
|
||||
|
|
@ -1828,7 +1828,7 @@ describe("QmdMemoryManager", () => {
|
|||
.filter((args: string[]) => args[0] === "query");
|
||||
expect(queryCalls).toEqual([
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "workspace-main"],
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "notes"],
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "notes-main"],
|
||||
]);
|
||||
await manager.close();
|
||||
});
|
||||
|
|
@ -1880,7 +1880,7 @@ describe("QmdMemoryManager", () => {
|
|||
expect(searchAndQueryCalls).toEqual([
|
||||
["search", "test", "--json", "-n", String(maxResults), "-c", "workspace-main"],
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "workspace-main"],
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "notes"],
|
||||
["query", "test", "--json", "-n", String(maxResults), "-c", "notes-main"],
|
||||
]);
|
||||
await manager.close();
|
||||
});
|
||||
|
|
@ -2217,7 +2217,7 @@ describe("QmdMemoryManager", () => {
|
|||
await manager.search("hello", { sessionKey: "agent:main:slack:dm:u123" });
|
||||
|
||||
expect(selectors).toEqual(["qmd.hybrid_search", "qmd.hybrid_search"]);
|
||||
expect(collections).toEqual(["workspace-a", "workspace-b"]);
|
||||
expect(collections).toEqual(["workspace-a-main", "workspace-b-main"]);
|
||||
|
||||
await manager.close();
|
||||
});
|
||||
|
|
@ -3326,7 +3326,7 @@ describe("QmdMemoryManager", () => {
|
|||
);
|
||||
return child;
|
||||
}
|
||||
if (args[0] === "search" && args.includes("notes")) {
|
||||
if (args[0] === "search" && args.includes("notes-main")) {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
emitAndClose(child, "stdout", "[]");
|
||||
return child;
|
||||
|
|
@ -3542,14 +3542,14 @@ describe("QmdMemoryManager", () => {
|
|||
);
|
||||
return child;
|
||||
}
|
||||
if (args[0] === "search" && args.includes("notes")) {
|
||||
if (args[0] === "search" && args.includes("notes-main")) {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
emitAndClose(
|
||||
child,
|
||||
"stdout",
|
||||
JSON.stringify([
|
||||
{
|
||||
file: "qmd://notes/guide.md",
|
||||
file: "qmd://notes-main/guide.md",
|
||||
score: 0.7,
|
||||
snippet: "@@ -1,1\nnotes guide",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -173,6 +173,39 @@ describe("resolveMemoryBackendConfig", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("keeps unresolved child paths under a symlinked workspace agent-scoped", async () => {
|
||||
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qmd-backend-config-"));
|
||||
const realRootDir = path.join(tmpRoot, "real-root");
|
||||
const aliasRootDir = path.join(tmpRoot, "alias-root");
|
||||
const workspaceDir = path.join(realRootDir, "workspace");
|
||||
const workspaceAliasDir = path.join(aliasRootDir, "workspace");
|
||||
try {
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
await fs.symlink(realRootDir, aliasRootDir);
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: { workspace: workspaceDir },
|
||||
list: [{ id: "main", default: true, workspace: workspaceDir }],
|
||||
},
|
||||
memory: {
|
||||
backend: "qmd",
|
||||
qmd: {
|
||||
includeDefaultMemory: false,
|
||||
paths: [
|
||||
{ path: path.join(workspaceAliasDir, "notes"), name: "notes", pattern: "**/*.md" },
|
||||
],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const resolved = resolveMemoryBackendConfig({ cfg, agentId: "main" });
|
||||
const names = new Set((resolved.qmd?.collections ?? []).map((collection) => collection.name));
|
||||
expect(names.has("notes-main")).toBe(true);
|
||||
expect(names.has("notes")).toBe(false);
|
||||
} finally {
|
||||
await fs.rm(tmpRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolves qmd update timeout overrides", () => {
|
||||
const cfg = {
|
||||
agents: { defaults: { workspace: "/tmp/memory-test" } },
|
||||
|
|
|
|||
|
|
@ -118,10 +118,20 @@ function scopeCollectionBase(base: string, agentId: string): string {
|
|||
|
||||
function canonicalizePathForContainment(rawPath: string): string {
|
||||
const resolved = path.resolve(rawPath);
|
||||
try {
|
||||
return path.normalize(fs.realpathSync.native(resolved));
|
||||
} catch {
|
||||
return path.normalize(resolved);
|
||||
let current = resolved;
|
||||
const suffix: string[] = [];
|
||||
while (true) {
|
||||
try {
|
||||
const canonical = path.normalize(fs.realpathSync.native(current));
|
||||
return path.normalize(path.join(canonical, ...suffix));
|
||||
} catch {
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) {
|
||||
return path.normalize(resolved);
|
||||
}
|
||||
suffix.unshift(path.basename(current));
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue