summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/tests/context-window.test.ts
blob: bb64ed53672a30361ff94d87fc3e0d1e49ce8c9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { describe, expect, it } from "vitest";
import { computeContextUsage } from "../src/lib/context-window.js";
import type { CacheStats } from "../src/lib/types.js";

function stats(last: CacheStats["last"]): CacheStats {
	return {
		inputTokens: 0,
		outputTokens: 0,
		cacheReadTokens: 0,
		cacheWriteTokens: 0,
		requests: last ? 1 : 0,
		last,
	};
}

describe("computeContextUsage", () => {
	it("derives current context from the LAST request's input + output", () => {
		const usage = computeContextUsage(
			stats({
				inputTokens: 47000,
				outputTokens: 1200,
				cacheReadTokens: 40000,
				cacheWriteTokens: 0,
			}),
			200000,
		);
		// 47000 + 1200 — NOT the cumulative totals, and cache tokens are already
		// inside inputTokens (not re-added).
		expect(usage.current).toBe(48200);
		expect(usage.max).toBe(200000);
		expect(usage.percent).toBeCloseTo(24.1, 5); // 48200 / 200000 * 100, unrounded
	});

	it("returns max=null and percent=null when the limit is unknown", () => {
		const usage = computeContextUsage(
			stats({ inputTokens: 100, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }),
			null,
		);
		expect(usage.current).toBe(100);
		expect(usage.max).toBeNull();
		expect(usage.percent).toBeNull();
	});

	it("treats a non-positive limit as unknown", () => {
		const usage = computeContextUsage(
			stats({ inputTokens: 100, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }),
			0,
		);
		expect(usage.max).toBeNull();
		expect(usage.percent).toBeNull();
	});

	it("reports zero usage when no request has completed yet", () => {
		expect(computeContextUsage(null, 200000)).toEqual({
			current: 0,
			max: 200000,
			percent: 0,
		});
		expect(computeContextUsage(stats(null), 200000)).toEqual({
			current: 0,
			max: 200000,
			percent: 0,
		});
	});

	it("clamps percent to 100 when context overflows the window", () => {
		const usage = computeContextUsage(
			stats({ inputTokens: 250000, outputTokens: 5000, cacheReadTokens: 0, cacheWriteTokens: 0 }),
			200000,
		);
		expect(usage.current).toBe(255000);
		expect(usage.percent).toBe(100);
	});

	it("keeps an unrounded percent so the UI can show 2 decimals", () => {
		const usage = computeContextUsage(
			stats({ inputTokens: 3690, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }),
			1000000,
		);
		// 3690 / 1,000,000 * 100 = 0.369 → displayed as "0.37%" (toFixed(2)).
		expect(usage.percent).toBeCloseTo(0.369, 6);
		expect((usage.percent as number).toFixed(2)).toBe("0.37");
	});
});