@trazum/core 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anthropic-cost.d.ts +173 -0
- package/dist/anthropic-cost.d.ts.map +1 -0
- package/dist/anthropic-cost.js +222 -0
- package/dist/anthropic-cost.js.map +1 -0
- package/dist/anthropic-usage.d.ts +192 -0
- package/dist/anthropic-usage.d.ts.map +1 -0
- package/dist/anthropic-usage.js +260 -0
- package/dist/anthropic-usage.js.map +1 -0
- package/dist/claude-code.d.ts +29 -1
- package/dist/claude-code.d.ts.map +1 -1
- package/dist/claude-code.js +33 -1
- package/dist/claude-code.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/openai-cost.d.ts +62 -0
- package/dist/openai-cost.d.ts.map +1 -0
- package/dist/openai-cost.js +151 -0
- package/dist/openai-cost.js.map +1 -0
- package/dist/openai-usage.d.ts +159 -0
- package/dist/openai-usage.d.ts.map +1 -0
- package/dist/openai-usage.js +281 -0
- package/dist/openai-usage.js.map +1 -0
- package/dist/openrouter-activity.d.ts +103 -0
- package/dist/openrouter-activity.d.ts.map +1 -0
- package/dist/openrouter-activity.js +169 -0
- package/dist/openrouter-activity.js.map +1 -0
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +25 -3
- package/dist/pricing.js.map +1 -1
- package/package.json +2 -2
- package/src/anthropic-cost.ts +303 -0
- package/src/anthropic-usage.ts +363 -0
- package/src/claude-code.ts +62 -2
- package/src/index.ts +19 -1
- package/src/openai-cost.ts +170 -0
- package/src/openai-usage.ts +353 -0
- package/src/openrouter-activity.ts +221 -0
- package/src/pricing.ts +27 -3
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the provider billed, beside what Trazum computed.
|
|
3
|
+
*
|
|
4
|
+
* The one figure nobody else gives you. Every other door here answers *what
|
|
5
|
+
* did this usage cost at these rates*; the provider answers *what did we
|
|
6
|
+
* charge you*, and the two are different questions that produce different
|
|
7
|
+
* numbers. The gap between them is the interesting part, and until this file
|
|
8
|
+
* there was nowhere to look at it.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the two are never added
|
|
11
|
+
*
|
|
12
|
+
* `docs/commands.md` already states the rule for LiteLLM's `total_cost`: a
|
|
13
|
+
* provider-billed figure is printed **beside** Trazum's and never merged into
|
|
14
|
+
* it, because two price tables summed into one number is how a report becomes
|
|
15
|
+
* quietly wrong. This file is that rule with arithmetic attached. Nothing here
|
|
16
|
+
* corrects one figure with the other, and nothing here decides which is right:
|
|
17
|
+
* they are two measurements of the same window, and the reader is the one
|
|
18
|
+
* entitled to say which they trust.
|
|
19
|
+
*
|
|
20
|
+
* ## The unit, which is the trap
|
|
21
|
+
*
|
|
22
|
+
* `amount` is **a decimal string in the currency's lowest unit**: `"123.45"`
|
|
23
|
+
* in USD is $1.2345, not $123.45. A reader of this API who takes the field for
|
|
24
|
+
* dollars overstates a bill by a hundred times, and the figure looks entirely
|
|
25
|
+
* plausible on a large organisation. It is divided by a hundred here, once, at
|
|
26
|
+
* the end, and a test asserts the factor against the schema's own example.
|
|
27
|
+
*
|
|
28
|
+
* `currency` is documented as always `USD` today. It is still checked: a
|
|
29
|
+
* converter that assumed it would be silently wrong the day it changes, and
|
|
30
|
+
* summing two currencies into one total is the same failure as summing two
|
|
31
|
+
* price tables. Anything but USD is refused rather than converted, because a
|
|
32
|
+
* conversion needs a rate and inventing one is the sin this product is built
|
|
33
|
+
* against.
|
|
34
|
+
*
|
|
35
|
+
* ## What the decomposition is for
|
|
36
|
+
*
|
|
37
|
+
* A difference nobody can attribute is a number that starts an argument. This
|
|
38
|
+
* report can attribute most of one, when it is fetched with
|
|
39
|
+
* `group_by[]=description`:
|
|
40
|
+
*
|
|
41
|
+
* - **`cost_type` other than `tokens`** — web search, code execution, session
|
|
42
|
+
* usage. Trazum prices tokens and nothing else, so every cent of these is
|
|
43
|
+
* billed money it never claimed to cover. Named rather than blamed.
|
|
44
|
+
* - **`service_tier: "batch"`** — billed at a discount `from-anthropic`
|
|
45
|
+
* deliberately leaves out rather than misprice at a catalogue rate.
|
|
46
|
+
*
|
|
47
|
+
* What is left after both is the **remainder**, and it is the only figure here
|
|
48
|
+
* worth arguing about: the same standard-tier tokens, priced two ways, or
|
|
49
|
+
* usage the log never saw. A tool that folded the remainder into one of the
|
|
50
|
+
* explanations would be hiding the only thing it was built to show.
|
|
51
|
+
*
|
|
52
|
+
* Without `group_by[]=description` none of that decomposition exists —
|
|
53
|
+
* `cost_type`, `service_tier` and `model` are all `null` — and the reading
|
|
54
|
+
* says so rather than reporting a remainder that is really the whole
|
|
55
|
+
* difference wearing a smaller name.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* What a provider charged, in the terms `reconcile` needs and no more.
|
|
59
|
+
*
|
|
60
|
+
* Two providers' reports read into it, and the difference between them is
|
|
61
|
+
* confined to the files that read them: what the money was for, whether
|
|
62
|
+
* batch can be told apart, which window, which currency.
|
|
63
|
+
*/
|
|
64
|
+
export interface BilledReading {
|
|
65
|
+
/** Everything billed in the window, in dollars. */
|
|
66
|
+
usd: number;
|
|
67
|
+
/** Billed for something no token rate covers: web search, code execution. */
|
|
68
|
+
notTokensUsd: number;
|
|
69
|
+
/** Billed at the batch tier, which a catalogue rate is not the rate for. */
|
|
70
|
+
batchUsd: number;
|
|
71
|
+
/**
|
|
72
|
+
* Whether this report can name a batch charge at all.
|
|
73
|
+
*
|
|
74
|
+
* Anthropic's can, once grouped by description. OpenAI's never does, so a
|
|
75
|
+
* batch discount there sits inside the remainder and the reader is told.
|
|
76
|
+
*/
|
|
77
|
+
batchSeparable: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Whether the report was fetched with the grouping that names each row.
|
|
80
|
+
*
|
|
81
|
+
* Without it nothing on a row says what the money was for, so neither
|
|
82
|
+
* figure above can be separated from the total and a reconciliation can
|
|
83
|
+
* only report a difference it cannot attribute.
|
|
84
|
+
*/
|
|
85
|
+
described: boolean;
|
|
86
|
+
/** The window the buckets actually cover, or `null` when there are none. */
|
|
87
|
+
window: {
|
|
88
|
+
fromMs: number;
|
|
89
|
+
toMs: number;
|
|
90
|
+
} | null;
|
|
91
|
+
/** Currencies seen that were not USD. Summing across them is refused. */
|
|
92
|
+
otherCurrencies: string[];
|
|
93
|
+
}
|
|
94
|
+
/** What Anthropic charged, read from its own report. */
|
|
95
|
+
export interface AnthropicCostReading extends BilledReading {
|
|
96
|
+
buckets: number;
|
|
97
|
+
rows: number;
|
|
98
|
+
/** Rows whose `amount` was not a number. Counted, never read as zero. */
|
|
99
|
+
unreadableAmount: number;
|
|
100
|
+
/** `has_more`: one page of several, so the billed figure is understated. */
|
|
101
|
+
truncated: boolean;
|
|
102
|
+
/** The input was not the JSON this endpoint returns. */
|
|
103
|
+
unparseable: boolean;
|
|
104
|
+
}
|
|
105
|
+
/** Two measurements of one window, and what separates them. */
|
|
106
|
+
export interface Reconciliation {
|
|
107
|
+
computedUsd: number;
|
|
108
|
+
billedUsd: number;
|
|
109
|
+
/** Billed minus computed. Positive means the provider charged more. */
|
|
110
|
+
differenceUsd: number;
|
|
111
|
+
/** The part of the difference the report itself accounts for. */
|
|
112
|
+
notTokensUsd: number;
|
|
113
|
+
batchUsd: number;
|
|
114
|
+
/**
|
|
115
|
+
* What neither figure explains: the same standard-tier tokens priced two
|
|
116
|
+
* ways, or usage the log never saw. The only number here worth arguing
|
|
117
|
+
* about, and never folded into the two above.
|
|
118
|
+
*/
|
|
119
|
+
remainderUsd: number;
|
|
120
|
+
/** `false` when the report was not grouped in a way that names its rows. */
|
|
121
|
+
attributable: boolean;
|
|
122
|
+
/** `false` when this provider's report cannot name a batch charge at all. */
|
|
123
|
+
batchSeparable: boolean;
|
|
124
|
+
/** Why the two are not comparable, when they are not. */
|
|
125
|
+
refusal: {
|
|
126
|
+
reason: 'no-billed-window';
|
|
127
|
+
} | {
|
|
128
|
+
reason: 'window-not-covered';
|
|
129
|
+
computed: {
|
|
130
|
+
fromMs: number;
|
|
131
|
+
toMs: number;
|
|
132
|
+
};
|
|
133
|
+
billed: {
|
|
134
|
+
fromMs: number;
|
|
135
|
+
toMs: number;
|
|
136
|
+
};
|
|
137
|
+
} | {
|
|
138
|
+
reason: 'other-currency';
|
|
139
|
+
currencies: string[];
|
|
140
|
+
} | null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Read a cost report. Pure, like every measuring function here, and for the
|
|
144
|
+
* same reason `anthropic-usage.ts` gives: the credential that fetches this is
|
|
145
|
+
* an admin credential, and this project holds none.
|
|
146
|
+
*/
|
|
147
|
+
export declare function anthropicCostReport(text: string): AnthropicCostReading;
|
|
148
|
+
/**
|
|
149
|
+
* Set what Trazum computed beside what the provider billed.
|
|
150
|
+
*
|
|
151
|
+
* @param computed what Trazum priced, and the window it priced.
|
|
152
|
+
*
|
|
153
|
+
* **The windows must line up or this refuses.** A receipt for September set
|
|
154
|
+
* against a bill for August is a wrong number under a right title, which is
|
|
155
|
+
* the failure this whole product is arranged against. The billed window has
|
|
156
|
+
* to contain the computed one — daily buckets are wider than a receipt's span
|
|
157
|
+
* by construction, so containment rather than equality is the honest test —
|
|
158
|
+
* and a report that starts after the first call it is being compared with is
|
|
159
|
+
* missing money nobody would see was missing.
|
|
160
|
+
*/
|
|
161
|
+
export declare function reconcile(computed: {
|
|
162
|
+
usd: number;
|
|
163
|
+
fromMs: number;
|
|
164
|
+
toMs: number;
|
|
165
|
+
}, billed: BilledReading): Reconciliation;
|
|
166
|
+
/**
|
|
167
|
+
* Whether this text is a cost report rather than some other JSON.
|
|
168
|
+
*
|
|
169
|
+
* `amount` with `currency` beside it, in a document with buckets: the usage
|
|
170
|
+
* report has neither, and a Messages response has no buckets.
|
|
171
|
+
*/
|
|
172
|
+
export declare function looksLikeAnthropicCost(text: string, prefixBytes?: number): boolean;
|
|
173
|
+
//# sourceMappingURL=anthropic-cost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-cost.d.ts","sourceRoot":"","sources":["../src/anthropic-cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChD,yEAAyE;IACzE,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,wDAAwD;AACxD,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;IACtB,6EAA6E;IAC7E,cAAc,EAAE,OAAO,CAAC;IACxB,yDAAyD;IACzD,OAAO,EACH;QAAE,MAAM,EAAE,kBAAkB,CAAA;KAAE,GAC9B;QAAE,MAAM,EAAE,oBAAoB,CAAC;QAAC,QAAQ,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,MAAM,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GACtH;QAAE,MAAM,EAAE,gBAAgB,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,GAClD,IAAI,CAAC;CACV;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CA4FtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACvD,MAAM,EAAE,aAAa,GACpB,cAAc,CAuChB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAO,GAAG,OAAO,CAIhF"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the provider billed, beside what Trazum computed.
|
|
3
|
+
*
|
|
4
|
+
* The one figure nobody else gives you. Every other door here answers *what
|
|
5
|
+
* did this usage cost at these rates*; the provider answers *what did we
|
|
6
|
+
* charge you*, and the two are different questions that produce different
|
|
7
|
+
* numbers. The gap between them is the interesting part, and until this file
|
|
8
|
+
* there was nowhere to look at it.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the two are never added
|
|
11
|
+
*
|
|
12
|
+
* `docs/commands.md` already states the rule for LiteLLM's `total_cost`: a
|
|
13
|
+
* provider-billed figure is printed **beside** Trazum's and never merged into
|
|
14
|
+
* it, because two price tables summed into one number is how a report becomes
|
|
15
|
+
* quietly wrong. This file is that rule with arithmetic attached. Nothing here
|
|
16
|
+
* corrects one figure with the other, and nothing here decides which is right:
|
|
17
|
+
* they are two measurements of the same window, and the reader is the one
|
|
18
|
+
* entitled to say which they trust.
|
|
19
|
+
*
|
|
20
|
+
* ## The unit, which is the trap
|
|
21
|
+
*
|
|
22
|
+
* `amount` is **a decimal string in the currency's lowest unit**: `"123.45"`
|
|
23
|
+
* in USD is $1.2345, not $123.45. A reader of this API who takes the field for
|
|
24
|
+
* dollars overstates a bill by a hundred times, and the figure looks entirely
|
|
25
|
+
* plausible on a large organisation. It is divided by a hundred here, once, at
|
|
26
|
+
* the end, and a test asserts the factor against the schema's own example.
|
|
27
|
+
*
|
|
28
|
+
* `currency` is documented as always `USD` today. It is still checked: a
|
|
29
|
+
* converter that assumed it would be silently wrong the day it changes, and
|
|
30
|
+
* summing two currencies into one total is the same failure as summing two
|
|
31
|
+
* price tables. Anything but USD is refused rather than converted, because a
|
|
32
|
+
* conversion needs a rate and inventing one is the sin this product is built
|
|
33
|
+
* against.
|
|
34
|
+
*
|
|
35
|
+
* ## What the decomposition is for
|
|
36
|
+
*
|
|
37
|
+
* A difference nobody can attribute is a number that starts an argument. This
|
|
38
|
+
* report can attribute most of one, when it is fetched with
|
|
39
|
+
* `group_by[]=description`:
|
|
40
|
+
*
|
|
41
|
+
* - **`cost_type` other than `tokens`** — web search, code execution, session
|
|
42
|
+
* usage. Trazum prices tokens and nothing else, so every cent of these is
|
|
43
|
+
* billed money it never claimed to cover. Named rather than blamed.
|
|
44
|
+
* - **`service_tier: "batch"`** — billed at a discount `from-anthropic`
|
|
45
|
+
* deliberately leaves out rather than misprice at a catalogue rate.
|
|
46
|
+
*
|
|
47
|
+
* What is left after both is the **remainder**, and it is the only figure here
|
|
48
|
+
* worth arguing about: the same standard-tier tokens, priced two ways, or
|
|
49
|
+
* usage the log never saw. A tool that folded the remainder into one of the
|
|
50
|
+
* explanations would be hiding the only thing it was built to show.
|
|
51
|
+
*
|
|
52
|
+
* Without `group_by[]=description` none of that decomposition exists —
|
|
53
|
+
* `cost_type`, `service_tier` and `model` are all `null` — and the reading
|
|
54
|
+
* says so rather than reporting a remainder that is really the whole
|
|
55
|
+
* difference wearing a smaller name.
|
|
56
|
+
*/
|
|
57
|
+
const asObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
58
|
+
? value
|
|
59
|
+
: null;
|
|
60
|
+
/**
|
|
61
|
+
* Read a cost report. Pure, like every measuring function here, and for the
|
|
62
|
+
* same reason `anthropic-usage.ts` gives: the credential that fetches this is
|
|
63
|
+
* an admin credential, and this project holds none.
|
|
64
|
+
*/
|
|
65
|
+
export function anthropicCostReport(text) {
|
|
66
|
+
const empty = {
|
|
67
|
+
usd: 0,
|
|
68
|
+
notTokensUsd: 0,
|
|
69
|
+
batchUsd: 0,
|
|
70
|
+
batchSeparable: false,
|
|
71
|
+
described: false,
|
|
72
|
+
window: null,
|
|
73
|
+
buckets: 0,
|
|
74
|
+
rows: 0,
|
|
75
|
+
otherCurrencies: [],
|
|
76
|
+
unreadableAmount: 0,
|
|
77
|
+
truncated: false,
|
|
78
|
+
unparseable: false,
|
|
79
|
+
};
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(text);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return { ...empty, unparseable: true };
|
|
86
|
+
}
|
|
87
|
+
const report = asObject(parsed);
|
|
88
|
+
if (report === null || !Array.isArray(report.data))
|
|
89
|
+
return { ...empty, unparseable: true };
|
|
90
|
+
/* Summed in cents and divided once, because summing a hundredth of a cent a
|
|
91
|
+
thousand times and dividing each time is a different number. */
|
|
92
|
+
let cents = 0;
|
|
93
|
+
let notTokensCents = 0;
|
|
94
|
+
let batchCents = 0;
|
|
95
|
+
let described = false;
|
|
96
|
+
let buckets = 0;
|
|
97
|
+
let rows = 0;
|
|
98
|
+
let unreadableAmount = 0;
|
|
99
|
+
let fromMs = null;
|
|
100
|
+
let toMs = null;
|
|
101
|
+
const otherCurrencies = new Set();
|
|
102
|
+
for (const entry of report.data) {
|
|
103
|
+
const bucket = asObject(entry);
|
|
104
|
+
if (bucket === null || typeof bucket.starting_at !== 'string')
|
|
105
|
+
continue;
|
|
106
|
+
buckets += 1;
|
|
107
|
+
const from = Date.parse(bucket.starting_at);
|
|
108
|
+
const to = typeof bucket.ending_at === 'string' ? Date.parse(bucket.ending_at) : Number.NaN;
|
|
109
|
+
if (Number.isFinite(from))
|
|
110
|
+
fromMs = fromMs === null ? from : Math.min(fromMs, from);
|
|
111
|
+
if (Number.isFinite(to))
|
|
112
|
+
toMs = toMs === null ? to : Math.max(toMs, to);
|
|
113
|
+
if (!Array.isArray(bucket.results))
|
|
114
|
+
continue;
|
|
115
|
+
for (const found of bucket.results) {
|
|
116
|
+
const result = asObject(found);
|
|
117
|
+
if (result === null)
|
|
118
|
+
continue;
|
|
119
|
+
rows += 1;
|
|
120
|
+
/* A currency this cannot sum stops it being summed at all, rather than
|
|
121
|
+
being quietly added to a dollar total. */
|
|
122
|
+
if (typeof result.currency === 'string' && result.currency !== 'USD') {
|
|
123
|
+
otherCurrencies.add(result.currency);
|
|
124
|
+
}
|
|
125
|
+
const amount = typeof result.amount === 'string' ? Number(result.amount) : Number.NaN;
|
|
126
|
+
if (!Number.isFinite(amount)) {
|
|
127
|
+
unreadableAmount += 1;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
cents += amount;
|
|
131
|
+
if (typeof result.cost_type === 'string') {
|
|
132
|
+
described = true;
|
|
133
|
+
if (result.cost_type !== 'tokens')
|
|
134
|
+
notTokensCents += amount;
|
|
135
|
+
}
|
|
136
|
+
if (typeof result.service_tier === 'string') {
|
|
137
|
+
described = true;
|
|
138
|
+
if (result.service_tier === 'batch')
|
|
139
|
+
batchCents += amount;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
usd: cents / 100,
|
|
145
|
+
notTokensUsd: notTokensCents / 100,
|
|
146
|
+
batchUsd: batchCents / 100,
|
|
147
|
+
batchSeparable: described,
|
|
148
|
+
described,
|
|
149
|
+
window: fromMs === null || toMs === null ? null : { fromMs, toMs },
|
|
150
|
+
buckets,
|
|
151
|
+
rows,
|
|
152
|
+
otherCurrencies: [...otherCurrencies],
|
|
153
|
+
unreadableAmount,
|
|
154
|
+
truncated: report.has_more === true,
|
|
155
|
+
unparseable: false,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Set what Trazum computed beside what the provider billed.
|
|
160
|
+
*
|
|
161
|
+
* @param computed what Trazum priced, and the window it priced.
|
|
162
|
+
*
|
|
163
|
+
* **The windows must line up or this refuses.** A receipt for September set
|
|
164
|
+
* against a bill for August is a wrong number under a right title, which is
|
|
165
|
+
* the failure this whole product is arranged against. The billed window has
|
|
166
|
+
* to contain the computed one — daily buckets are wider than a receipt's span
|
|
167
|
+
* by construction, so containment rather than equality is the honest test —
|
|
168
|
+
* and a report that starts after the first call it is being compared with is
|
|
169
|
+
* missing money nobody would see was missing.
|
|
170
|
+
*/
|
|
171
|
+
export function reconcile(computed, billed) {
|
|
172
|
+
const bare = {
|
|
173
|
+
computedUsd: computed.usd,
|
|
174
|
+
billedUsd: billed.usd,
|
|
175
|
+
differenceUsd: billed.usd - computed.usd,
|
|
176
|
+
notTokensUsd: billed.notTokensUsd,
|
|
177
|
+
batchUsd: billed.batchUsd,
|
|
178
|
+
remainderUsd: 0,
|
|
179
|
+
attributable: billed.described,
|
|
180
|
+
batchSeparable: billed.batchSeparable,
|
|
181
|
+
};
|
|
182
|
+
if (billed.otherCurrencies.length > 0) {
|
|
183
|
+
return { ...bare, refusal: { reason: 'other-currency', currencies: billed.otherCurrencies } };
|
|
184
|
+
}
|
|
185
|
+
if (billed.window === null)
|
|
186
|
+
return { ...bare, refusal: { reason: 'no-billed-window' } };
|
|
187
|
+
if (billed.window.fromMs > computed.fromMs || billed.window.toMs < computed.toMs) {
|
|
188
|
+
return {
|
|
189
|
+
...bare,
|
|
190
|
+
refusal: {
|
|
191
|
+
reason: 'window-not-covered',
|
|
192
|
+
computed: { fromMs: computed.fromMs, toMs: computed.toMs },
|
|
193
|
+
billed: billed.window,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/*
|
|
198
|
+
The remainder is what is left when the report's own explanations are taken
|
|
199
|
+
out of the difference, and it is deliberately not clamped at zero. A
|
|
200
|
+
negative one is a real answer -- Trazum priced more than the provider
|
|
201
|
+
charged -- and reporting it as zero would hide a stale rate in exactly the
|
|
202
|
+
direction that costs somebody money.
|
|
203
|
+
*/
|
|
204
|
+
return {
|
|
205
|
+
...bare,
|
|
206
|
+
remainderUsd: bare.differenceUsd - billed.notTokensUsd - billed.batchUsd,
|
|
207
|
+
refusal: null,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Whether this text is a cost report rather than some other JSON.
|
|
212
|
+
*
|
|
213
|
+
* `amount` with `currency` beside it, in a document with buckets: the usage
|
|
214
|
+
* report has neither, and a Messages response has no buckets.
|
|
215
|
+
*/
|
|
216
|
+
export function looksLikeAnthropicCost(text, prefixBytes = 8192) {
|
|
217
|
+
const head = text.slice(0, prefixBytes);
|
|
218
|
+
if (!head.includes('"amount"') || !head.includes('"currency"'))
|
|
219
|
+
return false;
|
|
220
|
+
return head.includes('"starting_at"') || head.includes('"has_more"');
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=anthropic-cost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-cost.js","sourceRoot":"","sources":["../src/anthropic-cost.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic's own usage report, read as a usage log.
|
|
3
|
+
*
|
|
4
|
+
* The fifth converter in the pattern `from-claude-code` started, and the first
|
|
5
|
+
* one that reads a **provider** rather than a tool sitting in front of one.
|
|
6
|
+
* Every other converter answers *what did the calls my proxy saw cost*; this
|
|
7
|
+
* one answers *what does the provider say my organisation used*, which is the
|
|
8
|
+
* question a finance team asks and the one no local log can answer, because a
|
|
9
|
+
* log only knows the machines it was written on.
|
|
10
|
+
*
|
|
11
|
+
* ## Why this takes a file and not a key
|
|
12
|
+
*
|
|
13
|
+
* The Usage & Cost API needs an **admin** credential: an `sk-ant-admin01-…`
|
|
14
|
+
* key, an `org:admin` OAuth token, or an unscoped personal or service account
|
|
15
|
+
* key. Workspace keys do not work. That credential can read every workspace's
|
|
16
|
+
* usage and manage the organisation's members and keys, which makes it exactly
|
|
17
|
+
* the kind of secret this project has spent its whole design not holding.
|
|
18
|
+
*
|
|
19
|
+
* So this function takes the **response**, not the credential. The operator
|
|
20
|
+
* runs one `curl` with their own key, in their own shell, and pipes the JSON
|
|
21
|
+
* here. Trazum never sees the key, never makes the request, and stays a pure
|
|
22
|
+
* function of text — which is also why this file can be tested without a
|
|
23
|
+
* network and why the deterministic core is still deterministic.
|
|
24
|
+
*
|
|
25
|
+
* ## The format is derived, not guessed
|
|
26
|
+
*
|
|
27
|
+
* Every field below is from the published response schema of
|
|
28
|
+
* `GET /v1/organizations/usage_report/messages`: `data[]` of time buckets with
|
|
29
|
+
* `starting_at`, `ending_at` and `results[]`, and each result carrying
|
|
30
|
+
* `uncached_input_tokens`, `cache_read_input_tokens`, `cache_creation`
|
|
31
|
+
* (`ephemeral_5m_input_tokens`, `ephemeral_1h_input_tokens`), `output_tokens`,
|
|
32
|
+
* `model`, `service_tier` and `server_tool_use.web_search_requests`.
|
|
33
|
+
*
|
|
34
|
+
* The cache shape needs no translation at all: `parseUsageLine` already reads
|
|
35
|
+
* `cache_creation.ephemeral_5m_input_tokens` and its 1-hour sibling, because
|
|
36
|
+
* that is the shape the Messages API itself returns. The one rename is
|
|
37
|
+
* `uncached_input_tokens` to `input_tokens`, and it is a rename rather than a
|
|
38
|
+
* sum: this report reports cached reads **beside** the uncached input rather
|
|
39
|
+
* than folded into it, which is the Anthropic shape and not the OpenAI one.
|
|
40
|
+
*
|
|
41
|
+
* ## What it refuses to price, and counts instead
|
|
42
|
+
*
|
|
43
|
+
* **A result with no model.** `model` is `null` unless the caller passed
|
|
44
|
+
* `group_by[]=model`. Nothing on a row without it says what answered, so
|
|
45
|
+
* nothing can price it. Refused, counted, and the count names the missing
|
|
46
|
+
* parameter — a converter that quietly returned an empty log would send
|
|
47
|
+
* somebody looking for a bug in their key.
|
|
48
|
+
*
|
|
49
|
+
* **A non-standard service tier.** Batch is billed at a discount and priority
|
|
50
|
+
* is not billed like either; a catalogue rate is the standard rate. Pricing a
|
|
51
|
+
* batch row from it would overstate a bill by half and look right doing it,
|
|
52
|
+
* which is this product's one unforgivable failure. Those rows are left out
|
|
53
|
+
* and counted, the same way an unpriceable line becomes a named gap rather
|
|
54
|
+
* than a guess.
|
|
55
|
+
*
|
|
56
|
+
* **Web search requests.** `server_tool_use.web_search_requests` is billed per
|
|
57
|
+
* request, not per token, so no token rate reaches it. Counted and named, so a
|
|
58
|
+
* total that is missing them says so.
|
|
59
|
+
*
|
|
60
|
+
* **A truncated report.** `has_more: true` means the answer is one page of
|
|
61
|
+
* several, and a bill built from one page is understated by however many pages
|
|
62
|
+
* were not asked for. Said out loud rather than left for somebody to notice in
|
|
63
|
+
* a figure.
|
|
64
|
+
*
|
|
65
|
+
* ## What deliberately does not cross
|
|
66
|
+
*
|
|
67
|
+
* `account_id`, `service_account_id` and `api_key_id` are read by nothing
|
|
68
|
+
* here. The first two name people; the third names a credential. None of them
|
|
69
|
+
* is a project name and none of them reaches the output.
|
|
70
|
+
*
|
|
71
|
+
* `workspace_id` is read only when the operator hands over a mapping, because
|
|
72
|
+
* a workspace id is not a project name and turning one into the other is a
|
|
73
|
+
* decision rather than an inference. `labelByWorkspace` is that decision,
|
|
74
|
+
* written down: the same shape `--label-by-cwd` established for transcripts,
|
|
75
|
+
* exact rather than prefixed, because an opaque identifier has no hierarchy
|
|
76
|
+
* to take the longest match of.
|
|
77
|
+
*
|
|
78
|
+
* ## The `null` that means two things, and how it is told apart
|
|
79
|
+
*
|
|
80
|
+
* The report's own schema says `workspace_id` is `null` **both** when the
|
|
81
|
+
* caller did not group by workspace **and** for the default workspace. One
|
|
82
|
+
* value, two meanings, and a mapping that guessed between them would put the
|
|
83
|
+
* default workspace's money on a label nobody chose or leave it off one they
|
|
84
|
+
* did.
|
|
85
|
+
*
|
|
86
|
+
* It is derived instead: if any result in the report carries a workspace id,
|
|
87
|
+
* the report was grouped, and a `null` there is the default workspace — so a
|
|
88
|
+
* rule written for `null` applies to it. If no result carries one, nothing
|
|
89
|
+
* distinguishes the two readings, `null` rules do not apply, and the
|
|
90
|
+
* conversion says the split was asked for and could not be made.
|
|
91
|
+
*
|
|
92
|
+
* ## The instant, and why it is the bucket's
|
|
93
|
+
*
|
|
94
|
+
* This report has no calls in it. A bucket is an interval and its usage is a
|
|
95
|
+
* sum over that interval, so every record made from it carries the bucket's
|
|
96
|
+
* `starting_at` — a day's usage at that day's start, an hour's at the hour's.
|
|
97
|
+
* Anything finer would be a precision the source does not have, and
|
|
98
|
+
* `bucket_width=1h` is there for an operator who wants it.
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* One workspace, and the project name the operator gives it.
|
|
102
|
+
*
|
|
103
|
+
* Matched exactly, never by prefix: a workspace id is opaque and two of them
|
|
104
|
+
* sharing leading characters share nothing at all. `null` names the default
|
|
105
|
+
* workspace, which is the only workspace the report identifies by absence.
|
|
106
|
+
*/
|
|
107
|
+
export interface WorkspaceLabel {
|
|
108
|
+
workspace: string | null;
|
|
109
|
+
label: string;
|
|
110
|
+
}
|
|
111
|
+
/** One converted record, shaped exactly as `parseUsageLine` reads it. */
|
|
112
|
+
export interface AnthropicUsageRecord {
|
|
113
|
+
model: string;
|
|
114
|
+
ts: string;
|
|
115
|
+
label?: string;
|
|
116
|
+
usage: {
|
|
117
|
+
input_tokens: number;
|
|
118
|
+
output_tokens: number;
|
|
119
|
+
cache_read_input_tokens?: number;
|
|
120
|
+
cache_creation?: {
|
|
121
|
+
ephemeral_5m_input_tokens: number;
|
|
122
|
+
ephemeral_1h_input_tokens: number;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export interface AnthropicUsageConversion {
|
|
127
|
+
records: AnthropicUsageRecord[];
|
|
128
|
+
/** Time buckets in the report, including intervals with no usage. */
|
|
129
|
+
buckets: number;
|
|
130
|
+
/** Results that became records. */
|
|
131
|
+
rows: number;
|
|
132
|
+
/** Results with `model: null`, which nothing can price. */
|
|
133
|
+
unnamedModel: number;
|
|
134
|
+
/** Results at a tier a standard rate would misprice. */
|
|
135
|
+
nonStandardTier: number;
|
|
136
|
+
/**
|
|
137
|
+
* Whether any result named its tier at all.
|
|
138
|
+
*
|
|
139
|
+
* `false` means the report was not grouped by `service_tier`, so a batch row
|
|
140
|
+
* and a standard row are indistinguishable here and the discount, if any,
|
|
141
|
+
* is invisible. Not an error and not a refusal: most organisations run
|
|
142
|
+
* standard only. It is said because the alternative is a reader assuming a
|
|
143
|
+
* question was answered that was never asked.
|
|
144
|
+
*/
|
|
145
|
+
tierNamed: boolean;
|
|
146
|
+
/** Server-side tool calls billed per request, which no token rate prices. */
|
|
147
|
+
webSearchRequests: number;
|
|
148
|
+
/** `has_more`: this is one page and the bill from it is understated. */
|
|
149
|
+
truncated: boolean;
|
|
150
|
+
/** Records whose label came from a workspace rule rather than `--label`. */
|
|
151
|
+
labelledByWorkspace: number;
|
|
152
|
+
/**
|
|
153
|
+
* Results carrying a workspace no rule named.
|
|
154
|
+
*
|
|
155
|
+
* They keep `--label` if there is one and go unattributed if there is not,
|
|
156
|
+
* which is the same fallback `--label-by-cwd` makes: a workspace nobody
|
|
157
|
+
* wrote a rule for is unattributed rather than attributed to a neighbour.
|
|
158
|
+
*/
|
|
159
|
+
unruledWorkspace: number;
|
|
160
|
+
/**
|
|
161
|
+
* Rules were given and no result carried a workspace id.
|
|
162
|
+
*
|
|
163
|
+
* Either the report was not grouped by workspace or this organisation uses
|
|
164
|
+
* only the default one, and nothing here can tell those apart. The split
|
|
165
|
+
* asked for was not made, and that is said rather than left to be noticed.
|
|
166
|
+
*/
|
|
167
|
+
workspaceNotGrouped: boolean;
|
|
168
|
+
/** The input was not the JSON this endpoint returns. */
|
|
169
|
+
unparseable: number;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* @param label the project this usage belongs to, chosen by the operator.
|
|
173
|
+
*
|
|
174
|
+
* Optional, and absent means the records carry none — the unattributed bucket
|
|
175
|
+
* every other door already understands. The provider does not know this
|
|
176
|
+
* organisation's project names and neither does this file.
|
|
177
|
+
*/
|
|
178
|
+
export declare function anthropicUsageRecords(text: string, options?: {
|
|
179
|
+
label?: string;
|
|
180
|
+
labelByWorkspace?: readonly WorkspaceLabel[];
|
|
181
|
+
}): AnthropicUsageConversion;
|
|
182
|
+
/**
|
|
183
|
+
* Whether this text is an Anthropic usage report rather than some other JSON.
|
|
184
|
+
*
|
|
185
|
+
* Three fields together, because each alone is too common to decide on:
|
|
186
|
+
* `uncached_input_tokens` is this endpoint's own name for a count every other
|
|
187
|
+
* shape calls something else, and a report always carries buckets with a
|
|
188
|
+
* `starting_at`. A sniffer that matched on `output_tokens` alone would claim
|
|
189
|
+
* every Messages response ever saved to a file.
|
|
190
|
+
*/
|
|
191
|
+
export declare function looksLikeAnthropicUsage(text: string, prefixBytes?: number): boolean;
|
|
192
|
+
//# sourceMappingURL=anthropic-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-usage.d.ts","sourceRoot":"","sources":["../src/anthropic-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkGG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,cAAc,CAAC,EAAE;YACf,yBAAyB,EAAE,MAAM,CAAC;YAClC,yBAAyB,EAAE,MAAM,CAAC;SACnC,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAC7B,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;CACrB;AAKD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;CAAO,GAC7E,wBAAwB,CAgK1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAO,GAAG,OAAO,CAIjF"}
|