@broberg/ai-sdk 0.62.1 → 0.63.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 +9 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +20 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -221,8 +221,15 @@ You don't have to wire a sink. If `UPMETRICS_API_KEY` is in the env, a bare
|
|
|
221
221
|
call-sites passed no sink, leaving ~91% of Mistral spend invisible. No key in
|
|
222
222
|
the env → no sink, no crash (ship-dark).
|
|
223
223
|
|
|
224
|
+
**Every client needs a name (0.63+, F034.4).** `createAI()` throws at startup unless
|
|
225
|
+
`UPMETRICS_AGENT_NAME` is set or you pass `agentName` — even when no key is present, so
|
|
226
|
+
your tests catch it before production does. Owner order 2026-10-15: «Ingen må være
|
|
227
|
+
anonyme» — measured over 30 days, 8 repos had sent their spend as `unknown`. Not needed
|
|
228
|
+
with an explicit `costSink` or `costSink: null`.
|
|
229
|
+
|
|
224
230
|
```ts
|
|
225
|
-
createAI();
|
|
231
|
+
createAI({ agentName: "my-app" }); // key in env → tracked; no key → nothing happens
|
|
232
|
+
createAI(); // same, if UPMETRICS_AGENT_NAME is set — else throws
|
|
226
233
|
createAI({ costSink: mySink }); // explicit sink wins
|
|
227
234
|
createAI({ costSink: null }); // explicit OPT-OUT — see below
|
|
228
235
|
```
|
|
@@ -230,7 +237,7 @@ createAI({ costSink: null }); // explicit OPT-OUT — see below
|
|
|
230
237
|
| Env var | Effect |
|
|
231
238
|
|---|---|
|
|
232
239
|
| `UPMETRICS_API_KEY` | **The only switch.** Present → tracking on. |
|
|
233
|
-
| `UPMETRICS_AGENT_NAME` | Row label.
|
|
240
|
+
| `UPMETRICS_AGENT_NAME` | Row label, **required** (or `agentName`) since 0.63.0 — set it in production AND in your test env. Up to 0.62 the fallback was `npm_package_name`, empty outside an npm/bun script, so `node dist/…` and Docker services logged as `unknown`. |
|
|
234
241
|
| `UPMETRICS_BASE_URL` | Ingest host. Defaults to `https://upmetrics.org`. |
|
|
235
242
|
| `UPMETRICS_COMPLIANCE` | `1` sets compliance mode. `Usage` carries no prompt/response text either way. |
|
|
236
243
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1864,6 +1864,9 @@ declare const aiConfigSchema: z.ZodObject<{
|
|
|
1864
1864
|
* to opt OUT explicitly — for a consumer that already reports its own costs
|
|
1865
1865
|
* and would otherwise be counted twice (F034.3). An object is used as-is. */
|
|
1866
1866
|
costSink: z.ZodOptional<z.ZodNullable<z.ZodType<CostSink, z.ZodTypeDef, CostSink>>>;
|
|
1867
|
+
/** F034.4 — who is calling, as Upmetrics groups it (e.g. "cms"). Required when
|
|
1868
|
+
* `costSink` is omitted, unless UPMETRICS_AGENT_NAME is set. */
|
|
1869
|
+
agentName: z.ZodOptional<z.ZodString>;
|
|
1867
1870
|
budget: z.ZodOptional<z.ZodObject<{
|
|
1868
1871
|
perCallUsd: z.ZodOptional<z.ZodNumber>;
|
|
1869
1872
|
rollingUsd: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1896,6 +1899,7 @@ declare const aiConfigSchema: z.ZodObject<{
|
|
|
1896
1899
|
transport: "http" | "subprocess";
|
|
1897
1900
|
}>> | undefined;
|
|
1898
1901
|
providers?: Record<string, ProviderAdapter> | undefined;
|
|
1902
|
+
agentName?: string | undefined;
|
|
1899
1903
|
budget?: {
|
|
1900
1904
|
perCallUsd?: number | undefined;
|
|
1901
1905
|
rollingUsd?: number | undefined;
|
|
@@ -1916,6 +1920,7 @@ declare const aiConfigSchema: z.ZodObject<{
|
|
|
1916
1920
|
transport: "http" | "subprocess";
|
|
1917
1921
|
}>> | undefined;
|
|
1918
1922
|
providers?: Record<string, ProviderAdapter> | undefined;
|
|
1923
|
+
agentName?: string | undefined;
|
|
1919
1924
|
budget?: {
|
|
1920
1925
|
perCallUsd?: number | undefined;
|
|
1921
1926
|
rollingUsd?: number | undefined;
|
|
@@ -2334,8 +2339,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
2334
2339
|
* wires the live adapters. */
|
|
2335
2340
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
2336
2341
|
|
|
2337
|
-
declare const VERSION: "0.
|
|
2338
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.
|
|
2342
|
+
declare const VERSION: "0.63.0";
|
|
2343
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.63.0";
|
|
2339
2344
|
|
|
2340
2345
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
2341
2346
|
* per-call override.
|
package/dist/index.js
CHANGED
|
@@ -340,11 +340,13 @@ async function search(req, opts = {}) {
|
|
|
340
340
|
const nowMs = () => (opts.now ?? (() => /* @__PURE__ */ new Date()))().getTime();
|
|
341
341
|
let lastErr;
|
|
342
342
|
for (const [i, provider] of chain.entries()) {
|
|
343
|
-
const coolKey = cooldownKey(provider, opts);
|
|
344
|
-
if (i < chain.length - 1 && (coolingUntil.get(coolKey) ?? 0) > nowMs()) continue;
|
|
345
343
|
const key = searchCacheKey(provider, req);
|
|
346
344
|
const hit = cache?.get(key);
|
|
347
345
|
if (hit) return { items: hit.items, meta: { ...hit.meta, cached: true, costUsd: 0, latencyMs: 0 } };
|
|
346
|
+
const coolKey = cooldownKey(provider, opts);
|
|
347
|
+
const until = coolingUntil.get(coolKey);
|
|
348
|
+
if (until !== void 0 && until <= nowMs()) coolingUntil.delete(coolKey);
|
|
349
|
+
else if (until !== void 0 && i < chain.length - 1) continue;
|
|
348
350
|
const price = SEARCH_PRICE_USD[provider];
|
|
349
351
|
const cap = opts.dailyCapUsd ?? Infinity;
|
|
350
352
|
if (!await capStore.reserve(capKey, price, cap)) {
|
|
@@ -3908,6 +3910,9 @@ var aiConfigSchema = z.object({
|
|
|
3908
3910
|
* to opt OUT explicitly — for a consumer that already reports its own costs
|
|
3909
3911
|
* and would otherwise be counted twice (F034.3). An object is used as-is. */
|
|
3910
3912
|
costSink: z.custom().nullable().optional(),
|
|
3913
|
+
/** F034.4 — who is calling, as Upmetrics groups it (e.g. "cms"). Required when
|
|
3914
|
+
* `costSink` is omitted, unless UPMETRICS_AGENT_NAME is set. */
|
|
3915
|
+
agentName: z.string().optional(),
|
|
3911
3916
|
budget: budgetSchema.optional(),
|
|
3912
3917
|
availability: availabilitySchema.optional()
|
|
3913
3918
|
});
|
|
@@ -3916,8 +3921,8 @@ var aiConfigSchema = z.object({
|
|
|
3916
3921
|
import { randomUUID } from "crypto";
|
|
3917
3922
|
|
|
3918
3923
|
// src/version.ts
|
|
3919
|
-
var VERSION = "0.
|
|
3920
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
3924
|
+
var VERSION = "0.63.0";
|
|
3925
|
+
var SDK_TAG = "@broberg/ai-sdk@0.63.0";
|
|
3921
3926
|
|
|
3922
3927
|
// src/cost/sinks/upmetrics.ts
|
|
3923
3928
|
function isRetryableStatus(status) {
|
|
@@ -3927,6 +3932,7 @@ var MAX_QUEUE = 30;
|
|
|
3927
3932
|
var MAX_ATTEMPTS = 5;
|
|
3928
3933
|
var MAX_BACKOFF_MS = 3e4;
|
|
3929
3934
|
function upmetricsSink(config) {
|
|
3935
|
+
if (!config.agentName?.trim()) throw new Error("upmetricsSink(): agentName is required (e.g. your repo name) \u2014 anonymous cost rows are not allowed");
|
|
3930
3936
|
const doFetch = config.fetch ?? fetch;
|
|
3931
3937
|
const url = `${config.baseUrl.replace(/\/$/, "")}/api/agent`;
|
|
3932
3938
|
const retry = config.retry ?? true;
|
|
@@ -4256,21 +4262,28 @@ var ROUTED_SPECS = [
|
|
|
4256
4262
|
DEFAULT_BATCH_SPEC,
|
|
4257
4263
|
DEFAULT_TRANSCRIBE_SPEC
|
|
4258
4264
|
];
|
|
4259
|
-
function defaultCostSink() {
|
|
4265
|
+
function defaultCostSink(agentName) {
|
|
4260
4266
|
const apiKey = process.env.UPMETRICS_API_KEY;
|
|
4261
4267
|
if (!apiKey) return void 0;
|
|
4262
4268
|
return upmetricsSink({
|
|
4263
4269
|
baseUrl: process.env.UPMETRICS_BASE_URL ?? "https://upmetrics.org",
|
|
4264
4270
|
apiKey,
|
|
4265
|
-
agentName
|
|
4271
|
+
agentName,
|
|
4266
4272
|
complianceMode: process.env.UPMETRICS_COMPLIANCE === "1"
|
|
4267
4273
|
});
|
|
4268
4274
|
}
|
|
4275
|
+
function requireAgentName(configured) {
|
|
4276
|
+
const name = (configured ?? process.env.UPMETRICS_AGENT_NAME ?? "").trim();
|
|
4277
|
+
if (name) return name;
|
|
4278
|
+
throw new Error(
|
|
4279
|
+
'createAI(): no agent name \u2014 every AI call must say who made it (owner order 2026-10-15). Set UPMETRICS_AGENT_NAME=<your repo> (production AND test env), or pass createAI({ agentName: "<your repo>" }). Not needed with an explicit costSink, or costSink: null.'
|
|
4280
|
+
);
|
|
4281
|
+
}
|
|
4269
4282
|
function createAI(config = {}) {
|
|
4270
4283
|
const cfg = aiConfigSchema.parse(config);
|
|
4271
4284
|
if (cfg.byok) assertByokProviders(cfg.providers);
|
|
4272
4285
|
const providers = cfg.providers ?? defaultProviders;
|
|
4273
|
-
const costSink = cfg.costSink === void 0 ? defaultCostSink() : cfg.costSink ?? void 0;
|
|
4286
|
+
const costSink = cfg.costSink === void 0 ? defaultCostSink(requireAgentName(cfg.agentName)) : cfg.costSink ?? void 0;
|
|
4274
4287
|
const budget = cfg.budget ? new BudgetGuard(cfg.budget) : void 0;
|
|
4275
4288
|
const estTokens = (s) => Math.ceil(s.length / 4);
|
|
4276
4289
|
async function preflight(spec, estInTokens, estOutTokens) {
|