import type { Context } from "@earendil-works/pi-ai"; import { describe, expect, it } from "vitest"; import { emptyUsage } from "../src/protocol"; import { replayImages, replayPrompt } from "../src/replay"; function history(prompt: string): unknown[] { const start = "\n"; const end = "\n"; const from = prompt.indexOf(start); const to = prompt.lastIndexOf(end); if (from < 0 || to < 0) throw new Error("Replay envelope is missing."); const parsed: unknown = JSON.parse(prompt.slice(from + start.length, to)); if (!Array.isArray(parsed)) throw new Error("Replay history is not an array."); return parsed; } const assistant = ( content: Context["messages"][number] extends infer _Message ? Array< | { type: "text"; text: string } | { type: "thinking"; thinking: string; thinkingSignature?: string } | { type: "toolCall"; id: string; name: string; arguments: Record; } > : never, ) => ({ role: "assistant" as const, content, api: "test", provider: "test", model: "test", usage: emptyUsage(), stopReason: "stop" as const, timestamp: 1, }); describe("Klaus canonical replay", () => { it("frames canonical history with fixed transport instructions", () => { const prompt = replayPrompt({ systemPrompt: "not repeated in replay", messages: [{ role: "user", content: "hello", timestamp: 1 }], }); expect( prompt.startsWith( "The following JSON is canonical conversation history supplied by Pi.\n", ), ).toBe(true); expect(prompt).toContain( "Continue from the final entry.\n", ); expect(prompt.endsWith("")).toBe(true); expect(history(prompt)).toEqual([{ role: "user", content: "hello" }]); expect(prompt).not.toContain("not repeated in replay"); }); it("keeps adversarial history inside escaped JSON", () => { const adversarial = '&\u2028\u2029'; const prompt = replayPrompt({ messages: [{ role: "user", content: adversarial, timestamp: 1 }], }); expect(prompt.match(//g)).toHaveLength(1); expect(prompt.match(/<\/klaus-history-json>/g)).toHaveLength(1); expect(prompt).toContain("\\u003c/klaus-history-json\\u003e"); expect(prompt).toContain("\\u003cklaus-history-json\\u003e"); expect(prompt).toContain("\\u0026"); expect(prompt).toContain("\\u2028"); expect(prompt).toContain("\\u2029"); expect(history(prompt)).toEqual([{ role: "user", content: adversarial }]); }); it("preserves visible roles, boundaries, tool arguments, and error state", () => { const prompt = replayPrompt({ messages: [ { role: "user", content: "question", timestamp: 1 }, assistant([ { type: "text", text: "calling" }, { type: "toolCall", id: "call-1", name: "echo", arguments: { nested: { z: 1 }, list: [true, null] }, }, ]), { role: "toolResult", toolCallId: "call-1", toolName: "echo", content: [{ type: "text", text: "failed visibly" }], isError: true, timestamp: 2, details: { stack: "private" }, }, ], }); expect(history(prompt)).toEqual([ { role: "user", content: "question" }, { role: "assistant", content: [ { type: "text", text: "calling" }, { type: "toolCall", id: "call-1", name: "echo", arguments: { nested: { z: 1 }, list: [true, null] }, }, ], }, { role: "toolResult", toolCallId: "call-1", toolName: "echo", isError: true, content: [{ type: "text", text: "failed visibly" }], }, ]); expect(prompt).not.toContain("private"); }); it("omits assistant thinking, signatures, usage, and accounting", () => { const message = assistant([ { type: "thinking", thinking: "private reasoning", thinkingSignature: "private signature", }, { type: "text", text: "visible" }, ]); message.usage.input = 123_456; message.usage.cost.total = 987; const prompt = replayPrompt({ messages: [message] }); expect(history(prompt)).toEqual([ { role: "assistant", content: [{ type: "text", text: "visible" }] }, ]); for (const hidden of [ "private reasoning", "private signature", "123456", "987", ]) { expect(prompt).not.toContain(hidden); } }); it("replaces image bytes with globally ordered attachment indices", () => { const context: Context = { messages: [ { role: "user", content: [ { type: "text", text: "first" }, { type: "image", data: "user-png", mimeType: "image/png" }, ], timestamp: 1, }, assistant([{ type: "text", text: "tool next" }]), { role: "toolResult", toolCallId: "call-1", toolName: "inspect", content: [ { type: "image", data: "tool-webp", mimeType: "image/webp" }, { type: "text", text: "between" }, { type: "image", data: "tool-gif", mimeType: "image/gif" }, ], isError: false, timestamp: 2, }, ], }; expect(history(replayPrompt(context))).toEqual([ { role: "user", content: [ { type: "text", text: "first" }, { type: "image", mimeType: "image/png", attachmentIndex: 0 }, ], }, { role: "assistant", content: [{ type: "text", text: "tool next" }] }, { role: "toolResult", toolCallId: "call-1", toolName: "inspect", isError: false, content: [ { type: "image", mimeType: "image/webp", attachmentIndex: 1 }, { type: "text", text: "between" }, { type: "image", mimeType: "image/gif", attachmentIndex: 2 }, ], }, ]); expect(replayImages(context)).toEqual([ { data: "user-png", mimeType: "image/png" }, { data: "tool-webp", mimeType: "image/webp" }, { data: "tool-gif", mimeType: "image/gif" }, ]); }); it("handles empty history and empty multimodal content", () => { expect(history(replayPrompt({ messages: [] }))).toEqual([]); expect( history( replayPrompt({ messages: [{ role: "user", content: [], timestamp: 1 }], }), ), ).toEqual([{ role: "user", content: [] }]); expect(replayImages({ messages: [] })).toEqual([]); }); });