mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 05:50:43 +00:00
* feat(active-memory): default QMD recall to search * feat(active-memory): surface search debug telemetry * fix(active-memory): avoid forking qmd managers
107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import {
|
|
resetMemoryToolMockState,
|
|
setMemoryBackend,
|
|
setMemorySearchImpl,
|
|
} from "./memory-tool-manager-mock.js";
|
|
import {
|
|
createMemorySearchToolOrThrow,
|
|
expectUnavailableMemorySearchDetails,
|
|
} from "./tools.test-helpers.js";
|
|
|
|
describe("memory_search unavailable payloads", () => {
|
|
beforeEach(() => {
|
|
resetMemoryToolMockState({ searchImpl: async () => [] });
|
|
});
|
|
|
|
it("returns explicit unavailable metadata for quota failures", async () => {
|
|
setMemorySearchImpl(async () => {
|
|
throw new Error("openai embeddings failed: 429 insufficient_quota");
|
|
});
|
|
|
|
const tool = createMemorySearchToolOrThrow();
|
|
const result = await tool.execute("quota", { query: "hello" });
|
|
expectUnavailableMemorySearchDetails(result.details, {
|
|
error: "openai embeddings failed: 429 insufficient_quota",
|
|
warning: "Memory search is unavailable because the embedding provider quota is exhausted.",
|
|
action: "Top up or switch embedding provider, then retry memory_search.",
|
|
});
|
|
});
|
|
|
|
it("returns explicit unavailable metadata for non-quota failures", async () => {
|
|
setMemorySearchImpl(async () => {
|
|
throw new Error("embedding provider timeout");
|
|
});
|
|
|
|
const tool = createMemorySearchToolOrThrow();
|
|
const result = await tool.execute("generic", { query: "hello" });
|
|
expectUnavailableMemorySearchDetails(result.details, {
|
|
error: "embedding provider timeout",
|
|
warning: "Memory search is unavailable due to an embedding/provider error.",
|
|
action: "Check embedding provider configuration and retry memory_search.",
|
|
});
|
|
});
|
|
|
|
it("returns structured search debug metadata for qmd results", async () => {
|
|
setMemoryBackend("qmd");
|
|
setMemorySearchImpl(async (opts) => {
|
|
opts?.onDebug?.({
|
|
backend: "qmd",
|
|
configuredMode: opts.qmdSearchModeOverride ?? "query",
|
|
effectiveMode: "query",
|
|
fallback: "unsupported-search-flags",
|
|
});
|
|
return [
|
|
{
|
|
path: "MEMORY.md",
|
|
startLine: 1,
|
|
endLine: 2,
|
|
score: 0.9,
|
|
snippet: "ramen",
|
|
source: "memory",
|
|
},
|
|
];
|
|
});
|
|
|
|
const tool = createMemorySearchToolOrThrow({
|
|
config: {
|
|
plugins: {
|
|
entries: {
|
|
"active-memory": {
|
|
config: {
|
|
qmd: {
|
|
searchMode: "search",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
memory: {
|
|
backend: "qmd",
|
|
qmd: {
|
|
searchMode: "query",
|
|
limits: {
|
|
maxInjectedChars: 1000,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
agentSessionKey: "agent:main:main:active-memory:debug",
|
|
});
|
|
const result = await tool.execute("debug", { query: "favorite food" });
|
|
expect(result.details).toMatchObject({
|
|
mode: "query",
|
|
debug: {
|
|
backend: "qmd",
|
|
configuredMode: "search",
|
|
effectiveMode: "query",
|
|
fallback: "unsupported-search-flags",
|
|
hits: 1,
|
|
},
|
|
});
|
|
expect((result.details as { debug?: { searchMs?: number } }).debug?.searchMs).toEqual(
|
|
expect.any(Number),
|
|
);
|
|
});
|
|
});
|