108 lines
3.2 KiB
TypeScript
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,
|
|
});
|
|
});
|