import type { AdapterContext, MemoryCommitRequest } from "@rakazo/adapter-kit"; import { MemoryDocumentTooLargeError } from "@rakazo/adapter-kit"; import { describe, expect, it, vi } from "vitest"; import { datedMemoryNote, rememberFromTool } from "./remember.js"; const context: AdapterContext = { operationId: "run-1", traceId: "run-1", spaceId: "space-1", userId: "user-1", signal: new AbortController().signal, }; function remember(args: Record, commit = vi.fn(async () => ({}) as never)) { return { commit, result: rememberFromTool({ commit }, context, { botId: "bot-1", runId: "run-1", threadId: "thread-1", date: "2026-10-03", args, }), }; } describe("datedMemoryNote", () => { it("is one dated bullet whose later lines stay inside it", () => { expect(datedMemoryNote(" Prefers tea ", "2026-10-03")).toBe("- 2026-10-03: Prefers tea"); expect(datedMemoryNote("Trip plan\nBerlin first\n\nthen Vienna", "2026-10-03")).toBe( "- 2026-10-03: Trip plan\n Berlin first\n\n then Vienna", ); }); }); describe("rememberFromTool", () => { it("appends a dated note to MEMORY.md by default", async () => { const { commit, result } = remember({ content: "Prefers tea" }); await expect(result).resolves.toEqual({ ok: true }); expect(commit).toHaveBeenCalledWith( { scope: "bot", botId: "bot-1", path: "MEMORY.md", content: "- 2026-10-03: Prefers tea", mode: "append", sourceRunId: "run-1", sourceThreadId: "thread-1", } satisfies MemoryCommitRequest, context, ); }); it("rewrites the whole document only when asked to", async () => { const { commit, result } = remember({ content: "# Chief\n\n- Prefers tea\n", path: "notes.md", mode: "replace", }); await expect(result).resolves.toEqual({ ok: true }); expect(commit).toHaveBeenCalledWith( expect.objectContaining({ path: "notes.md", content: "# Chief\n\n- Prefers tea\n", mode: "replace", }), context, ); }); it("refuses an empty note without writing", async () => { const { commit, result } = remember({ content: " " }); await expect(result).resolves.toEqual({ error: "content is empty" }); expect(commit).not.toHaveBeenCalled(); }); it("tells the bot to condense a full document", async () => { const commit = vi.fn(async () => { throw new MemoryDocumentTooLargeError("MEMORY.md"); }); const { result } = remember({ content: "One more fact" }, commit); await expect(result).resolves.toEqual({ error: 'MEMORY.md is full (16 KB). Condense it with mode "replace", then save this note again.', }); }); it("lets other storage failures fail the call", async () => { const commit = vi.fn(async () => { throw new Error("database unavailable"); }); await expect(remember({ content: "fact" }, commit).result).rejects.toThrow( "database unavailable", ); }); });