Files

108 lines
3.2 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { contextOccupancyTokens } from "./src/backends/claude.ts";
import { parseThreadTokenUsage } from "./src/backends/codex.ts";
// --- Claude: per-request occupancy, never the run aggregate ------------------
test("Claude occupancy sums one request's input, cache, and output tokens", () => {
assert.equal(
contextOccupancyTokens({
input_tokens: 12,
cache_read_input_tokens: 45_000,
cache_creation_input_tokens: 3_000,
output_tokens: 700,
}),
48_712,
);
});
test("Claude occupancy treats null cache/output counts as zero", () => {
assert.equal(
contextOccupancyTokens({
input_tokens: 9_000,
cache_read_input_tokens: null,
cache_creation_input_tokens: null,
output_tokens: 250,
}),
9_250,
);
});
test("Claude occupancy is unknown without a usable per-request usage", () => {
assert.equal(contextOccupancyTokens(undefined), undefined);
assert.equal(contextOccupancyTokens(null), undefined);
assert.equal(
contextOccupancyTokens({ input_tokens: null, output_tokens: 5 }),
undefined,
);
});
test("Claude occupancy from the last request stays below the window where the run aggregate would not", () => {
// A 10-request tool loop over a mostly-cached 150k prompt: the aggregate
// usage (what SDKResultMessage.usage reports) re-counts the cache per
// request and blows past the 200k window; the final request's usage is the
// true occupancy.
const perRequest = {
input_tokens: 500,
cache_read_input_tokens: 150_000,
cache_creation_input_tokens: 0,
output_tokens: 400,
};
const aggregate = {
input_tokens: 500 * 10,
cache_read_input_tokens: 150_000 * 10,
cache_creation_input_tokens: 0,
output_tokens: 400 * 10,
};
const occupancy = contextOccupancyTokens(perRequest);
assert.ok(occupancy !== undefined && occupancy < 200_000);
const misleading = contextOccupancyTokens(aggregate);
assert.ok(misleading !== undefined && misleading > 200_000);
});
// --- Codex: last request's total, never the thread-cumulative total ----------
const codexParams = (tokenUsage: unknown) => ({
threadId: "t",
turnId: "u",
tokenUsage,
});
test("Codex occupancy uses tokenUsage.last.totalTokens, not the cumulative total", () => {
const { tokens, contextWindow } = parseThreadTokenUsage(
codexParams({
total: {
totalTokens: 1_450_000,
inputTokens: 1_400_000,
cachedInputTokens: 1_300_000,
outputTokens: 50_000,
reasoningOutputTokens: 20_000,
},
last: {
totalTokens: 61_000,
inputTokens: 60_000,
cachedInputTokens: 55_000,
outputTokens: 1_000,
reasoningOutputTokens: 400,
},
modelContextWindow: 272_000,
}),
);
assert.equal(tokens, 61_000);
assert.equal(contextWindow, 272_000);
});
test("Codex occupancy is unknown when last usage or window is absent", () => {
assert.deepEqual(
parseThreadTokenUsage(
codexParams({ total: { totalTokens: 10 }, modelContextWindow: null }),
),
{ tokens: undefined, contextWindow: undefined },
);
assert.deepEqual(parseThreadTokenUsage({ threadId: "t" }), {
tokens: undefined,
contextWindow: undefined,
});
});