@zanii/blackbox 0.21.1 → 0.21.2
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/cost/index.d.ts +7 -0
- package/dist/cost/index.js +55 -12
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/cost/index.d.ts
CHANGED
|
@@ -17,6 +17,9 @@ export interface ModelPrice {
|
|
|
17
17
|
/** Audio in and out (else `input` / `output`). */
|
|
18
18
|
input_audio?: number;
|
|
19
19
|
output_audio?: number;
|
|
20
|
+
/** Image tokens in and out (else `input` / `output`): OpenAI's and Gemini's image models. */
|
|
21
|
+
input_image?: number;
|
|
22
|
+
output_image?: number;
|
|
20
23
|
/** µUSD per 1,000 web-search requests (Anthropic's server tool); absent: not priced. */
|
|
21
24
|
web_search_per_1k?: number;
|
|
22
25
|
/** Prices once the call's prompt is over `above` tokens (Gemini's >200k tier), highest first. */
|
|
@@ -56,6 +59,8 @@ export interface Tokens {
|
|
|
56
59
|
cache_write_1h?: number;
|
|
57
60
|
input_audio?: number;
|
|
58
61
|
output_audio?: number;
|
|
62
|
+
input_image?: number;
|
|
63
|
+
output_image?: number;
|
|
59
64
|
}
|
|
60
65
|
export interface CallCost {
|
|
61
66
|
seq: number;
|
|
@@ -74,6 +79,8 @@ export interface CallCost {
|
|
|
74
79
|
/** spec/cost.md §1a: the uplift applied, when one matched. */
|
|
75
80
|
uplift_percent?: number;
|
|
76
81
|
source?: "reported";
|
|
82
|
+
/** The answer carried no usage (`usage_missing`): unpriced, never counted as free. */
|
|
83
|
+
no_usage?: true;
|
|
77
84
|
}
|
|
78
85
|
export interface CostReport {
|
|
79
86
|
v: 1;
|
package/dist/cost/index.js
CHANGED
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
// Mirrors sdks/python/src/zanii_blackbox/cost.py.
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
const CLASSES = ["input", "output", "cache_read", "cache_write"];
|
|
5
|
-
const EXTRA = [
|
|
5
|
+
const EXTRA = [
|
|
6
|
+
"cache_write_1h",
|
|
7
|
+
"input_audio",
|
|
8
|
+
"output_audio",
|
|
9
|
+
"input_image",
|
|
10
|
+
"output_image",
|
|
11
|
+
];
|
|
6
12
|
const OPTIONAL_PRICES = [
|
|
7
13
|
"context_window",
|
|
8
14
|
"cache_write_1h",
|
|
9
15
|
"input_audio",
|
|
10
16
|
"output_audio",
|
|
17
|
+
"input_image",
|
|
18
|
+
"output_image",
|
|
11
19
|
"web_search_per_1k",
|
|
12
20
|
];
|
|
13
21
|
/** Parses and checks a price table; its sha256 is of the exact file bytes. */
|
|
@@ -99,12 +107,20 @@ export function tokensOf(usage) {
|
|
|
99
107
|
const cached = n("cachedContentTokenCount");
|
|
100
108
|
const audioIn = n("promptTokensDetails_AUDIO");
|
|
101
109
|
const audioOut = n("candidatesTokensDetails_AUDIO");
|
|
110
|
+
const imageIn = n("promptTokensDetails_IMAGE");
|
|
111
|
+
const imageOut = n("candidatesTokensDetails_IMAGE");
|
|
102
112
|
return extras({
|
|
103
|
-
input: Math.max(0, n("promptTokenCount") - cached - audioIn) +
|
|
104
|
-
|
|
113
|
+
input: Math.max(0, n("promptTokenCount") - cached - audioIn - imageIn) +
|
|
114
|
+
n("toolUsePromptTokenCount"),
|
|
115
|
+
output: Math.max(0, n("candidatesTokenCount") - audioOut - imageOut) + n("thoughtsTokenCount"),
|
|
105
116
|
cache_read: cached,
|
|
106
117
|
cache_write: 0,
|
|
107
|
-
}, {
|
|
118
|
+
}, {
|
|
119
|
+
input_audio: audioIn,
|
|
120
|
+
output_audio: audioOut,
|
|
121
|
+
input_image: imageIn,
|
|
122
|
+
output_image: imageOut,
|
|
123
|
+
});
|
|
108
124
|
}
|
|
109
125
|
if ("inputTokens" in usage)
|
|
110
126
|
// Bedrock Converse (spec/providers.md §5)
|
|
@@ -130,18 +146,28 @@ export function tokensOf(usage) {
|
|
|
130
146
|
// Anthropic's cache names are its own: they win over the Responses shape, since Anthropic also
|
|
131
147
|
// sends output_tokens_details (thinking_tokens) since Claude Sonnet 5
|
|
132
148
|
const anthropicCache = "cache_read_input_tokens" in usage || "cache_creation_input_tokens" in usage;
|
|
149
|
+
// OpenAI's transcriptions write input_token_details (singular); its images, image_tokens
|
|
133
150
|
if (!anthropicCache &&
|
|
134
|
-
Object.keys(usage).some((k) => k.startsWith("input_tokens_details_") ||
|
|
151
|
+
Object.keys(usage).some((k) => k.startsWith("input_tokens_details_") ||
|
|
152
|
+
k.startsWith("output_tokens_details_") ||
|
|
153
|
+
k.startsWith("input_token_details_"))) {
|
|
135
154
|
const cached = n("input_tokens_details_cached_tokens");
|
|
136
155
|
const written = n("input_tokens_details_cache_write_tokens");
|
|
137
|
-
const audioIn = n("input_tokens_details_audio_tokens");
|
|
156
|
+
const audioIn = n("input_tokens_details_audio_tokens") + n("input_token_details_audio_tokens");
|
|
138
157
|
const audioOut = n("output_tokens_details_audio_tokens");
|
|
158
|
+
const imageIn = n("input_tokens_details_image_tokens");
|
|
159
|
+
const imageOut = n("output_tokens_details_image_tokens");
|
|
139
160
|
return extras({
|
|
140
|
-
input: Math.max(0, n("input_tokens") - cached - written - audioIn),
|
|
141
|
-
output: Math.max(0, n("output_tokens") - audioOut),
|
|
161
|
+
input: Math.max(0, n("input_tokens") - cached - written - audioIn - imageIn),
|
|
162
|
+
output: Math.max(0, n("output_tokens") - audioOut - imageOut),
|
|
142
163
|
cache_read: cached,
|
|
143
164
|
cache_write: written,
|
|
144
|
-
}, {
|
|
165
|
+
}, {
|
|
166
|
+
input_audio: audioIn,
|
|
167
|
+
output_audio: audioOut,
|
|
168
|
+
input_image: imageIn,
|
|
169
|
+
output_image: imageOut,
|
|
170
|
+
});
|
|
145
171
|
}
|
|
146
172
|
// Anthropic: cache_creation_input_tokens is both lifetimes; the 1-hour part is priced apart
|
|
147
173
|
const hour = n("cache_creation_ephemeral_1h_input_tokens");
|
|
@@ -167,7 +193,12 @@ export function requestsOf(usage) {
|
|
|
167
193
|
}
|
|
168
194
|
/** A call's prompt, in tokens: what a context tier is decided on. */
|
|
169
195
|
export function promptTokens(t) {
|
|
170
|
-
return t.input +
|
|
196
|
+
return (t.input +
|
|
197
|
+
t.cache_read +
|
|
198
|
+
t.cache_write +
|
|
199
|
+
(t.cache_write_1h ?? 0) +
|
|
200
|
+
(t.input_audio ?? 0) +
|
|
201
|
+
(t.input_image ?? 0));
|
|
171
202
|
}
|
|
172
203
|
/** The prices a call pays: a context tier when its prompt is over one, then its service tier. */
|
|
173
204
|
export function effectivePrice(price, tokens, serviceTier) {
|
|
@@ -203,6 +234,8 @@ export function callMicroUsd(tokens, price, requests) {
|
|
|
203
234
|
sum += (tokens.cache_write_1h ?? 0) * (price.cache_write_1h ?? price.cache_write);
|
|
204
235
|
sum += (tokens.input_audio ?? 0) * (price.input_audio ?? price.input);
|
|
205
236
|
sum += (tokens.output_audio ?? 0) * (price.output_audio ?? price.output);
|
|
237
|
+
sum += (tokens.input_image ?? 0) * (price.input_image ?? price.input);
|
|
238
|
+
sum += (tokens.output_image ?? 0) * (price.output_image ?? price.output);
|
|
206
239
|
sum += (requests?.web_search ?? 0) * (price.web_search_per_1k ?? 0) * 1000;
|
|
207
240
|
if (!Number.isSafeInteger(sum))
|
|
208
241
|
throw new RangeError("cost overflow: tokens × price beyond 2^53");
|
|
@@ -288,9 +321,19 @@ export function sessionCost(lines, prices) {
|
|
|
288
321
|
if (replayed.has(e.meta.request_seq))
|
|
289
322
|
continue;
|
|
290
323
|
const usage = e.meta.usage;
|
|
291
|
-
if (typeof usage !== "object" || usage === null)
|
|
292
|
-
continue;
|
|
293
324
|
const model = typeof e.meta.model === "string" ? e.meta.model : null;
|
|
325
|
+
if (typeof usage !== "object" || usage === null) {
|
|
326
|
+
// an answer that said nothing of what it cost is unpriced, never silently free
|
|
327
|
+
if (e.meta.usage_missing === true)
|
|
328
|
+
calls.push({
|
|
329
|
+
seq: e.seq,
|
|
330
|
+
model,
|
|
331
|
+
tokens: { input: 0, output: 0, cache_read: 0, cache_write: 0 },
|
|
332
|
+
micro_usd: null,
|
|
333
|
+
no_usage: true,
|
|
334
|
+
});
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
294
337
|
const priced = priceCall({
|
|
295
338
|
model,
|
|
296
339
|
usage: usage,
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.21.
|
|
1
|
+
export declare const VERSION = "0.21.2";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// The SDK version, on its own so the CLI can print it without loading the whole SDK.
|
|
2
|
-
export const VERSION = "0.21.
|
|
2
|
+
export const VERSION = "0.21.2";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zanii/blackbox",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.21.
|
|
4
|
+
"version": "0.21.2",
|
|
5
5
|
"description": "The flight recorder for AI agents: sessions, a zero-loss spool, framework hooks, approvals, and offline verification of the gateway's hash-chained record.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai-agents",
|