import { describe, expect, it, vi } from "vitest"; import type { MessageEvent } from "#/types/agent-server/core"; import { loadCompleteTranscriptEvents, TRANSCRIPT_HISTORY_PAGE_SIZE, } from "./load-complete-events"; const timestamp = "2026-07-10T12:34:56.000Z"; const makeMessage = (index: number): MessageEvent => ({ id: `event-${index.toString().padStart(3, "0")}`, timestamp: new Date(Date.UTC(2026, 6, 10, 0, 0, index)).toISOString(), source: "user", llm_message: { role: "user", content: [{ type: "text", text: `Message ${index}` }], }, activated_skills: [], extended_content: [], }); describe("loadCompleteTranscriptEvents", () => { it("paginates beyond the 50 events initially loaded by the chat", async () => { const allEvents = Array.from({ length: 225 }, (_, index) => makeMessage(index), ); const loadedEvents = allEvents.slice(-50); const descendingEvents = allEvents.slice().reverse(); const searchEvents = vi.fn( async ({ limit, pageId }: { limit: number; pageId?: string }) => { const offset = Number(pageId ?? 0); const items = descendingEvents.slice(offset, offset + limit); const nextOffset = offset + items.length; return { items, next_page_id: nextOffset < descendingEvents.length ? String(nextOffset) : null, }; }, ); const result = await loadCompleteTranscriptEvents( loadedEvents, searchEvents, ); expect(result).toEqual(allEvents); expect(searchEvents).toHaveBeenCalledTimes(3); expect(searchEvents).toHaveBeenNthCalledWith(1, { limit: TRANSCRIPT_HISTORY_PAGE_SIZE, sortOrder: "TIMESTAMP_DESC", strictPagination: true, }); }); it("rejects a repeated full page when completeness cannot be proven", async () => { const page = Array.from( { length: TRANSCRIPT_HISTORY_PAGE_SIZE }, (_, index) => makeMessage(index), ).reverse(); const searchEvents = vi.fn().mockResolvedValue({ items: page }); await expect( loadCompleteTranscriptEvents(page, searchEvents), ).rejects.toThrow("cannot prove that all events were loaded"); expect(searchEvents).toHaveBeenCalledTimes(1); }); it("uses cursors without dropping events at a shared timestamp boundary", async () => { const allEvents = Array.from({ length: 125 }, (_, index) => ({ ...makeMessage(index), timestamp, })); const descendingEvents = allEvents.slice().reverse(); const searchEvents = vi.fn( async ({ limit, pageId }: { limit: number; pageId?: string }) => { const offset = Number(pageId ?? 0); const items = descendingEvents.slice(offset, offset + limit); return { items, next_page_id: offset + items.length < descendingEvents.length ? String(offset + items.length) : null, }; }, ); const result = await loadCompleteTranscriptEvents([], searchEvents); expect(result).toEqual(allEvents); expect(searchEvents).toHaveBeenNthCalledWith(2, { limit: TRANSCRIPT_HISTORY_PAGE_SIZE, pageId: "100", sortOrder: "TIMESTAMP_DESC", strictPagination: true, }); }); it("does not let live-only store events mask unfetched persisted history", async () => { const persistedEvents = Array.from({ length: 150 }, (_, index) => makeMessage(index), ); const liveEvents = Array.from({ length: 50 }, (_, index) => makeMessage(index + 150), ); const searchEvents = vi.fn( async ({ limit, timestampLt, }: { limit: number; timestampLt?: string; }) => ({ items: persistedEvents .filter((event) => timestampLt ? event.timestamp < timestampLt : true, ) .slice() .reverse() .slice(0, limit), next_page_id: null, }), ); const result = await loadCompleteTranscriptEvents( liveEvents, searchEvents, persistedEvents.length, ); expect(result).toEqual([...persistedEvents, ...liveEvents]); expect(searchEvents).toHaveBeenCalledTimes(2); }); it("rejects malformed history pages", async () => { await expect( loadCompleteTranscriptEvents([], async () => ({ items: null as never })), ).rejects.toThrow("expected page.items to be an array"); }); it("rejects a partial export when the server reports more events", async () => { await expect( loadCompleteTranscriptEvents( [], async () => ({ items: [makeMessage(1)], next_page_id: null }), 2, ), ).rejects.toThrow("Transcript history is incomplete"); }); });