evOo-local/packages/adapters/src/supermemory-memory-provider.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

121 lines
3.7 KiB
TypeScript

import type { AdapterContext } from "@rakazo/adapter-kit";
import { afterEach, describe, expect, it, vi } from "vitest";
import { SupermemoryMemoryProvider } from "./supermemory-memory-provider.js";
const context: AdapterContext = {
operationId: "op-1",
traceId: "trace-1",
spaceId: "workspace-1",
userId: "user-1",
botId: "bot-1",
signal: new AbortController().signal,
};
function provider() {
return new SupermemoryMemoryProvider({
baseUrl: "http://localhost:6767",
apiKey: "sm_test_key",
});
}
afterEach(() => vi.unstubAllGlobals());
describe("SupermemoryMemoryProvider", () => {
it("keeps Supermemory namespaces inside the adapter and omits empty history", async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ results: [] }), {
status: 200,
headers: { "content-type": "application/json" },
}),
);
vi.stubGlobal("fetch", fetchMock);
await provider().recall(
{ query: "project", scope: "shared", botId: "bot-1", limit: 5 },
context,
);
expect(fetchMock).toHaveBeenCalledTimes(2);
expect(
fetchMock.mock.calls.map((call) => JSON.parse(String(call[1]?.body)).containerTag),
).toEqual(["rakazo:workspace:workspace-1", "rakazo:bot-1"]);
});
it("adds the current history generation only after compaction", async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ results: [] }), {
status: 200,
headers: { "content-type": "application/json" },
}),
);
vi.stubGlobal("fetch", fetchMock);
await provider().recall(
{
query: "project",
scope: "isolated",
botId: "bot-1",
historyGeneration: 3,
limit: 5,
},
context,
);
expect(
fetchMock.mock.calls.map((call) => JSON.parse(String(call[1]?.body)).containerTag),
).toEqual(["rakazo:bot-1", "rakazo:bot-1:history:3"]);
});
it("passes recall limits and cancellation through to the provider client", async () => {
const controller = new AbortController();
controller.abort(new Error("cancelled"));
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ results: [] }), {
status: 200,
headers: { "content-type": "application/json" },
}),
);
vi.stubGlobal("fetch", fetchMock);
await provider().recall(
{ query: "project", scope: "isolated", botId: "bot-1", limit: 2 },
{ ...context, signal: controller.signal },
);
const init = fetchMock.mock.calls[0]?.[1];
expect(JSON.parse(String(init?.body)).limit).toBe(2);
expect(init?.signal.aborted).toBe(true);
});
it("mirrors shared durable saves so a later scope change retains bot memory", async () => {
const fetchMock = vi.fn().mockResolvedValue(new Response("", { status: 200 }));
vi.stubGlobal("fetch", fetchMock);
await provider().save(
{
content: "Use metric units.",
scope: "shared",
botId: "bot-1",
source: { kind: "durable" },
},
context,
);
expect(
fetchMock.mock.calls.map((call) => JSON.parse(String(call[1]?.body)).containerTag),
).toEqual(["rakazo:workspace:workspace-1", "rakazo:bot-1"]);
});
it("purges only requested history generations", async () => {
const fetchMock = vi.fn().mockResolvedValue(new Response("", { status: 200 }));
vi.stubGlobal("fetch", fetchMock);
await provider().purgeHistory({ botId: "bot-1", generations: [2, 3, 3] }, context);
expect(fetchMock.mock.calls.map((call) => call[0])).toEqual([
"http://localhost:6767/v3/container-tags/rakazo%3Abot-1%3Ahistory%3A2",
"http://localhost:6767/v3/container-tags/rakazo%3Abot-1%3Ahistory%3A3",
]);
});
});