-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathpatchWorkflowRunFields.test.ts
More file actions
92 lines (85 loc) · 2.78 KB
/
Copy pathpatchWorkflowRunFields.test.ts
File metadata and controls
92 lines (85 loc) · 2.78 KB
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
85
86
87
88
89
90
91
92
import { describe, expect, it } from "vitest";
import type { AgentUsage } from "../agents/shared.ts";
import { aggregateUsage } from "./patchWorkflowRunFields.ts";
const entry = (overrides: Partial<AgentUsage>): AgentUsage => ({
agent: "pullfrog",
inputTokens: 0,
outputTokens: 0,
...overrides,
});
describe("aggregateUsage", () => {
it("returns empty object for empty input", () => {
expect(aggregateUsage([])).toEqual({});
});
it("drops fields that sum to zero so NULL stays 'not reported'", () => {
// a run that only recorded input tokens shouldn't write zero into output/cache/cost —
// those columns stay NULL so dashboards can tell 'zero' from 'never reported'.
expect(aggregateUsage([entry({ inputTokens: 42 })])).toEqual({ inputTokens: 42 });
});
it("sums a single entry with all fields present", () => {
expect(
aggregateUsage([
entry({
inputTokens: 100,
outputTokens: 50,
cacheReadTokens: 1000,
cacheWriteTokens: 200,
costUsd: 0.12,
}),
])
).toEqual({
inputTokens: 100,
outputTokens: 50,
cacheReadTokens: 1000,
cacheWriteTokens: 200,
costUsd: 0.12,
});
});
it("sums multiple entries across agents", () => {
expect(
aggregateUsage([
entry({
agent: "claude",
inputTokens: 100,
outputTokens: 50,
cacheReadTokens: 1000,
costUsd: 0.1,
}),
entry({
agent: "pullfrog",
inputTokens: 200,
outputTokens: 80,
cacheReadTokens: 2000,
cacheWriteTokens: 300,
costUsd: 0.25,
}),
])
).toEqual({
inputTokens: 300,
outputTokens: 130,
cacheReadTokens: 3000,
cacheWriteTokens: 300,
// floating-point sum — specifying exact value documents expected precision
costUsd: 0.35,
});
});
it("treats undefined cache/cost as zero and drops when the sum is still zero", () => {
expect(
aggregateUsage([
entry({ inputTokens: 10, outputTokens: 5 }),
entry({ inputTokens: 20, outputTokens: 15 }),
])
).toEqual({ inputTokens: 30, outputTokens: 20 });
});
it("clamps individual INT fields at INT4_MAX so partial-persist cannot happen", () => {
// server-side per-field rejection would silently drop the huge column and
// keep the small ones, producing a row with a NULL for the missing metric.
// clamping client-side guarantees the wire payload is self-consistent.
const result = aggregateUsage([
entry({ inputTokens: 3_000_000_000, outputTokens: 42, cacheReadTokens: 5 }),
]);
expect(result.inputTokens).toBe(2_147_483_647);
expect(result.outputTokens).toBe(42);
expect(result.cacheReadTokens).toBe(5);
});
});