import type { AdapterContext } from "@rakazo/adapter-kit"; import { describe, expect, it, vi } from "vitest"; import { appendMarkdown, MarkdownMemoryStore, rankMemoryDocuments } from "./index.js"; const context: AdapterContext = { operationId: "read-memory", traceId: "read-memory", spaceId: "workspace-1", userId: "user-1", signal: new AbortController().signal, }; describe("memory store contract shape", () => { it("declares markdown portability", () => { const store = new MarkdownMemoryStore({} as never); expect(store.describe().capabilities.markdownPortable).toBe(true); }); it("reads the most recently updated documents first", async () => { const updatedAt = new Date("2026-08-16T10:00:00.000Z"); const findMany = vi .fn() .mockResolvedValue([ { id: "memory-1", path: "facts.md", content: "A fact", revision: 3, updatedAt }, ]); const store = new MarkdownMemoryStore({ memoryDocument: { findMany } } as never); await expect(store.read({ scope: "bot", botId: "bot-1" }, context)).resolves.toEqual({ documents: [ { id: "memory-1", path: "facts.md", content: "A fact", revision: 3, updatedAt: updatedAt.toISOString(), }, ], }); expect(findMany).toHaveBeenCalledWith({ where: { spaceId: "workspace-1", userId: "user-1", scope: "bot", botId: "bot-1", }, orderBy: [{ updatedAt: "desc" }, { path: "asc" }], }); }); }); describe("appendMarkdown", () => { it("adds the note below a heading or paragraph, and right below a list", () => { expect(appendMarkdown("# Chief\n\n", "- 2026-10-03: Prefers tea")).toBe( "# Chief\n\n- 2026-10-03: Prefers tea\n", ); expect(appendMarkdown("- a\n- b", "- c")).toBe("- a\n- b\n- c\n"); expect(appendMarkdown("- a\n more about a\n", "- c")).toBe("- a\n more about a\n- c\n"); expect(appendMarkdown("", "- first")).toBe("- first\n"); }); it("leaves the document unchanged for an empty note", () => { expect(appendMarkdown("# Chief\n", " ")).toBe("# Chief\n"); }); it("deduplicates an identical single-line note when appended repeatedly", () => { const existing = "# Chief\n\n- 2026-10-03: Prefers tea\n"; expect(appendMarkdown(existing, "- 2026-10-03: Prefers tea")).toBe(existing); }); }); describe("rankMemoryDocuments & search", () => { it("ranks path and heading matches above body-only or partial token matches", async () => { const docs = [ { id: "1", path: "notes/general.md", content: "We discussed the deployment pipeline briefly.", revision: 1, updatedAt: new Date("2026-10-01T00:00:00.000Z"), }, { id: "2", path: "ops/deployment-guide.md", content: "# Deployment Guide\n\nRun the production deployment script with rollback checks.", revision: 2, updatedAt: new Date("2026-10-02T00:00:00.000Z"), }, { id: "3", path: "notes/random.md", content: "Unrelated lunch menu.", revision: 1, updatedAt: new Date("2026-10-03T00:00:00.000Z"), }, ]; const findMany = vi.fn().mockResolvedValue(docs); const store = new MarkdownMemoryStore({ memoryDocument: { findMany } } as never); const results = await store.search({ scope: "user", query: "deployment rollback" }, context); expect(results.map((r) => r.path)).toEqual(["ops/deployment-guide.md", "notes/general.md"]); expect(results[0]!.score).toBe(1); expect(results[1]!.score).toBeLessThan(1); expect(results[0]!.snippet).toContain("rollback"); }); it("returns empty array when no tokens match", () => { expect( rankMemoryDocuments([{ path: "a.md", content: "alpha beta" }], "nonexistent token"), ).toEqual([]); }); });