@broberg/ai-sdk 0.55.3 → 0.56.1

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/index.js CHANGED
@@ -3,25 +3,28 @@ import {
3
3
  ModelUnavailableError,
4
4
  allEntries,
5
5
  assertOverrideProvider,
6
+ describeTier,
6
7
  listModels,
7
8
  providerIds,
8
9
  resetRegistry,
9
10
  resolveModel,
10
11
  resolveTier,
11
12
  setAvailability
12
- } from "./chunk-PDGFAD66.js";
13
+ } from "./chunk-VMQSIO3J.js";
13
14
  import {
14
15
  DEFAULT_CLIP_SEC,
15
16
  MEDIA_PRICING,
16
17
  MEDIA_PRICING_CHECKED_AT,
17
- PRICING,
18
18
  PRICING_STALE_AFTER_DAYS,
19
19
  getMediaPrice,
20
- getPrice,
21
20
  listMediaPrices,
22
21
  pricingFreshness,
23
22
  pricingGeneratedAt
24
- } from "./chunk-ILZ33HZO.js";
23
+ } from "./chunk-BOZYLPIM.js";
24
+ import {
25
+ PRICING,
26
+ getPrice
27
+ } from "./chunk-QVMGFHCF.js";
25
28
 
26
29
  // src/cost/default-hosts.ts
