| 1 | import { describe, expect, it } from "vite-plus/test"; |
| 2 | import * as DateTime from "effect/DateTime"; |
| 3 | import { |
| 4 | deriveLatestContextWindowSnapshot, |
| 5 | formatContextWindowTokens, |
| 6 | latestProviderTurnTokenUsage, |
| 7 | } from "./contextWindow"; |
| 8 | |
| 9 | describe("V2 context window presentation", () => { |
| 10 | it("uses retained compaction token data when available", () => { |
| 11 | const snapshot = deriveLatestContextWindowSnapshot([ |
| 12 | { |
| 13 | item: { |
| 14 | id: "compaction-1" as never, |
| 15 | threadId: "thread-1" as never, |
| 16 | runId: null, |
| 17 | nodeId: null, |
| 18 | providerThreadId: null, |
| 19 | providerTurnId: null, |
| 20 | nativeItemRef: null, |
| 21 | parentItemId: null, |
| 22 | ordinal: 1, |
| 23 | status: "completed", |
| 24 | title: null, |
| 25 | startedAt: null, |
| 26 | completedAt: null, |
| 27 | updatedAt: DateTime.makeUnsafe("2026-06-20T00:00:00.000Z"), |
| 28 | type: "compaction", |
| 29 | driver: null, |
| 30 | beforeTokenCount: 10_000, |
| 31 | afterTokenCount: 2_000, |
| 32 | }, |
| 33 | }, |
| 34 | ]); |
| 35 | expect(snapshot?.usedTokens).toBe(2_000); |
| 36 | expect(snapshot?.totalProcessedTokens).toBe(10_000); |
| 37 | }); |
| 38 | |
| 39 | it("prefers current provider usage and preserves ACP cost", () => { |
| 40 | const snapshot = deriveLatestContextWindowSnapshot([], undefined, { |
| 41 | contextUsage: { |
| 42 | usedTokens: 2_500, |
| 43 | maxTokens: 10_000, |
| 44 | cost: { amount: 0.42, currency: "USD" }, |
| 45 | }, |
| 46 | updatedAt: DateTime.makeUnsafe("2026-08-23T00:00:00.000Z"), |
| 47 | }); |
| 48 | |
| 49 | expect(snapshot).toMatchObject({ |
| 50 | usedTokens: 2_500, |
| 51 | maxTokens: 10_000, |
| 52 | remainingTokens: 7_500, |
| 53 | usedPercentage: 25, |
| 54 | cost: { amount: 0.42, currency: "USD" }, |
| 55 | }); |
| 56 | }); |
| 57 | |
| 58 | it("formats compact token values", () => { |
| 59 | expect(formatContextWindowTokens(1_500)).toBe("1.5k"); |
| 60 | }); |
| 61 | |
| 62 | it.each([ |
| 63 | [999_499, "999k"], |
| 64 | [999_500, "1m"], |
| 65 | [999_999, "1m"], |
| 66 | [1_000_000, "1m"], |
| 67 | [1_100_000, "1.1m"], |
| 68 | ])("formats %d tokens as %s at the million boundary", (tokens, expected) => { |
| 69 | expect(formatContextWindowTokens(tokens)).toBe(expected); |
| 70 | }); |
| 71 | }); |
| 72 | |
| 73 | describe("live provider-turn usage (#8144)", () => { |
| 74 | it("prefers the provider's live report over compaction items", () => { |
| 75 | const snapshot = deriveLatestContextWindowSnapshot([], { |
| 76 | usedTokens: 42_000, |
| 77 | maxTokens: 200_000, |
| 78 | inputTokens: 40_000, |
| 79 | outputTokens: 2_000, |
| 80 | updatedAt: "2026-08-27T00:00:00.000Z", |
| 81 | }); |
| 82 | expect(snapshot).not.toBeNull(); |
| 83 | expect(snapshot?.usedTokens).toBe(42_000); |
| 84 | expect(snapshot?.maxTokens).toBe(200_000); |
| 85 | expect(snapshot?.remainingTokens).toBe(158_000); |
| 86 | expect(snapshot?.usedPercentage).toBe(21); |
| 87 | }); |
| 88 | |
| 89 | it("handles a report without a known context window", () => { |
| 90 | const snapshot = deriveLatestContextWindowSnapshot([], { |
| 91 | usedTokens: 42_000, |
| 92 | updatedAt: "2026-08-27T00:00:00.000Z", |
| 93 | }); |
| 94 | expect(snapshot?.maxTokens).toBeNull(); |
| 95 | expect(snapshot?.usedPercentage).toBeNull(); |
| 96 | }); |
| 97 | }); |
| 98 | |
| 99 | describe("latestProviderTurnTokenUsage", () => { |
| 100 | it("picks the newest report, not the last turn in snapshot order", () => { |
| 101 | const usage = (usedTokens: number, updatedAt: string) => ({ |
| 102 | tokenUsage: { usedTokens, updatedAt }, |
| 103 | }); |
| 104 | // Snapshots sort by provider thread id, so an older thread can come last. |
| 105 | const latest = latestProviderTurnTokenUsage([ |
| 106 | usage(300_000, "2026-06-20T12:00:00.000Z"), |
| 107 | {}, |
| 108 | usage(90_000, "2026-06-20T09:00:00.000Z"), |
| 109 | ]); |
| 110 | expect(latest?.usedTokens).toBe(300_000); |
| 111 | }); |
| 112 | }); |