import { ConversationEntryKind } from "@freya/core" import { describe, expect, test } from "bun:test" import type { ConversationStorageEntry } from "./conversation-recording-query-agent.ts" import { createSessionManager } from "./session-manager.ts" describe("createSessionManager", () => { test("hydrates user and assistant entries into Pi session context", () => { const sessionManager = createSessionManager({ entries: [ entry({ id: "entry-1", sequence: 1, kind: ConversationEntryKind.UserMessage, payload: { role: "user", parts: [{ type: "text", text: "hello" }], }, }), entry({ id: "entry-2", sequence: 2, kind: ConversationEntryKind.AssistantMessage, payload: { role: "assistant", parts: [{ type: "text", text: "hi there" }], }, metadata: { modelRun: { route: "agent_query", provider: "openrouter", model: "stored-model", }, }, }), ], modelProvider: "openrouter", modelId: "fallback-model", }) const context = sessionManager.buildSessionContext() expect(context.messages.map(roleOf)).toEqual(["user", "assistant"]) expect(textFromMessage(context.messages[0])).toBe("hello") expect(textFromMessage(context.messages[1])).toBe("hi there") expect(context.model).toEqual({ provider: "openrouter", modelId: "stored-model", }) }) test("uses the latest context summary and replays only uncovered raw entries", () => { const sessionManager = createSessionManager({ entries: [ entry({ id: "entry-1", sequence: 1, kind: ConversationEntryKind.UserMessage, payload: { role: "user", parts: [{ type: "text", text: "old question" }], }, }), entry({ id: "entry-2", sequence: 2, kind: ConversationEntryKind.AssistantMessage, payload: { role: "assistant", parts: [{ type: "text", text: "old answer" }], }, }), entry({ id: "entry-3", sequence: 3, kind: ConversationEntryKind.ContextSummary, payload: { covers: { startSequence: 1, endSequence: 2, }, summary: { durableFacts: ["The user is designing conversation storage."], preferences: [], decisions: ["Context compaction is stored as a conversation entry."], openTasks: [], importantDetails: [], }, promptVersion: "test-v1", }, }), entry({ id: "entry-4", sequence: 4, kind: ConversationEntryKind.UserMessage, payload: { role: "user", parts: [{ type: "text", text: "new question" }], }, }), ], modelProvider: "openrouter", modelId: "fallback-model", }) const context = sessionManager.buildSessionContext() expect(context.messages.map(roleOf)).toEqual(["compactionSummary", "user"]) expect(textFromMessage(context.messages[0])).toContain( "The user is designing conversation storage.", ) expect(textFromMessage(context.messages[0])).toContain( "Context compaction is stored as a conversation entry.", ) expect(textFromMessage(context.messages[1])).toBe("new question") }) }) function entry( input: Omit & { createdAt?: Date metadata?: ConversationStorageEntry["metadata"] }, ): ConversationStorageEntry { return { ...input, metadata: input.metadata ?? {}, createdAt: input.createdAt ?? new Date("2026-06-15T00:00:00.000Z"), } } function roleOf(message: unknown): string | undefined { if (!isRecord(message)) return undefined return typeof message.role === "string" ? message.role : undefined } function textFromMessage(message: unknown): string { if (!isRecord(message)) return "" if (typeof message.summary === "string") return message.summary const content = message.content if (typeof content === "string") return content if (!Array.isArray(content)) return "" return content.map(textFromContentPart).join("") } function textFromContentPart(part: unknown): string { if (!isRecord(part)) return "" return typeof part.text === "string" ? part.text : "" } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null }