27
30
  var DEFAULT_BASE_URLS = {
@@ -3303,6 +3306,8 @@ var callOptions = {
3303
3306
  override: tierSpecSchema.partial().optional(),
3304
3307
  fallback: z.array(z.union([tierSchema, tierSpecSchema])).optional(),
3305
3308
  purpose: z.string().optional(),
3309
+ /** F077.3 — you MEAN to call a floating "-latest" id (no warning, no strictPinning error). */
3310
+ allowFloating: z.boolean().optional(),
3306
3311
  /** Consumer-defined attribution dimensions (e.g. {tenantId}) ridden into the
3307
3312
  * cost sink for per-tenant/per-customer cost breakdown (F011). */
3308
3313
  labels: z.record(z.string(), z.string()).optional()
@@ -3525,6 +3530,8 @@ var aiConfigSchema = z.object({
3525
3530
  /** F039.2 — client-wide opt-out from prompt caching (default: on where the
3526
3531
  * provider supports it). A per-call `promptCache` wins over this. */
3527
3532
  promptCache: z.boolean().optional(),
3533
+ /** F077.3 — refuse any "-latest" model id unless the call passes allowFloating: true. */
3534
+ strictPinning: z.boolean().optional(),
3528
3535
  defaults: z.record(tierSchema, tierSpecSchema).optional(),
3529
3536
  // Functions can't be deeply validated — z.custom asserts the TS type and
3530
3537
  // passes the value through untouched.
@@ -3541,8 +3548,8 @@ var aiConfigSchema = z.object({
3541
3548
  import { randomUUID } from "crypto";
3542
3549
 
3543
3550
  // src/version.ts
3544
- var VERSION = "0.55.3";
3545
- var SDK_TAG = "@broberg/ai-sdk@0.55.3";
3551
+ var VERSION = "0.56.1";
3552
+ var SDK_TAG = "@broberg/ai-sdk@0.56.1";
3546
3553
 
3547
3554
  // src/cost/sinks/upmetrics.ts
3548
3555
  function isRetryableStatus(status) {
@@ -3883,12 +3890,12 @@ var DEFAULT_BFL_REFERENCE_SPEC = {
3883
3890
  model: "flux-2-max",
3884
3891
  transport: "http"
3885
3892
  };
3886
- var DEFAULT_OCR_SPEC = { provider: "mistral", model: "mistral-ocr-latest", transport: "http" };
3887
- var DEFAULT_MODERATION_SPEC = { provider: "mistral", model: "mistral-moderation-latest", transport: "http" };
3888
- var DEFAULT_JUDGE_SPEC = { provider: "typesafe", model: "jev-latest", transport: "http" };
3893
+ var DEFAULT_OCR_SPEC = { provider: "mistral", model: "mistral-ocr-4-1", transport: "http" };
3894
+ var DEFAULT_MODERATION_SPEC = { provider: "mistral", model: "mistral-moderation-2603", transport: "http" };
3895
+ var DEFAULT_JUDGE_SPEC = { provider: "typesafe", model: "jev-1.13.0", transport: "http" };
3889
3896
  var DEFAULT_PODCAST_SPEC = { provider: "elevenlabs", model: "eleven_v3", transport: "http" };
3890
3897
  var DEFAULT_TTS_SPEC = { provider: "elevenlabs", model: "eleven_multilingual_v2", transport: "http" };
3891
- var DEFAULT_BATCH_SPEC = { provider: "mistral", model: "mistral-small-latest", transport: "http" };
3898
+ var DEFAULT_BATCH_SPEC = { provider: "mistral", model: "mistral-small-2603", transport: "http" };
3892
3899
  var ROUTED_SPECS = [
3893
3900
  DEFAULT_IMAGE_SPEC,
3894
3901
  DEFAULT_LORA_IMAGE_SPEC,
@@ -3987,6 +3994,23 @@ function createAI(config = {}) {
3987
3994
  const r = resolveModel(spec.model, { fallback: cfg.availability.fallback, provider: spec.provider });
3988
3995
  return r.fellBack ? { ...spec, model: r.model } : spec;
3989
3996
  }
3997
+ const warnedFloating = /* @__PURE__ */ new Set();
3998
+ function checkPinning(spec, allowFloating) {
3999
+ if (!spec.model?.endsWith("-latest") || allowFloating) return false;
4000
+ const key = `${spec.provider}:${spec.model}`;
4001
+ if (cfg.strictPinning) {
4002
+ throw new Error(
4003
+ `createAI: "${key}" is a floating -latest alias and strictPinning is on. Use a dated id (describeTier() names the pinned ones) or pass allowFloating: true for this call.`
4004
+ );
4005
+ }
4006
+ if (!warnedFloating.has(key)) {
4007
+ warnedFloating.add(key);
4008
+ console.warn(
4009
+ `[@broberg/ai-sdk] "${key}" floats: the provider can move it to another model and price without a release. Pin a dated id, or pass allowFloating: true to say you mean it. (F077)`
4010
+ );
4011
+ }
4012
+ return true;
4013
+ }
3990
4014
  async function runCapability(opts) {
3991
4015
  const routes = [
3992
4016
  applyAvailability(opts.primary),
@@ -3997,11 +4021,13 @@ function createAI(config = {}) {
3997
4021
  let lastErr;
3998
4022
  for (let i = 0; i < routes.length; i++) {
3999
4023
  const spec = routes[i];
4024
+ const floating = checkPinning(spec, opts.allowFloating);
4000
4025
  await preflight(spec, opts.estIn, opts.estOut);
4001
4026
  const t0 = performance.now();
4002
4027
  try {
4003
4028
  const res = await opts.invoke(spec);
4004
4029
  enrich(res.usage, opts.capability, i === 0 ? opts.tier : void 0, opts.purpose, performance.now() - t0, opts.labels);
4030
+ if (floating) res.usage.floating = true;
4005
4031
  await settle(res.usage);
4006
4032
  await report(res.usage);
4007
4033
  return res;
@@ -4057,6 +4083,7 @@ function createAI(config = {}) {
4057
4083
  let lastErr;
4058
4084
  for (let i = 0; i < routes.length; i++) {
4059
4085
  const spec = routes[i];
4086
+ const floating = checkPinning(spec, input.allowFloating);
4060
4087
  await preflight(spec, estIn, estOut);
4061
4088
  const adapter = pickProvider(spec.provider);
4062
4089
  if (!adapter.chatStream) {
@@ -4083,6 +4110,7 @@ function createAI(config = {}) {
4083
4110
  if (ev.type === "text" || ev.type === "tool_call") emitted = true;
4084
4111
  if (ev.type === "usage") {
4085
4112
  enrich(ev.usage, "chat", i === 0 ? tier : void 0, input.purpose, performance.now() - t0, input.labels);
4113
+ if (floating) ev.usage.floating = true;
4086
4114
  await settle(ev.usage);
4087
4115
  await report(ev.usage);
4088
4116
  }
@@ -4128,6 +4156,7 @@ function createAI(config = {}) {
4128
4156
  tier,
4129
4157
  purpose: input.purpose,
4130
4158
  labels: input.labels,
4159
+ allowFloating: input.allowFloating,
4131
4160
  estIn,
4132
4161
  estOut: input.maxTokens ?? 512,
4133
4162
  invoke: async (spec) => {
@@ -4149,6 +4178,7 @@ function createAI(config = {}) {
4149
4178
  tier,
4150
4179
  purpose: input.purpose,
4151
4180
  labels: input.labels,
4181
+ allowFloating: input.allowFloating,
4152
4182
  estIn: estTokens(input.prompt) + 1e3,
4153
4183
  // prompt + ~1k image payload
4154
4184
  estOut: 512,
@@ -4170,6 +4200,7 @@ function createAI(config = {}) {
4170
4200
  tier,
4171
4201
  purpose: input.purpose,
4172
4202
  labels: input.labels,
4203
+ allowFloating: input.allowFloating,
4173
4204
  estIn: estTokens(input.prompt) + 4e3,
4174
4205
  // prompt + video tokens (native video ≈ frames)
4175
4206
  estOut: 512,
@@ -4192,6 +4223,7 @@ function createAI(config = {}) {
4192
4223
  tier,
4193
4224
  purpose: input.purpose,
4194
4225
  labels: input.labels,
4226
+ allowFloating: input.allowFloating,
4195
4227
  estIn,
4196
4228
  estOut: estIn,
4197
4229
  invoke: async (spec) => {
@@ -4216,6 +4248,7 @@ function createAI(config = {}) {
4216
4248
  capability: "image",
4217
4249
  purpose: input.purpose,
4218
4250
  labels: input.labels,
4251
+ allowFloating: input.allowFloating,
4219
4252
  estIn: 0,
4220
4253
  // image cost is not token-based
4221
4254
  estOut: 0,
@@ -4248,6 +4281,7 @@ function createAI(config = {}) {
4248
4281
  capability: "animate",
4249
4282
  purpose: input.purpose,
4250
4283
  labels: input.labels,
4284
+ allowFloating: input.allowFloating,
4251
4285
  estIn: 0,
4252
4286
  // video cost is per-second, not token-based
4253
4287
  estOut: 0,
@@ -4273,6 +4307,7 @@ function createAI(config = {}) {
4273
4307
  capability: "trainStyle",
4274
4308
  purpose: input.purpose,
4275
4309
  labels: input.labels,
4310
+ allowFloating: input.allowFloating,
4276
4311
  estIn: 0,
4277
4312
  // training is priced flat by fal, not token-based
4278
4313
  estOut: 0,
@@ -4299,6 +4334,7 @@ function createAI(config = {}) {
4299
4334
  capability: "ocr",
4300
4335
  purpose: input.purpose,
4301
4336
  labels: input.labels,
4337
+ allowFloating: input.allowFloating,
4302
4338
  estIn: 0,
4303
4339
  // OCR cost is per-page, not token-based
4304
4340
  estOut: 0,
@@ -4318,6 +4354,7 @@ function createAI(config = {}) {
4318
4354
  capability: "moderation",
4319
4355
  purpose: input.purpose,
4320
4356
  labels: input.labels,
4357
+ allowFloating: input.allowFloating,
4321
4358
  estIn: items.reduce((n, s) => n + estTokens(s), 0),
4322
4359
  estOut: 0,
4323
4360
  invoke: async (spec) => {
@@ -4336,6 +4373,7 @@ function createAI(config = {}) {
4336
4373
  capability: "judge",
4337
4374
  purpose: input.purpose,
4338
4375
  labels: input.labels,
4376
+ allowFloating: input.allowFloating,
4339
4377
  estIn: estTokens(stateText) + estTokens(JSON.stringify(input.questions)),
4340
4378
  estOut: 0,
4341
4379
  // output tokens are free on Jev
@@ -4362,6 +4400,7 @@ function createAI(config = {}) {
4362
4400
  capability: "podcast",
4363
4401
  purpose: input.purpose,
4364
4402
  labels: input.labels,
4403
+ allowFloating: input.allowFloating,
4365
4404
  estIn: chars,
4366
4405
  // per-character cost (not token-based)
4367
4406
  estOut: 0,
@@ -4381,6 +4420,7 @@ function createAI(config = {}) {
4381
4420
  capability: "tts",
4382
4421
  purpose: input.purpose,
4383
4422
  labels: input.labels,
4423
+ allowFloating: input.allowFloating,
4384
4424
  estIn: input.text.length,
4385
4425
  // per-character cost
4386
4426
  estOut: 0,
@@ -4411,6 +4451,7 @@ function createAI(config = {}) {
4411
4451
  tier,
4412
4452
  purpose: input.purpose,
4413
4453
  labels: input.labels,
4454
+ allowFloating: input.allowFloating,
4414
4455
  estIn: text.reduce((n, t) => n + estTokens(t), 0),
4415
4456
  estOut: 0,
4416
4457
  invoke: async (spec) => {
@@ -4429,6 +4470,7 @@ function createAI(config = {}) {
4429
4470
  capability: "transcribe",
4430
4471
  purpose: input.purpose,
4431
4472
  labels: input.labels,
4473
+ allowFloating: input.allowFloating,
4432
4474
  estIn: 0,
4433
4475
  estOut: 0,
4434
4476
  invoke: async (spec) => {
@@ -5091,6 +5133,7 @@ export {
5091
5133
  deepseekAdapter,
5092
5134
  defaultBaseUrl,
5093
5135
  defaultProviders,
5136
+ describeTier,
5094
5137
  discordSink,
5095
5138
  elevenlabsAdapter,
5096
5139
  embeddingInputSchema,