mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
fix(memory): rebind qmd collections on pattern drift (#57438)
This commit is contained in:
@@ -49,6 +49,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/MCP: reuse bundled MCP runtimes across turns in the same session, while recreating them when MCP config changes and disposing stale runtimes cleanly on session rollover. (#55090) Thanks @allan0509.
|
||||
- Memory/QMD: honor `memory.qmd.update.embedInterval` even when regular QMD update cadence is disabled or slower by arming a dedicated embed-cadence maintenance timer, while avoiding redundant timers when regular updates are already frequent enough. (#37326) Thanks @barronlroth.
|
||||
- Memory/QMD: add `memory.qmd.searchTool` as an exact mcporter tool override, so custom QMD MCP tools such as `hybrid_search` can be used without weakening the validated `searchMode` config surface. (#27801) Thanks @keramblock.
|
||||
- Memory/QMD: rebind collections when QMD reports a changed pattern but omits path metadata, so config pattern changes stop being silently ignored on restart. (#49897) Thanks @Madruru.
|
||||
- Agents/memory flush: keep daily memory flush files append-only during embedded attempts so compaction writes do not overwrite earlier notes. (#53725) Thanks @HPluseven.
|
||||
- Web UI/markdown: stop bare auto-links from swallowing adjacent CJK text while preserving valid mixed-script path and query characters in rendered links. (#48410) Thanks @jnuyao.
|
||||
- BlueBubbles/iMessage: coalesce URL-only inbound messages with their link-preview balloon again so sharing a bare link no longer drops the URL from agent context. Thanks @vincentkoc.
|
||||
|
||||
@@ -610,6 +610,55 @@ describe("QmdMemoryManager", () => {
|
||||
expect(addCalls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("rebinds collection when qmd text output exposes a changed pattern without a path", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
memory: {
|
||||
backend: "qmd",
|
||||
qmd: {
|
||||
includeDefaultMemory: false,
|
||||
update: { interval: "0s", debounceMs: 60_000, onBoot: false },
|
||||
paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
spawnMock.mockImplementation((_cmd: string, args: string[]) => {
|
||||
if (args[0] === "collection" && args[1] === "list") {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
emitAndClose(
|
||||
child,
|
||||
"stdout",
|
||||
["workspace-main (qmd://workspace-main/)", " Pattern: *.txt", " Files: 17"].join(
|
||||
"\n",
|
||||
),
|
||||
);
|
||||
return child;
|
||||
}
|
||||
return createMockChild();
|
||||
});
|
||||
|
||||
const { manager } = await createManager({ mode: "full" });
|
||||
await manager.close();
|
||||
|
||||
const commands = spawnMock.mock.calls.map((call: unknown[]) => call[1] as string[]);
|
||||
const removeCalls = commands.filter(
|
||||
(args) => args[0] === "collection" && args[1] === "remove" && args[2] === "workspace-main",
|
||||
);
|
||||
expect(removeCalls).toHaveLength(1);
|
||||
|
||||
const addCall = commands.find((args) => {
|
||||
if (args[0] !== "collection" || args[1] !== "add") {
|
||||
return false;
|
||||
}
|
||||
const nameIdx = args.indexOf("--name");
|
||||
return nameIdx >= 0 && args[nameIdx + 1] === "workspace-main";
|
||||
});
|
||||
expect(addCall).toBeDefined();
|
||||
expect(addCall?.[2]).toBe(workspaceDir);
|
||||
expect(addCall).toContain("**/*.md");
|
||||
});
|
||||
|
||||
it("migrates unscoped legacy collections before adding scoped names", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
|
||||
@@ -734,18 +734,19 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
}
|
||||
|
||||
private shouldRebindCollection(collection: ManagedCollection, listed: ListedCollection): boolean {
|
||||
if (typeof listed.pattern === "string" && listed.pattern !== collection.pattern) {
|
||||
return true;
|
||||
}
|
||||
if (!listed.path) {
|
||||
// Older qmd versions may only return names from `collection list --json`.
|
||||
// Do not perform destructive rebinds when metadata is incomplete: remove+add
|
||||
// can permanently drop collections if add fails (for example on timeout).
|
||||
// If the pattern is also missing, do not perform destructive rebinds when
|
||||
// metadata is incomplete: remove+add can permanently drop collections if
|
||||
// add fails (for example on timeout).
|
||||
return false;
|
||||
}
|
||||
if (!this.pathsMatch(listed.path, collection.path)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof listed.pattern === "string" && listed.pattern !== collection.pattern) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user