@zanii/blackbox 0.13.0 → 0.14.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/README.md +6 -0
- package/dist/billing/index.d.ts +6 -0
- package/dist/billing/index.js +10 -1
- package/dist/cli.js +24 -3
- package/dist/cost/index.d.ts +18 -0
- package/dist/cost/index.js +37 -1
- package/dist/money/index.d.ts +17 -1
- package/dist/money/index.js +48 -5
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,12 @@ verifyAnswerCredential(credential, lines, bodies, packs); // { ok, problems }: t
|
|
|
83
83
|
|
|
84
84
|
The same checks run offline as pure functions: `toolHallucinations`, `groundingFindings`, `factsIn`, `loadReferencePacks`, `answerRisk`, `detectorAccuracy`.
|
|
85
85
|
|
|
86
|
+
## New in 0.14.0
|
|
87
|
+
|
|
88
|
+
- Price uplifts (`uplifts` in a price table): US-only inference, regional endpoints and fast modes priced above list, per deployment (`upliftPercent`).
|
|
89
|
+
- Statements in any currency: the `fx:<CUR>:<rate>` unit, `fxRate(currency)` (the ECB's rate through Frankfurter), and `blackbox statement --currency EUR` with the rate, date and source in the statement.
|
|
90
|
+
- Tax invoices for zero-rated and reverse-charge customers (`vat_treatment`).
|
|
91
|
+
|
|
86
92
|
## New in 0.13.0
|
|
87
93
|
|
|
88
94
|
- `fromOtlp(body)`: OpenTelemetry spans (GenAI semconv or OpenInference) as session events, the mapping behind gateway v0.15's `POST /v1/traces`. Point any framework's OTLP exporter at the gateway with the session's token, and its spans join the record.
|
package/dist/billing/index.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface Plans {
|
|
|
31
31
|
}
|
|
32
32
|
/** Parses a plans file (spec/billing.md §1); throws on anything that isn't integer fils. */
|
|
33
33
|
export declare function loadPlans(bytes: Uint8Array): Plans;
|
|
34
|
+
/** spec/billing.md §5b: how VAT applies to a customer. */
|
|
35
|
+
export type VatTreatment = "standard" | "zero_rated" | "reverse_charge";
|
|
34
36
|
export interface TaxInvoiceInput {
|
|
35
37
|
number: string;
|
|
36
38
|
issued_at: string;
|
|
@@ -53,6 +55,8 @@ export interface TaxInvoiceInput {
|
|
|
53
55
|
sessions: number;
|
|
54
56
|
};
|
|
55
57
|
vat_percent?: number;
|
|
58
|
+
/** §5b: `zero_rated` and `reverse_charge` invoice VAT at 0%, with a note saying why. */
|
|
59
|
+
vat_treatment?: VatTreatment;
|
|
56
60
|
}
|
|
57
61
|
/** spec/billing.md §5: the tax invoice document. */
|
|
58
62
|
export declare function taxInvoice(input: TaxInvoiceInput): {
|
|
@@ -90,6 +94,8 @@ export declare function taxInvoice(input: TaxInvoiceInput): {
|
|
|
90
94
|
events: number;
|
|
91
95
|
sessions: number;
|
|
92
96
|
};
|
|
97
|
+
vat_treatment?: "reverse_charge" | "zero_rated";
|
|
98
|
+
vat_note?: string;
|
|
93
99
|
total_aed: string;
|
|
94
100
|
};
|
|
95
101
|
export type TaxInvoice = ReturnType<typeof taxInvoice>;
|
package/dist/billing/index.js
CHANGED
|
@@ -69,6 +69,10 @@ export function loadPlans(bytes) {
|
|
|
69
69
|
}
|
|
70
70
|
return doc;
|
|
71
71
|
}
|
|
72
|
+
const VAT_NOTES = {
|
|
73
|
+
zero_rated: "Zero-rated supply (export of services): VAT at 0%",
|
|
74
|
+
reverse_charge: "Reverse charge: the customer accounts for the VAT",
|
|
75
|
+
};
|
|
72
76
|
/** The month's `[from, to)` and its last day (spec/billing.md §5). */
|
|
73
77
|
function period(month) {
|
|
74
78
|
const [y, m] = month.split("-").map(Number);
|
|
@@ -79,7 +83,8 @@ function period(month) {
|
|
|
79
83
|
/** spec/billing.md §5: the tax invoice document. */
|
|
80
84
|
export function taxInvoice(input) {
|
|
81
85
|
const p = period(input.month);
|
|
82
|
-
const
|
|
86
|
+
const treatment = input.vat_treatment ?? "standard";
|
|
87
|
+
const inv = invoice(input.plan, input.usage, treatment === "standard" ? (input.vat_percent ?? 5) : 0);
|
|
83
88
|
return {
|
|
84
89
|
v: 1,
|
|
85
90
|
title: "Tax Invoice",
|
|
@@ -101,6 +106,9 @@ export function taxInvoice(input) {
|
|
|
101
106
|
plan: { id: input.plan_id, name: input.plan.name, version: input.plans_version },
|
|
102
107
|
usage: { events: input.usage.events, sessions: input.usage.sessions },
|
|
103
108
|
...inv,
|
|
109
|
+
...(treatment !== "standard"
|
|
110
|
+
? { vat_treatment: treatment, vat_note: VAT_NOTES[treatment] }
|
|
111
|
+
: {}),
|
|
104
112
|
total_aed: formatAed(inv.total_fils),
|
|
105
113
|
};
|
|
106
114
|
}
|
|
@@ -146,6 +154,7 @@ export function renderTaxInvoice(d) {
|
|
|
146
154
|
`| VAT ${d.vat_percent}% | ${aed(d.vat_fils)} |`,
|
|
147
155
|
`| **Total** | **${aed(d.total_fils)}** |`,
|
|
148
156
|
"",
|
|
157
|
+
...(d.vat_note ? [`VAT: ${d.vat_note}.`, ""] : []),
|
|
149
158
|
`Plan: ${oneLine(d.plan.name)} (${d.plan.id}, plans ${d.plan.version}). Usage: ${grouped(d.usage.events)} events, ${grouped(d.usage.sessions)} sessions.`,
|
|
150
159
|
"",
|
|
151
160
|
];
|
package/dist/cli.js
CHANGED
|
@@ -43,7 +43,7 @@ const USAGE = `usage (spec/cli.md):
|
|
|
43
43
|
blackbox policy-from-zanii <zanii-policy.json> [--out <file>]
|
|
44
44
|
blackbox policy-to-zanii <policy.json> [--out <file>]
|
|
45
45
|
blackbox statement --provider anthropic|openai --from <YYYY-MM-DD> --to <YYYY-MM-DD> [--out <file>]
|
|
46
|
-
blackbox statement --provider csv --file <f> --model-column <name> --amount-column <name> --unit usd|cents|micro_usd|aed [--delimiter <c>] --from <d> --to <d> [--out <file>]
|
|
46
|
+
blackbox statement --provider csv --file <f> --model-column <name> --amount-column <name> (--unit usd|cents|micro_usd|aed | --currency <CUR> [--rate <usd per unit>] [--rate-date <d>]) [--delimiter <c>] --from <d> --to <d> [--out <file>]
|
|
47
47
|
blackbox statement --provider custom --connector <file> --from <d> --to <d> [--out <file>]
|
|
48
48
|
blackbox preflight --require <items> [--optional <items>]
|
|
49
49
|
blackbox --version
|
|
@@ -956,8 +956,29 @@ async function statementAny(provider, flags, from, to) {
|
|
|
956
956
|
if (provider === "csv") {
|
|
957
957
|
const model = flags["model-column"];
|
|
958
958
|
const amount = flags["amount-column"];
|
|
959
|
-
|
|
959
|
+
let unit = flags.unit;
|
|
960
960
|
const delimiter = flags.delimiter;
|
|
961
|
+
// spec/money.md §2c: another currency, at a stated rate or the ECB's for the day
|
|
962
|
+
let fx;
|
|
963
|
+
if (flags.currency) {
|
|
964
|
+
try {
|
|
965
|
+
fx = flags.rate
|
|
966
|
+
? {
|
|
967
|
+
currency: flags.currency,
|
|
968
|
+
usd_per_unit: flags.rate,
|
|
969
|
+
date: flags["rate-date"] ?? to,
|
|
970
|
+
source: "stated",
|
|
971
|
+
}
|
|
972
|
+
: await money.fxRate(flags.currency, {
|
|
973
|
+
...(flags["rate-date"] ? { date: flags["rate-date"] } : {}),
|
|
974
|
+
...(process.env.BLACKBOX_FX_URL ? { url: process.env.BLACKBOX_FX_URL } : {}),
|
|
975
|
+
});
|
|
976
|
+
unit = money.fxUnit(fx.currency, fx.usd_per_unit);
|
|
977
|
+
}
|
|
978
|
+
catch (e) {
|
|
979
|
+
return message(e);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
961
982
|
if (!flags.file ||
|
|
962
983
|
!model ||
|
|
963
984
|
!amount ||
|
|
@@ -972,7 +993,7 @@ async function statementAny(provider, flags, from, to) {
|
|
|
972
993
|
unit,
|
|
973
994
|
...(delimiter ? { delimiter } : {}),
|
|
974
995
|
});
|
|
975
|
-
return { doc: { provider: "csv", from, to, lines: statement.lines } };
|
|
996
|
+
return { doc: { provider: "csv", from, to, lines: statement.lines, ...(fx ? { fx } : {}) } };
|
|
976
997
|
}
|
|
977
998
|
catch (e) {
|
|
978
999
|
return message(e);
|
package/dist/cost/index.d.ts
CHANGED
|
@@ -33,6 +33,19 @@ export interface PriceTable {
|
|
|
33
33
|
currency: "USD";
|
|
34
34
|
unit: "micro_usd_per_mtok";
|
|
35
35
|
models: Record<string, ModelPrice>;
|
|
36
|
+
/** spec/cost.md §1a: percentages added to a call's table price when it matches. */
|
|
37
|
+
uplifts?: Uplift[];
|
|
38
|
+
}
|
|
39
|
+
/** spec/cost.md §1a: a call that matches every condition given costs `percent` more. */
|
|
40
|
+
export interface Uplift {
|
|
41
|
+
/** The configured provider id the call went to (`bedrock-eu`). */
|
|
42
|
+
provider?: string;
|
|
43
|
+
/** A model id prefix (`claude-opus-5`). */
|
|
44
|
+
model?: string;
|
|
45
|
+
/** Flattened usage fields and the values they must have (`{"inference_geo": "us"}`). */
|
|
46
|
+
usage?: Record<string, string>;
|
|
47
|
+
percent: number;
|
|
48
|
+
note?: string;
|
|
36
49
|
}
|
|
37
50
|
export interface Tokens {
|
|
38
51
|
input: number;
|
|
@@ -58,6 +71,8 @@ export interface CallCost {
|
|
|
58
71
|
service?: string;
|
|
59
72
|
context_above?: number;
|
|
60
73
|
};
|
|
74
|
+
/** spec/cost.md §1a: the uplift applied, when one matched. */
|
|
75
|
+
uplift_percent?: number;
|
|
61
76
|
source?: "reported";
|
|
62
77
|
}
|
|
63
78
|
export interface CostReport {
|
|
@@ -126,6 +141,9 @@ export declare function priceCall(call: {
|
|
|
126
141
|
}, table: PriceTable): Omit<CallCost, "seq" | "model"> & {
|
|
127
142
|
key: string | null;
|
|
128
143
|
};
|
|
144
|
+
/** spec/cost.md §1a: the sum of the uplifts a call matches (0 when none): its provider, a model
|
|
145
|
+
* prefix, and usage fields, each only when the uplift names it. */
|
|
146
|
+
export declare function upliftPercent(table: PriceTable, provider: string | null, model: string, usage: Record<string, unknown>): number;
|
|
129
147
|
/** fils at the CBUAE peg (3.6725 AED / USD), rounded half up. */
|
|
130
148
|
export declare function toAedFils(microUsd: number): number;
|
|
131
149
|
export declare function formatAed(fils: number): string;
|
package/dist/cost/index.js
CHANGED
|
@@ -40,6 +40,24 @@ export function loadPrices(bytes) {
|
|
|
40
40
|
if (p.status !== undefined && p.status !== "deprecated" && p.status !== "beta")
|
|
41
41
|
throw new Error(`price table: ${model}.status must be deprecated or beta`);
|
|
42
42
|
}
|
|
43
|
+
if (table.uplifts !== undefined) {
|
|
44
|
+
if (!Array.isArray(table.uplifts))
|
|
45
|
+
throw new Error("price table: uplifts must be a list");
|
|
46
|
+
for (const [i, u] of table.uplifts.entries()) {
|
|
47
|
+
const at = `price table: uplifts[${i}]`;
|
|
48
|
+
if (!Number.isSafeInteger(u?.percent) || u.percent < 1 || u.percent > 1000)
|
|
49
|
+
throw new Error(`${at}.percent must be an integer 1-1000`);
|
|
50
|
+
if (u.provider !== undefined && typeof u.provider !== "string")
|
|
51
|
+
throw new Error(`${at}.provider must be a string`);
|
|
52
|
+
if (u.model !== undefined && typeof u.model !== "string")
|
|
53
|
+
throw new Error(`${at}.model must be a string`);
|
|
54
|
+
if (u.usage !== undefined &&
|
|
55
|
+
(typeof u.usage !== "object" ||
|
|
56
|
+
u.usage === null ||
|
|
57
|
+
Object.values(u.usage).some((v) => typeof v !== "string")))
|
|
58
|
+
throw new Error(`${at}.usage must map usage fields to strings`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
43
61
|
return { table, sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}` };
|
|
44
62
|
}
|
|
45
63
|
/** The exact model, else the longest table key the model starts with; null when there's none. */
|
|
@@ -194,12 +212,15 @@ export function priceCall(call, table) {
|
|
|
194
212
|
const match = call.model === null ? null : priceFor(call.model, table, call.provider);
|
|
195
213
|
if (match) {
|
|
196
214
|
const { price, tier } = effectivePrice(match.price, tokens, call.serviceTier);
|
|
215
|
+
const base = callMicroUsd(tokens, price, requests);
|
|
216
|
+
const uplift = upliftPercent(table, call.provider ?? null, call.model, call.usage);
|
|
197
217
|
return {
|
|
198
218
|
key: match.key,
|
|
199
219
|
tokens,
|
|
200
|
-
micro_usd:
|
|
220
|
+
micro_usd: uplift ? Math.floor((base * (100 + uplift) + 50) / 100) : base,
|
|
201
221
|
...(requests ? { requests } : {}),
|
|
202
222
|
...(tier ? { tier } : {}),
|
|
223
|
+
...(uplift ? { uplift_percent: uplift } : {}),
|
|
203
224
|
};
|
|
204
225
|
}
|
|
205
226
|
if (typeof call.reportedMicroUsd === "number")
|
|
@@ -212,6 +233,21 @@ export function priceCall(call, table) {
|
|
|
212
233
|
};
|
|
213
234
|
return { key: null, tokens, micro_usd: null, ...(requests ? { requests } : {}) };
|
|
214
235
|
}
|
|
236
|
+
/** spec/cost.md §1a: the sum of the uplifts a call matches (0 when none): its provider, a model
|
|
237
|
+
* prefix, and usage fields, each only when the uplift names it. */
|
|
238
|
+
export function upliftPercent(table, provider, model, usage) {
|
|
239
|
+
let percent = 0;
|
|
240
|
+
for (const u of table.uplifts ?? []) {
|
|
241
|
+
if (u.provider !== undefined && u.provider !== provider)
|
|
242
|
+
continue;
|
|
243
|
+
if (u.model !== undefined && !model.startsWith(u.model))
|
|
244
|
+
continue;
|
|
245
|
+
if (u.usage && Object.entries(u.usage).some(([k, v]) => String(usage[k] ?? "") !== v))
|
|
246
|
+
continue;
|
|
247
|
+
percent += u.percent;
|
|
248
|
+
}
|
|
249
|
+
return percent;
|
|
250
|
+
}
|
|
215
251
|
/** fils at the CBUAE peg (3.6725 AED / USD), rounded half up. */
|
|
216
252
|
export function toAedFils(microUsd) {
|
|
217
253
|
return Math.floor((microUsd * 36725 + 50_000_000) / 100_000_000);
|
package/dist/money/index.d.ts
CHANGED
|
@@ -45,7 +45,23 @@ export declare function fuel(summary: Summary, budgetMicroUsd: number | null, ba
|
|
|
45
45
|
p90_total_micro_usd: number | null;
|
|
46
46
|
verdict: string;
|
|
47
47
|
};
|
|
48
|
-
|
|
48
|
+
/** `fx:<ISO code>:<USD per unit>` (`fx:EUR:1.0821`): another currency at a stated rate (§2c). */
|
|
49
|
+
export type AmountUnit = "usd" | "cents" | "micro_usd" | "aed" | `fx:${string}`;
|
|
50
|
+
/** spec/money.md §2c: the unit for amounts in `currency` at `usdPerUnit` (a decimal string). */
|
|
51
|
+
export declare function fxUnit(currency: string, usdPerUnit: string): AmountUnit;
|
|
52
|
+
export interface FxRate {
|
|
53
|
+
currency: string;
|
|
54
|
+
/** USD per one unit of the currency, as the source gave it (a decimal string). */
|
|
55
|
+
usd_per_unit: string;
|
|
56
|
+
/** The rate's own date (a reference rate is set once a working day). */
|
|
57
|
+
date: string;
|
|
58
|
+
source: string;
|
|
59
|
+
}
|
|
60
|
+
/** spec/money.md §2c: the ECB reference rate for a day (or the latest), through Frankfurter. */
|
|
61
|
+
export declare function fxRate(currency: string, opts?: {
|
|
62
|
+
date?: string;
|
|
63
|
+
url?: string;
|
|
64
|
+
}): Promise<FxRate>;
|
|
49
65
|
/** spec/money.md §2a-b: an exact decimal amount (string, or a JSON number's text) to integer
|
|
50
66
|
* micro-USD, rounded half up. `unit` is what the amount counts. */
|
|
51
67
|
export declare function decimalToMicroUsd(value: unknown, unit: AmountUnit): number;
|
package/dist/money/index.js
CHANGED
|
@@ -112,23 +112,66 @@ const UNITS = {
|
|
|
112
112
|
micro_usd: [0, 1n],
|
|
113
113
|
aed: [10, 36725n],
|
|
114
114
|
};
|
|
115
|
+
const FX_UNIT = /^fx:([A-Z]{3}):(\d{1,9})(?:\.(\d{1,12}))?$/;
|
|
116
|
+
/** A unit as [power of ten, multiplier, divisor]; null for one that isn't. */
|
|
117
|
+
function unitScale(unit) {
|
|
118
|
+
const s = Object.hasOwn(UNITS, unit) ? UNITS[unit] : undefined;
|
|
119
|
+
if (s)
|
|
120
|
+
return [s[0], 1n, s[1]];
|
|
121
|
+
const m = FX_UNIT.exec(unit);
|
|
122
|
+
if (!m)
|
|
123
|
+
return null;
|
|
124
|
+
const frac = m[3] ?? "";
|
|
125
|
+
const rate = BigInt(`${m[2]}${frac}`);
|
|
126
|
+
return rate === 0n ? null : [6 - frac.length, rate, 1n];
|
|
127
|
+
}
|
|
128
|
+
/** spec/money.md §2c: the unit for amounts in `currency` at `usdPerUnit` (a decimal string). */
|
|
129
|
+
export function fxUnit(currency, usdPerUnit) {
|
|
130
|
+
const unit = `fx:${currency}:${usdPerUnit}`;
|
|
131
|
+
if (!unitScale(unit))
|
|
132
|
+
throw new Error(`not a currency and rate: ${currency} ${usdPerUnit}`);
|
|
133
|
+
return unit;
|
|
134
|
+
}
|
|
135
|
+
/** spec/money.md §2c: the ECB reference rate for a day (or the latest), through Frankfurter. */
|
|
136
|
+
export async function fxRate(currency, opts = {}) {
|
|
137
|
+
if (!/^[A-Z]{3}$/.test(currency))
|
|
138
|
+
throw new Error(`not an ISO 4217 code: ${currency}`);
|
|
139
|
+
if (opts.date !== undefined && !/^\d{4}-\d{2}-\d{2}$/.test(opts.date))
|
|
140
|
+
throw new Error(`not a date: ${opts.date}`);
|
|
141
|
+
const base = (opts.url ?? "https://api.frankfurter.dev").replace(/\/+$/, "");
|
|
142
|
+
const res = await fetch(`${base}/v1/${opts.date ?? "latest"}?base=${currency}&symbols=USD`, {
|
|
143
|
+
signal: AbortSignal.timeout(10_000),
|
|
144
|
+
});
|
|
145
|
+
if (!res.ok)
|
|
146
|
+
throw new Error(`the rate service answered HTTP ${res.status}`);
|
|
147
|
+
const body = (await res.json());
|
|
148
|
+
const usd = body.rates?.USD;
|
|
149
|
+
if (typeof usd !== "number" || !(usd > 0) || typeof body.date !== "string")
|
|
150
|
+
throw new Error("the rate service's answer has no USD rate");
|
|
151
|
+
return {
|
|
152
|
+
currency,
|
|
153
|
+
usd_per_unit: String(usd),
|
|
154
|
+
date: body.date,
|
|
155
|
+
source: "ECB reference rate, via Frankfurter",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
115
158
|
/** spec/money.md §2a-b: an exact decimal amount (string, or a JSON number's text) to integer
|
|
116
159
|
* micro-USD, rounded half up. `unit` is what the amount counts. */
|
|
117
160
|
export function decimalToMicroUsd(value, unit) {
|
|
118
161
|
const text = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
|
|
119
162
|
const m = typeof text === "string" ? DECIMAL.exec(text.trim()) : null;
|
|
120
|
-
const scale =
|
|
163
|
+
const scale = unitScale(unit);
|
|
121
164
|
if (!m || !scale)
|
|
122
165
|
throw new Error(`not a non-negative decimal amount: ${JSON.stringify(value)}`);
|
|
123
166
|
const frac = m[2] ?? "";
|
|
124
|
-
const digits = BigInt(`${m[1]}${frac}`);
|
|
167
|
+
const digits = BigInt(`${m[1]}${frac}`) * scale[1];
|
|
125
168
|
if (digits === 0n)
|
|
126
169
|
return 0;
|
|
127
170
|
const k = Number(m[3] ?? 0) - frac.length + scale[0];
|
|
128
171
|
if (k > 30)
|
|
129
172
|
throw new Error(`amount too large: ${JSON.stringify(value)}`);
|
|
130
173
|
const num = k >= 0 ? digits * 10n ** BigInt(k) : digits;
|
|
131
|
-
const den = scale[
|
|
174
|
+
const den = scale[2] * (k >= 0 ? 1n : 10n ** BigInt(-k));
|
|
132
175
|
let micro = num / den;
|
|
133
176
|
if ((num % den) * 2n >= den)
|
|
134
177
|
micro += 1n;
|
|
@@ -312,8 +355,8 @@ export function checkConnector(value) {
|
|
|
312
355
|
for (const k of ["results", "model", "amount"])
|
|
313
356
|
if (typeof c[k] !== "string" || !PATH.test(c[k]))
|
|
314
357
|
return `${k} must be a path`;
|
|
315
|
-
if (!c.unit || !(c.unit
|
|
316
|
-
return "unit must be usd, cents, micro_usd or
|
|
358
|
+
if (!c.unit || !unitScale(c.unit))
|
|
359
|
+
return "unit must be usd, cents, micro_usd, aed or fx:<CUR>:<USD per unit>";
|
|
317
360
|
if (c.currency !== undefined &&
|
|
318
361
|
(typeof c.currency?.path !== "string" ||
|
|
319
362
|
!PATH.test(c.currency.path) ||
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.14.0";
|
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.
|
|
2
|
+
export const VERSION = "0.14.0";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zanii/blackbox",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
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",
|