
























@@ -2160,6 +2160,104 @@ describe("memory plugin e2e", () => {
21602160expect(detectCategory("The server is running on port 3000")).toBe("fact");
21612161expect(detectCategory("Random note")).toBe("other");
21622162});
2163+2164+test("memory_forget candidate list shows full UUIDs, not truncated IDs", async () => {
2165+const fakeUuid1 = "890e1fae-1234-5678-abcd-ef0123456789";
2166+const fakeUuid2 = "a1b2c3d4-5678-9abc-def0-1234567890ab";
2167+2168+// LanceDB vectorSearch returns rows with _distance; score = 1/(1+d)
2169+// We want scores between 0.7 and 0.9 so candidates are returned (not auto-deleted)
2170+// score=0.85 => d = 1/0.85 - 1 ≈ 0.176; score=0.80 => d = 1/0.80 - 1 = 0.25
2171+const fakeRows = [
2172+{
2173+id: fakeUuid1,
2174+text: "User prefers dark mode",
2175+category: "preference",
2176+vector: [0.1],
2177+importance: 0.8,
2178+createdAt: Date.now(),
2179+_distance: 0.176,
2180+},
2181+{
2182+id: fakeUuid2,
2183+text: "User lives in New York",
2184+category: "fact",
2185+vector: [0.2],
2186+importance: 0.7,
2187+createdAt: Date.now(),
2188+_distance: 0.25,
2189+},
2190+];
2191+2192+const toArray = vi.fn(async () => fakeRows);
2193+const limitFn = vi.fn(() => ({ toArray }));
2194+const vectorSearch = vi.fn(() => ({ limit: limitFn }));
2195+2196+vi.resetModules();
2197+vi.doMock("openai", () => ({
2198+default: class MockOpenAI {
2199+embeddings = { create: vi.fn(async () => ({ data: [{ embedding: [0.1, 0.2, 0.3] }] })) };
2200+},
2201+}));
2202+vi.doMock("@lancedb/lancedb", () => ({
2203+connect: vi.fn(async () => ({
2204+tableNames: vi.fn(async () => ["memories"]),
2205+openTable: vi.fn(async () => ({
2206+ vectorSearch,
2207+countRows: vi.fn(async () => 2),
2208+add: vi.fn(async () => undefined),
2209+delete: vi.fn(async () => undefined),
2210+})),
2211+})),
2212+}));
2213+2214+try {
2215+const { default: memoryPlugin } = await import("./index.js");
2216+// oxlint-disable-next-line typescript/no-explicit-any
2217+const registeredTools: any[] = [];
2218+const mockApi = {
2219+id: "memory-lancedb",
2220+name: "Memory (LanceDB)",
2221+source: "test",
2222+config: {},
2223+pluginConfig: {
2224+embedding: { apiKey: OPENAI_API_KEY, model: "text-embedding-3-small" },
2225+dbPath: getDbPath(),
2226+autoCapture: false,
2227+autoRecall: false,
2228+},
2229+runtime: {},
2230+logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
2231+// oxlint-disable-next-line typescript/no-explicit-any
2232+registerTool: (tool: any, opts: any) => {
2233+registeredTools.push({ tool, opts });
2234+},
2235+registerCli: vi.fn(),
2236+registerService: vi.fn(),
2237+on: vi.fn(),
2238+resolvePath: (p: string) => p,
2239+};
2240+2241+// oxlint-disable-next-line typescript/no-explicit-any
2242+memoryPlugin.register(mockApi as any);
2243+const forgetTool = registeredTools.find((t) => t.opts?.name === "memory_forget")?.tool;
2244+expect(forgetTool).toBeDefined();
2245+2246+const result = await forgetTool.execute("test-call-full-ids", { query: "user preference" });
2247+2248+// The candidate list text must contain the FULL UUID, not a truncated prefix
2249+const text = result.content?.[0]?.text ?? "";
2250+expect(text).toContain(fakeUuid1);
2251+expect(text).toContain(fakeUuid2);
2252+// Ensure truncated 8-char prefix alone is NOT the format used
2253+expect(text).not.toMatch(/\[890e1fae\]/);
2254+expect(text).not.toMatch(/\[a1b2c3d4\]/);
2255+} finally {
2256+vi.doUnmock("openai");
2257+vi.doUnmock("@lancedb/lancedb");
2258+vi.resetModules();
2259+}
2260+});
21632261});
2164226221652263describe("lancedb runtime loader", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。