





























@@ -1829,6 +1829,137 @@ describe("QmdMemoryManager", () => {
18291829await manager.close();
18301830});
183118311832+it("uses valid qmd query JSON captured before a non-zero exit", async () => {
1833+cfg = {
1834+ ...cfg,
1835+memory: {
1836+backend: "qmd",
1837+qmd: {
1838+includeDefaultMemory: false,
1839+searchMode: "query",
1840+update: { interval: "0s", debounceMs: 60_000, onBoot: false },
1841+paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
1842+},
1843+},
1844+} as OpenClawConfig;
1845+1846+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1847+if (args[0] === "query") {
1848+const child = createMockChild({ autoClose: false });
1849+queueMicrotask(() => {
1850+child.stdout.emit("data", "initializing qmd reranker\n");
1851+child.stdout.emit(
1852+"data",
1853+JSON.stringify(
1854+[
1855+{
1856+file: "qmd://workspace-main/notes/welcome.md",
1857+score: 0.93,
1858+snippet: "@@ -7,1\nrouter glacier backup",
1859+},
1860+],
1861+null,
1862+2,
1863+),
1864+);
1865+child.stderr.emit("data", "ggml-metal-device.m:612 assertion failed");
1866+child.closeWith(134);
1867+});
1868+return child;
1869+}
1870+return createMockChild();
1871+});
1872+1873+const { manager } = await createManager();
1874+1875+await expect(
1876+manager.search("router glacier backup", { sessionKey: "agent:main:slack:dm:u123" }),
1877+).resolves.toEqual([
1878+{
1879+path: "notes/welcome.md",
1880+startLine: 7,
1881+endLine: 7,
1882+score: 0.93,
1883+snippet: "@@ -7,1\nrouter glacier backup",
1884+source: "memory",
1885+},
1886+]);
1887+expectMockMessageContains(
1888+logWarnMock,
1889+"qmd query exited non-zero after producing valid JSON; using captured search results (code 134)",
1890+);
1891+await manager.close();
1892+});
1893+1894+it("keeps invalid qmd query stdout failed after a non-zero exit", async () => {
1895+cfg = {
1896+ ...cfg,
1897+memory: {
1898+backend: "qmd",
1899+qmd: {
1900+includeDefaultMemory: false,
1901+searchMode: "query",
1902+update: { interval: "0s", debounceMs: 60_000, onBoot: false },
1903+paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
1904+},
1905+},
1906+} as OpenClawConfig;
1907+1908+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1909+if (args[0] === "query") {
1910+const child = createMockChild({ autoClose: false });
1911+emitAndClose(child, "stdout", "not json", 134);
1912+return child;
1913+}
1914+return createMockChild();
1915+});
1916+1917+const { manager } = await createManager();
1918+1919+await expect(
1920+manager.search("router glacier backup", { sessionKey: "agent:main:slack:dm:u123" }),
1921+).rejects.toThrow(/qmd query router glacier backup .* failed \(code 134\): not json/);
1922+await manager.close();
1923+});
1924+1925+it("does not use qmd query JSON from a non-crash search failure", async () => {
1926+cfg = {
1927+ ...cfg,
1928+memory: {
1929+backend: "qmd",
1930+qmd: {
1931+includeDefaultMemory: false,
1932+searchMode: "query",
1933+update: { interval: "0s", debounceMs: 60_000, onBoot: false },
1934+paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
1935+},
1936+},
1937+} as OpenClawConfig;
1938+1939+spawnMock.mockImplementation((_cmd: string, args: string[]) => {
1940+if (args[0] === "query") {
1941+const child = createMockChild({ autoClose: false });
1942+queueMicrotask(() => {
1943+child.stdout.emit("data", "[]");
1944+child.stderr.emit("data", "SQLITE_BUSY: database is locked");
1945+child.closeWith(2);
1946+});
1947+return child;
1948+}
1949+return createMockChild();
1950+});
1951+1952+const { manager } = await createManager();
1953+1954+await expect(
1955+manager.search("router glacier backup", { sessionKey: "agent:main:slack:dm:u123" }),
1956+).rejects.toThrow(/SQLITE_BUSY: database is locked/);
1957+expect(logWarnMock).not.toHaveBeenCalledWith(
1958+expect.stringContaining("using captured search results"),
1959+);
1960+await manager.close();
1961+});
1962+18321963it("repairs missing managed collections and retries search once", async () => {
18331964cfg = {
18341965 ...cfg,
@@ -1864,7 +1995,11 @@ describe("QmdMemoryManager", () => {
18641995if (collection === "memory-root-main" && !missingCollectionSeen) {
18651996missingCollectionSeen = true;
18661997const child = createMockChild({ autoClose: false });
1867-emitAndClose(child, "stderr", "Collection not found: memory-root-main", 1);
1998+queueMicrotask(() => {
1999+child.stdout.emit("data", "[]");
2000+child.stderr.emit("data", "Collection not found: memory-root-main");
2001+child.closeWith(1);
2002+});
18682003return child;
18692004}
18702005if (collection === "memory-root-main") {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。