import { describe, it } from "node:test"; import assert from "node:assert/strict"; import { applyAging } from "../../../open-sse/services/compression/progressiveAging.ts"; import type { AgingThresholds, Summarizer } from "../../../open-sse/services/compression/types.ts"; function makeMessages( count: number, role: string = "user", prefix: string = "Message" ): Array<{ role: string; content: string }> { return Array.from({ length: count }, (_, i) => ({ role: i % 2 === 0 ? "user" : "assistant", content: `${prefix} ${i}: ${"x".repeat(100)}`, })); } describe("applyAging", () => { const defaultThresholds: AgingThresholds = { fullSummary: 5, moderate: 3, light: 2, verbatim: 2 }; it("returns empty array for empty input", () => { const result = applyAging([]); assert.deepEqual(result.messages, []); assert.equal(result.saved, 0); }); it("returns single message unchanged (verbatim tier)", () => { const msgs = [{ role: "user", content: "Hello world" }]; const result = applyAging(msgs, defaultThresholds); assert.equal(result.messages.length, 1); assert.equal((result.messages[0] as { content: string }).content, "Hello world"); }); it("keeps last 2 messages as verbatim", () => { const msgs = makeMessages(10); const result = applyAging(msgs, defaultThresholds); const last2 = result.messages.slice(-2); for (const msg of last2) { const content = typeof (msg as { content: unknown }).content === "string" ? (msg as { content: string }).content : ""; assert.ok( !content.startsWith("[COMPRESSED:aging:"), `Last message should be verbatim, got: ${content.slice(0, 40)}` ); } }); it("applies fullSummary tier to oldest messages", () => { const msgs = makeMessages(10); const result = applyAging(msgs, defaultThresholds); const first = result.messages[0] as { content: string }; const content = typeof first.content === "string" ? first.content : ""; assert.ok( content.startsWith("[COMPRESSED:aging:fullSummary]"), `Expected fullSummary marker, got: ${content.slice(0, 60)}` ); }); it("skips messages with [COMPRESSED: prefix (idempotent)", () => { const msgs: Array<{ role: string; content: string }> = [ { role: "assistant", content: "[COMPRESSED:aging:fullSummary] prior summary" }, { role: "user", content: "New message" }, ]; const result = applyAging(msgs, defaultThresholds); const first = result.messages[0] as { content: string }; const content = typeof first.content === "string" ? first.content : ""; assert.ok(content.startsWith("[COMPRESSED:aging:fullSummary]")); assert.ok(!content.includes("[COMPRESSED:aging:fullSummary][COMPRESSED:")); }); it("uses custom thresholds", () => { const customThresholds: AgingThresholds = { fullSummary: 1, moderate: 1, light: 1, verbatim: 1, }; const msgs = makeMessages(6); const result = applyAging(msgs, customThresholds); assert.ok(result.messages.length > 0); }); it("accepts custom summarizer", () => { const customSummarizer: Summarizer = { summarize: () => "[CUSTOM SUMMARY]", }; const msgs = makeMessages(10); const result = applyAging(msgs, defaultThresholds, customSummarizer); const fullSummaryMsgs = result.messages.filter((m) => { const content = typeof (m as { content: unknown }).content === "string" ? (m as { content: string }).content : ""; return content.includes("[CUSTOM SUMMARY]"); }); assert.ok(fullSummaryMsgs.length > 0, "Expected at least one message with custom summary"); }); it("computes saved tokens", () => { const msgs = makeMessages(10); const result = applyAging(msgs, defaultThresholds); assert.ok(typeof result.saved === "number"); }); it("handles 2-message conversation (all verbatim)", () => { const msgs = [ { role: "user", content: "Hello" }, { role: "assistant", content: "Hi there" }, ]; const result = applyAging(msgs, defaultThresholds); assert.equal(result.messages.length, 2); for (const msg of result.messages) { const content = typeof (msg as { content: unknown }).content === "string" ? (msg as { content: string }).content : ""; assert.ok(!content.startsWith("[COMPRESSED:")); } }); it("handles 5-message conversation with light tier", () => { const msgs = makeMessages(5); const thresholds: AgingThresholds = { fullSummary: 10, moderate: 10, light: 3, verbatim: 1 }; const result = applyAging(msgs, thresholds); assert.ok(result.messages.length > 0); }); it("handles messages with array content", () => { const msgs = [{ role: "user", content: [{ type: "text", text: "Hello from array" }] }]; const result = applyAging(msgs, defaultThresholds); assert.equal(result.messages.length, 1); }); it("does not mutate original messages array", () => { const original = makeMessages(5); const originalCopy = JSON.parse(JSON.stringify(original)); applyAging(original, defaultThresholds); assert.deepEqual(original, originalCopy); }); it("handles all-assistant messages", () => { const msgs = Array.from({ length: 8 }, (_, i) => ({ role: "assistant" as const, content: `Response ${i}: ${"y".repeat(100)}`, })); const result = applyAging(msgs, defaultThresholds); assert.ok(result.messages.length > 0); }); it("handles mixed user/assistant/tool messages", () => { const msgs = [ { role: "user", content: "Fix the bug" }, { role: "assistant", content: "I'll fix it" }, { role: "tool", content: "Result: fixed" }, { role: "assistant", content: "Done" }, ]; const result = applyAging(msgs, defaultThresholds); assert.ok(result.messages.length > 0); }); it("idempotent — running twice produces same output", () => { const msgs = makeMessages(10); const first = applyAging(msgs, defaultThresholds); const second = applyAging(first.messages, defaultThresholds); const firstContent = JSON.stringify( first.messages.map((m) => (m as { content: string }).content) ); const secondContent = JSON.stringify( second.messages.map((m) => (m as { content: string }).content) ); assert.equal(firstContent, secondContent); }); });