@shop-os/modelkit 0.1.4 → 0.1.5

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.cjs CHANGED
@@ -175,7 +175,8 @@ var GEMINI_RATIOS = [
175
175
  "3:4",
176
176
  "21:9",
177
177
  "4:5",
178
- "5:4"
178
+ "5:4",
179
+ "adaptive"
179
180
  ];
180
181
  function geminiImage(id, label, aliases, sizes) {
181
182
  const model = {
@@ -186,7 +187,7 @@ function geminiImage(id, label, aliases, sizes) {
186
187
  adapter: "google-image",
187
188
  providerModelId: id,
188
189
  lifecycle: "active",
189
- constraints: { aspectRatios: [...GEMINI_RATIOS], sizes },
190
+ constraints: { aspectRatios: [...GEMINI_RATIOS], sizes, supports: ["safetySettings"] },
190
191
  defaults: { size: "1K", aspectRatio: "1:1" },
191
192
  usage: { ...IMAGE_USAGE },
192
193
  pricingKind: "image_size"
@@ -283,7 +284,8 @@ var IMAGE_MODELS = [
283
284
  "9:16",
284
285
  "4:5",
285
286
  "5:4",
286
- "9:21"
287
+ "9:21",
288
+ "adaptive"
287
289
  ],
288
290
  sizes: ["1K"],
289
291
  references: { images: 10 },
@@ -344,9 +346,10 @@ var IMAGE_MODELS = [
344
346
  constraints: {
345
347
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
346
348
  sizes: ["1K"],
347
- supports: ["outputFormat"]
349
+ // flux-2-pro's job type always returns image/png; only the seed is forwarded.
350
+ supports: ["seed"]
348
351
  },
349
- defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png" },
352
+ defaults: { size: "1K", aspectRatio: "1:1" },
350
353
  usage: { ...IMAGE_USAGE },
351
354
  pricingKind: "image_size"
352
355
  },
@@ -364,7 +367,8 @@ var IMAGE_MODELS = [
364
367
  constraints: {
365
368
  aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
366
369
  sizes: ["1K", "2K", "4K"],
367
- requires: ["references"]
370
+ requires: ["references"],
371
+ supports: ["seed"]
368
372
  },
369
373
  defaults: { size: "1K", aspectRatio: "1:1" },
370
374
  usage: { ...IMAGE_USAGE },
@@ -383,7 +387,8 @@ var IMAGE_MODELS = [
383
387
  constraints: {
384
388
  aspectRatios: ["1:1", "2:3", "3:4", "4:3", "9:16", "16:9", "21:9"],
385
389
  sizes: ["1K"],
386
- requires: ["references"]
390
+ requires: ["references"],
391
+ supports: ["seed"]
387
392
  },
388
393
  defaults: { size: "1K", aspectRatio: "1:1" },
389
394
  usage: { ...IMAGE_USAGE },
@@ -403,7 +408,8 @@ var IMAGE_MODELS = [
403
408
  constraints: {
404
409
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4"],
405
410
  sizes: ["1K", "2K", "4K"],
406
- references: { images: 9 }
411
+ references: { images: 9 },
412
+ supports: []
407
413
  },
408
414
  defaults: { size: "1K", aspectRatio: "1:1" },
409
415
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -424,7 +430,8 @@ var IMAGE_MODELS = [
424
430
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"],
425
431
  sizes: [],
426
432
  references: { images: 1 },
427
- requires: ["references"]
433
+ requires: ["references"],
434
+ supports: []
428
435
  },
429
436
  defaults: { aspectRatio: "1:1" },
430
437
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -466,7 +473,8 @@ var OTHER_MODELS = [
466
473
  lifecycle: "active",
467
474
  constraints: {
468
475
  durations: [30],
469
- references: { images: 10 }
476
+ references: { images: 10 },
477
+ supports: []
470
478
  },
471
479
  defaults: {},
472
480
  usage: { unit: "images", modality: "AUDIO" },
@@ -481,7 +489,8 @@ var OTHER_MODELS = [
481
489
  providerModelId: "lyria-3-pro-preview",
482
490
  lifecycle: "active",
483
491
  constraints: {
484
- references: { images: 10 }
492
+ references: { images: 10 },
493
+ supports: []
485
494
  },
486
495
  defaults: {},
487
496
  usage: { unit: "images", modality: "AUDIO" },
@@ -564,7 +573,8 @@ var OTHER_MODELS = [
564
573
  lifecycle: "active",
565
574
  constraints: {
566
575
  references: { images: 1 },
567
- requires: ["references"]
576
+ requires: ["references"],
577
+ supports: []
568
578
  },
569
579
  defaults: {},
570
580
  usage: { unit: "images", modality: "IMAGE" },
@@ -583,7 +593,7 @@ function text(id, label, providerModelId, extra) {
583
593
  adapter: "ai-sdk-text",
584
594
  providerModelId,
585
595
  lifecycle: "active",
586
- constraints: {},
596
+ constraints: { supports: [] },
587
597
  defaults: {},
588
598
  usage: { ...TEXT_USAGE },
589
599
  pricingKind: "token",
@@ -656,7 +666,7 @@ var TEXT_MODELS = [
656
666
  // src/catalog/video.ts
657
667
  var VIDEO_USAGE = { unit: "seconds", modality: "VIDEO" };
658
668
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
659
- var KLING_RATIOS = ["16:9", "9:16", "1:1"];
669
+ var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
660
670
  var OMNI_RATIOS = ["16:9", "9:16"];
661
671
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
662
672
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
@@ -748,12 +758,15 @@ var VIDEO_MODELS = [
748
758
  providerModelId: "gemini-omni-flash-preview",
749
759
  lifecycle: "active",
750
760
  constraints: {
761
+ // 1.0 rejects `resolution`; it renders 720p. No defaults: the adapter
762
+ // sends ratio and duration only when the caller set them, so a
763
+ // reference clip keeps its own framing.
751
764
  aspectRatios: [...OMNI_RATIOS],
752
- resolutions: ["720p"],
753
765
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
754
- references: { images: 6, videos: 1 }
766
+ references: { images: 6, videos: 1 },
767
+ supports: []
755
768
  },
756
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
769
+ defaults: {},
757
770
  usage: { ...VIDEO_USAGE },
758
771
  pricingKind: "video_per_second"
759
772
  },
@@ -769,9 +782,10 @@ var VIDEO_MODELS = [
769
782
  aspectRatios: [...OMNI_RATIOS],
770
783
  resolutions: ["360p", "720p", "1080p", "4k"],
771
784
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
772
- references: { images: 6, videos: 1 }
785
+ references: { images: 6, videos: 1 },
786
+ supports: []
773
787
  },
774
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
788
+ defaults: {},
775
789
  usage: { ...VIDEO_USAGE },
776
790
  pricingKind: "video_per_second"
777
791
  },
@@ -865,7 +879,8 @@ var VIDEO_MODELS = [
865
879
  aspectRatios: [...GROK_RATIOS],
866
880
  resolutions: ["480p", "720p"],
867
881
  durations: { min: 1, max: 15 },
868
- references: { images: 7 }
882
+ references: { images: 7 },
883
+ supports: []
869
884
  },
870
885
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
871
886
  usage: { unit: "reported_cost_usd", modality: "VIDEO" },
@@ -1055,7 +1070,8 @@ var VIDEO_MODELS = [
1055
1070
  constraints: {
1056
1071
  aspectRatios: [...KLING_RATIOS],
1057
1072
  durations: { min: 3, max: 10 },
1058
- requires: ["sourceVideo"]
1073
+ requires: ["sourceVideo"],
1074
+ supports: []
1059
1075
  },
1060
1076
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1061
1077
  usage: { ...VIDEO_USAGE },
@@ -1088,7 +1104,7 @@ var VIDEO_MODELS = [
1088
1104
  lifecycle: "active",
1089
1105
  constraints: {
1090
1106
  requires: ["firstFrame"],
1091
- supports: ["seed"]
1107
+ supports: ["seed", "lastFrame"]
1092
1108
  },
1093
1109
  defaults: {},
1094
1110
  usage: { ...VIDEO_USAGE },
@@ -1199,7 +1215,7 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1199
1215
  const warnings = [];
1200
1216
  const c = model.constraints;
1201
1217
  const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1202
- if (merged.aspectRatio && c.aspectRatios && !c.aspectRatios.includes(merged.aspectRatio)) {
1218
+ if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1203
1219
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1204
1220
  warnings.push({
1205
1221
  code: "ratio_coerced",
@@ -1242,7 +1258,8 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1242
1258
  "quality",
1243
1259
  "count",
1244
1260
  "outputFormat",
1245
- "scaleFactor"
1261
+ "scaleFactor",
1262
+ "safetySettings"
1246
1263
  ]);
1247
1264
  return { request: merged, warnings };
1248
1265
  }
@@ -1272,7 +1289,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1272
1289
  delete merged.aspectRatio;
1273
1290
  }
1274
1291
  }
1275
- if (merged.aspectRatio && c.aspectRatios && !c.aspectRatios.includes(merged.aspectRatio)) {
1292
+ if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1276
1293
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1277
1294
  warnings.push({
1278
1295
  code: "ratio_coerced",
@@ -1354,8 +1371,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1354
1371
  return { request: merged, warnings };
1355
1372
  }
1356
1373
  function dropUnsupported(req, model, warnings, fields) {
1357
- const supports = model.constraints.supports;
1358
- if (!supports) return;
1374
+ const supports = model.constraints.supports ?? [];
1359
1375
  for (const field of fields) {
1360
1376
  if (req[field] !== void 0 && !supports.includes(field)) {
1361
1377
  warnings.push({
@@ -1433,8 +1449,45 @@ function keysFromEnv(env, prefix = "") {
1433
1449
  }
1434
1450
 
1435
1451
  // src/retry.ts
1452
+ var import_zod2 = require("zod");
1453
+
1454
+ // src/json.ts
1436
1455
  var import_zod = require("zod");
1437
- var textBody = import_zod.z.string();
1456
+ var JsonValueSchema = import_zod.z.lazy(
1457
+ () => import_zod.z.union([
1458
+ import_zod.z.string(),
1459
+ import_zod.z.number(),
1460
+ import_zod.z.boolean(),
1461
+ import_zod.z.null(),
1462
+ import_zod.z.array(JsonValueSchema),
1463
+ import_zod.z.record(import_zod.z.string(), JsonValueSchema)
1464
+ ])
1465
+ );
1466
+ var JsonObjectSchema = import_zod.z.record(import_zod.z.string(), JsonValueSchema);
1467
+ async function readErrorBody(res) {
1468
+ const text2 = await res.text().catch(() => "");
1469
+ try {
1470
+ return JsonValueSchema.parse(JSON.parse(text2));
1471
+ } catch {
1472
+ return text2;
1473
+ }
1474
+ }
1475
+ var thrownErrorSchema = import_zod.z.object({
1476
+ message: import_zod.z.string().optional(),
1477
+ status: import_zod.z.number().optional(),
1478
+ statusCode: import_zod.z.number().optional(),
1479
+ responseBody: import_zod.z.string().optional()
1480
+ });
1481
+ function describeThrown(cause) {
1482
+ const parsed = thrownErrorSchema.safeParse(cause);
1483
+ if (!parsed.success) return { message: String(cause), status: void 0, body: String(cause) };
1484
+ const { message, status, statusCode, responseBody } = parsed.data;
1485
+ const body = responseBody ?? message ?? String(cause);
1486
+ return { message: message ?? String(cause), status: status ?? statusCode, body };
1487
+ }
1488
+
1489
+ // src/retry.ts
1490
+ var textBody = import_zod2.z.string();
1438
1491
  function classifyHttpError(status, body, provider, model) {
1439
1492
  const asText = textBody.safeParse(body);
1440
1493
  const text2 = asText.success ? asText.data : JSON.stringify(body);
@@ -1517,6 +1570,13 @@ function transportError(provider, cause, model) {
1517
1570
  if (model !== void 0) init.model = model;
1518
1571
  return new ModelKitError(init);
1519
1572
  }
1573
+ function classifyThrown(provider, cause, model, override = {}) {
1574
+ if (cause instanceof ModelKitError) return cause;
1575
+ const info = describeThrown(cause);
1576
+ const status = override.status ?? info.status;
1577
+ if (status === void 0) return transportError(provider, cause, model);
1578
+ return classifyHttpError(status, override.body ?? info.body, provider, model);
1579
+ }
1520
1580
  async function pollUntil(check, opts) {
1521
1581
  const start = Date.now();
1522
1582
  let interval = opts.intervalMs;
@@ -1632,7 +1692,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
1632
1692
 
1633
1693
  // src/client.ts
1634
1694
  var import_ai2 = require("ai");
1635
- var import_zod3 = require("zod");
1695
+ var import_zod4 = require("zod");
1636
1696
 
1637
1697
  // src/adapters/media-ref.ts
1638
1698
  function isUrlRef(ref) {
@@ -1687,7 +1747,7 @@ var import_perplexity = require("@ai-sdk/perplexity");
1687
1747
  var import_xai = require("@ai-sdk/xai");
1688
1748
  var import_deepseek = require("@ai-sdk/deepseek");
1689
1749
  var import_moonshotai = require("@ai-sdk/moonshotai");
1690
- var import_zod2 = require("zod");
1750
+ var import_zod3 = require("zod");
1691
1751
  var TEXT_PROVIDERS = [
1692
1752
  "openai",
1693
1753
  "anthropic",
@@ -1698,7 +1758,7 @@ var TEXT_PROVIDERS = [
1698
1758
  "moonshot",
1699
1759
  "minimax"
1700
1760
  ];
1701
- var textProviderSchema = import_zod2.z.enum(TEXT_PROVIDERS);
1761
+ var textProviderSchema = import_zod3.z.enum(TEXT_PROVIDERS);
1702
1762
  function isTextProvider(value) {
1703
1763
  return textProviderSchema.safeParse(value).success;
1704
1764
  }
@@ -1707,9 +1767,9 @@ var OPENAI_COMPATIBLE_BASE_URLS = {
1707
1767
  };
1708
1768
  var GATEWAY_SLUGS = {
1709
1769
  openai: "openai",
1710
- anthropic: "anthropic",
1770
+ anthropic: "anthropic/v1",
1711
1771
  google: "google-ai-studio/v1beta",
1712
- xai: "grok",
1772
+ xai: "grok/v1",
1713
1773
  perplexity: "perplexity-ai",
1714
1774
  deepseek: "deepseek"
1715
1775
  };
@@ -1884,10 +1944,10 @@ function textAbortOptions(sdk, context) {
1884
1944
  if (abortSignal) return { abortSignal };
1885
1945
  return {};
1886
1946
  }
1887
- var catalogId = import_zod3.z.string();
1888
- var exactSize = import_zod3.z.templateLiteral([import_zod3.z.number(), "x", import_zod3.z.number()]);
1889
- var sdkRatio = import_zod3.z.templateLiteral([import_zod3.z.number(), ":", import_zod3.z.number()]);
1890
- var sizeTier = import_zod3.z.enum(["1K", "2K", "4K"]);
1947
+ var catalogId = import_zod4.z.string();
1948
+ var exactSize = import_zod4.z.templateLiteral([import_zod4.z.number(), "x", import_zod4.z.number()]);
1949
+ var sdkRatio = import_zod4.z.templateLiteral([import_zod4.z.number(), ":", import_zod4.z.number()]);
1950
+ var sizeTier = import_zod4.z.enum(["512", "1K", "2K", "4K"]);
1891
1951
  function isCatalogId(model) {
1892
1952
  return catalogId.safeParse(model).success;
1893
1953
  }
@@ -1944,6 +2004,10 @@ function pushIgnored(warnings, field, from, modelId) {
1944
2004
  message: `${modelId} provider instance does not support ${field}; ignored`
1945
2005
  });
1946
2006
  }
2007
+ function logCoercions(logger, modelId, warnings) {
2008
+ if (warnings.length === 0) return;
2009
+ logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
2010
+ }
1947
2011
  function createModelKit(config, adapters) {
1948
2012
  const catalog = new Catalog(MODELS).withOverrides(config.catalogOverride ?? []);
1949
2013
  const logger = config.logger ?? console;
@@ -1977,6 +2041,10 @@ function createModelKit(config, adapters) {
1977
2041
  logger.warn("[modelkit] usage emit failed", err);
1978
2042
  }
1979
2043
  }
2044
+ function withRowUnit(event) {
2045
+ const row = catalog.get(event.model);
2046
+ return row ? { ...event, unit: row.usage.unit } : event;
2047
+ }
1980
2048
  function textTarget(model, call) {
1981
2049
  if (!isCatalogId(model)) {
1982
2050
  return {
@@ -2045,6 +2113,7 @@ function createModelKit(config, adapters) {
2045
2113
  pushIgnored(warnings, "outputFormat", _outputFormat, model.modelId);
2046
2114
  if (scaleFactor !== void 0)
2047
2115
  pushIgnored(warnings, "scaleFactor", scaleFactor, model.modelId);
2116
+ logCoercions(logger, model.modelId, warnings);
2048
2117
  const abortSignal = combineSignals(req.abortSignal, call.signal);
2049
2118
  if (abortSignal) options.abortSignal = abortSignal;
2050
2119
  const result = await (0, import_ai2.generateImage)(options);
@@ -2128,6 +2197,7 @@ function createModelKit(config, adapters) {
2128
2197
  if (_mode !== void 0) pushIgnored(warnings, "mode", _mode, model.modelId);
2129
2198
  if (providerOptions) options.providerOptions = providerOptions;
2130
2199
  if (abortSignal) options.abortSignal = abortSignal;
2200
+ logCoercions(logger, model.modelId, warnings);
2131
2201
  const pending = (0, import_ai2.experimental_generateVideo)(options);
2132
2202
  let settled;
2133
2203
  let failed = false;
@@ -2186,6 +2256,7 @@ function createModelKit(config, adapters) {
2186
2256
  call.onUnsupported ?? "error"
2187
2257
  );
2188
2258
  warnings.push(...inputWarnings);
2259
+ logCoercions(logger, model.id, warnings);
2189
2260
  const signal = combineSignals(req.abortSignal, call.signal);
2190
2261
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2191
2262
  if (!adapter.generateImage)
@@ -2195,7 +2266,7 @@ function createModelKit(config, adapters) {
2195
2266
  model: model.id
2196
2267
  });
2197
2268
  const result = await adapter.generateImage(request, ctx);
2198
- const usage2 = { ...result.usage, model: model.id };
2269
+ const usage2 = { ...result.usage, model: model.id, unit: model.usage.unit };
2199
2270
  await emit(usage2);
2200
2271
  const images = result.images.map(toGeneratedImage);
2201
2272
  const first = images[0];
@@ -2228,6 +2299,7 @@ function createModelKit(config, adapters) {
2228
2299
  call.onUnsupported ?? "error"
2229
2300
  );
2230
2301
  warnings.push(...inputWarnings);
2302
+ logCoercions(logger, model.id, warnings);
2231
2303
  const signal = combineSignals(req.abortSignal, call.signal);
2232
2304
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2233
2305
  if (!adapter.generateVideo)
@@ -2245,7 +2317,11 @@ function createModelKit(config, adapters) {
2245
2317
  result(opts) {
2246
2318
  if (settled) return settled;
2247
2319
  const pending = result(opts).then(
2248
- (out) => emit({ ...out.usage, model: model.id }).then(() => out),
2320
+ (out) => emit({
2321
+ ...out.usage,
2322
+ model: model.id,
2323
+ unit: model.usage.unit
2324
+ }).then(() => out),
2249
2325
  (cause) => {
2250
2326
  settled = void 0;
2251
2327
  throw cause;
@@ -2265,7 +2341,8 @@ function createModelKit(config, adapters) {
2265
2341
  model: model.id
2266
2342
  });
2267
2343
  }
2268
- const { adapter, ctx } = context(model, call, []);
2344
+ const warnings = [];
2345
+ const { adapter, ctx } = context(model, call, warnings);
2269
2346
  if (!adapter.generateAudio) {
2270
2347
  throw new ModelKitError({
2271
2348
  code: "unsupported_option",
@@ -2277,7 +2354,8 @@ function createModelKit(config, adapters) {
2277
2354
  { ...model.defaults, ...req, model: model.id },
2278
2355
  ctx
2279
2356
  );
2280
- await emit({ ...result.usage, model: model.id });
2357
+ logCoercions(logger, model.id, warnings);
2358
+ await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
2281
2359
  return result;
2282
2360
  },
2283
2361
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
@@ -2317,7 +2395,7 @@ function createModelKit(config, adapters) {
2317
2395
  options.prepareStep ?? options.experimental_prepareStep
2318
2396
  )
2319
2397
  });
2320
- for (const event of steps.usage(result.steps)) await emit(event);
2398
+ for (const event of steps.usage(result.steps)) await emit(withRowUnit(event));
2321
2399
  return result;
2322
2400
  },
2323
2401
  streamText(options, call = {}) {
@@ -2335,7 +2413,7 @@ function createModelKit(config, adapters) {
2335
2413
  providerOptions: {},
2336
2414
  prepareStep: steps.wrap(options.prepareStep),
2337
2415
  onFinish: async (event) => {
2338
- for (const usage2 of steps.usage(event.steps)) await emit(usage2);
2416
+ for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
2339
2417
  await callerOnFinish?.(event);
2340
2418
  }
2341
2419
  });
@@ -2349,7 +2427,7 @@ function createModelKit(config, adapters) {
2349
2427
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions)
2350
2428
  };
2351
2429
  const result = await (0, import_ai2.generateObject)(sdkOptions);
2352
- await emit(textUsageEvent(entry, provider, result.usage));
2430
+ await emit(withRowUnit(textUsageEvent(entry, provider, result.usage)));
2353
2431
  return result;
2354
2432
  },
2355
2433
  streamObject(options, call = {}) {
@@ -2361,7 +2439,7 @@ function createModelKit(config, adapters) {
2361
2439
  model: languageModel2,
2362
2440
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions),
2363
2441
  onFinish: async (event) => {
2364
- await emit(textUsageEvent(entry, provider, event.usage));
2442
+ await emit(withRowUnit(textUsageEvent(entry, provider, event.usage)));
2365
2443
  await callerOnFinish?.(event);
2366
2444
  }
2367
2445
  };
@@ -2371,7 +2449,7 @@ function createModelKit(config, adapters) {
2371
2449
  }
2372
2450
 
2373
2451
  // src/adapters/ark.ts
2374
- var import_zod4 = require("zod");
2452
+ var import_zod5 = require("zod");
2375
2453
  var ARK_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
2376
2454
  var SUBMIT_PATH = "/contents/generations/tasks";
2377
2455
  var SEEDANCE_POLL_INTERVAL_MS = 15e3;
@@ -2429,7 +2507,7 @@ function arkKey(ctx) {
2429
2507
  return key;
2430
2508
  }
2431
2509
  function throwArkError(status, body, model) {
2432
- const parsed = import_zod4.z.string().safeParse(body);
2510
+ const parsed = import_zod5.z.string().safeParse(body);
2433
2511
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2434
2512
  if (/sensitive.?content|inputimage|human.?face/i.test(text2)) {
2435
2513
  const init = {
@@ -2443,6 +2521,16 @@ function throwArkError(status, body, model) {
2443
2521
  if (status !== void 0) init.status = status;
2444
2522
  throw new ModelKitError(init);
2445
2523
  }
2524
+ if (status === void 0) {
2525
+ throw new ModelKitError({
2526
+ code: "provider_rejected",
2527
+ message: `ark rejected the request: ${text2.slice(0, 500)}`,
2528
+ provider: "ark",
2529
+ model,
2530
+ body,
2531
+ retryable: false
2532
+ });
2533
+ }
2446
2534
  throw classifyHttpError(status, body, "ark", model);
2447
2535
  }
2448
2536
  function seedreamSize(aspect, size) {
@@ -2461,13 +2549,13 @@ function arkUrl(ref) {
2461
2549
  if ("url" in ref) return ref.url;
2462
2550
  return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2463
2551
  }
2464
- var SeedreamImageSchema = import_zod4.z.object({
2465
- url: import_zod4.z.string().optional(),
2466
- b64_json: import_zod4.z.string().optional()
2552
+ var SeedreamImageSchema = import_zod5.z.object({
2553
+ url: import_zod5.z.string().optional(),
2554
+ b64_json: import_zod5.z.string().optional()
2467
2555
  });
2468
- var SeedreamResponseSchema = import_zod4.z.object({
2469
- data: import_zod4.z.array(SeedreamImageSchema).optional(),
2470
- error: import_zod4.z.object({ message: import_zod4.z.string().optional(), code: import_zod4.z.string().optional() }).optional()
2556
+ var SeedreamResponseSchema = import_zod5.z.object({
2557
+ data: import_zod5.z.array(SeedreamImageSchema).optional(),
2558
+ error: import_zod5.z.object({ message: import_zod5.z.string().optional(), code: import_zod5.z.string().optional() }).optional()
2471
2559
  });
2472
2560
  function retryOptsFor(ctx, attempts = 3) {
2473
2561
  const opts = { attempts };
@@ -2478,6 +2566,11 @@ function fetchInitFor(ctx, init) {
2478
2566
  if (ctx.signal !== void 0) init.signal = ctx.signal;
2479
2567
  return init;
2480
2568
  }
2569
+ function arkFetch(ctx, url, init) {
2570
+ return ctx.fetch(url, fetchInitFor(ctx, init)).catch((cause) => {
2571
+ throw classifyThrown("ark", cause, ctx.model.id);
2572
+ });
2573
+ }
2481
2574
  async function generateSeedreamImage(req, ctx) {
2482
2575
  const key = arkKey(ctx);
2483
2576
  const modelId = ctx.model.id;
@@ -2495,14 +2588,11 @@ async function generateSeedreamImage(req, ctx) {
2495
2588
  if (refs.length === 1 && firstRef !== void 0) body.image = firstRef;
2496
2589
  else if (refs.length > 1) body.image = refs;
2497
2590
  const data = await withRetry(async () => {
2498
- const res = await ctx.fetch(
2499
- `${arkBaseUrl(ctx)}/images/generations`,
2500
- fetchInitFor(ctx, {
2501
- method: "POST",
2502
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2503
- body: JSON.stringify(body)
2504
- })
2505
- );
2591
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}/images/generations`, {
2592
+ method: "POST",
2593
+ headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2594
+ body: JSON.stringify(body)
2595
+ });
2506
2596
  if (!res.ok) {
2507
2597
  const text2 = await res.text().catch(() => "");
2508
2598
  throwArkError(res.status, text2, modelId);
@@ -2517,7 +2607,7 @@ async function generateSeedreamImage(req, ctx) {
2517
2607
  bytes = Buffer.from(first.b64_json, "base64");
2518
2608
  } else if (first?.url) {
2519
2609
  const imageUrl = first.url;
2520
- const res = await ctx.fetch(imageUrl, fetchInitFor(ctx, {}));
2610
+ const res = await arkFetch(ctx, imageUrl, {});
2521
2611
  if (!res.ok) {
2522
2612
  const text2 = await res.text().catch(() => "");
2523
2613
  throwArkError(res.status, text2, modelId);
@@ -2537,13 +2627,13 @@ async function generateSeedreamImage(req, ctx) {
2537
2627
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
2538
2628
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
2539
2629
  }
2540
- var SeedanceResponseSchema = import_zod4.z.object({
2541
- id: import_zod4.z.string().optional(),
2542
- status: import_zod4.z.string().optional(),
2543
- content: import_zod4.z.object({ video_url: import_zod4.z.string().optional() }).optional(),
2544
- error: import_zod4.z.union([import_zod4.z.string(), import_zod4.z.object({ message: import_zod4.z.string().optional() })]).optional()
2630
+ var SeedanceResponseSchema = import_zod5.z.object({
2631
+ id: import_zod5.z.string().optional(),
2632
+ status: import_zod5.z.string().optional(),
2633
+ content: import_zod5.z.object({ video_url: import_zod5.z.string().optional() }).optional(),
2634
+ error: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.object({ message: import_zod5.z.string().optional() })]).optional()
2545
2635
  });
2546
- var SeedanceErrorMessageSchema = import_zod4.z.object({ message: import_zod4.z.string().optional() });
2636
+ var SeedanceErrorMessageSchema = import_zod5.z.object({ message: import_zod5.z.string().optional() });
2547
2637
  function seedanceUsage(ctx, req, duration) {
2548
2638
  const usage2 = {
2549
2639
  model: ctx.model.id,
@@ -2557,7 +2647,7 @@ function seedanceUsage(ctx, req, duration) {
2557
2647
  return usage2;
2558
2648
  }
2559
2649
  function seedanceErrorMessage(error, status) {
2560
- const asString = import_zod4.z.string().safeParse(error);
2650
+ const asString = import_zod5.z.string().safeParse(error);
2561
2651
  if (asString.success) return asString.data;
2562
2652
  const asObject = SeedanceErrorMessageSchema.safeParse(error);
2563
2653
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
@@ -2622,14 +2712,11 @@ async function generateSeedanceVideo(req, ctx) {
2622
2712
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
2623
2713
  if (req.seed !== void 0) body.seed = req.seed;
2624
2714
  const submit = await withRetry(async () => {
2625
- const res = await ctx.fetch(
2626
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}`,
2627
- fetchInitFor(ctx, {
2628
- method: "POST",
2629
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2630
- body: JSON.stringify(body)
2631
- })
2632
- );
2715
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
2716
+ method: "POST",
2717
+ headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2718
+ body: JSON.stringify(body)
2719
+ });
2633
2720
  if (!res.ok) {
2634
2721
  const text2 = await res.text().catch(() => "");
2635
2722
  throwArkError(res.status, text2, modelId);
@@ -2642,12 +2729,9 @@ async function generateSeedanceVideo(req, ctx) {
2642
2729
  const jobId = submit.id;
2643
2730
  const usage2 = seedanceUsage(ctx, req, duration);
2644
2731
  const fetchStatus = async () => {
2645
- const res = await ctx.fetch(
2646
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`,
2647
- fetchInitFor(ctx, {
2648
- headers: { Authorization: `Bearer ${key}` }
2649
- })
2650
- );
2732
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
2733
+ headers: { Authorization: `Bearer ${key}` }
2734
+ });
2651
2735
  if (!res.ok) {
2652
2736
  if (res.status === 429 || res.status >= 500) return void 0;
2653
2737
  const text2 = await res.text().catch(() => "");
@@ -2708,43 +2792,6 @@ async function generateSeedanceVideo(req, ctx) {
2708
2792
  // src/adapters/fal.ts
2709
2793
  var import_zod6 = require("zod");
2710
2794
  var import_client = require("@fal-ai/client");
2711
-
2712
- // src/json.ts
2713
- var import_zod5 = require("zod");
2714
- var JsonValueSchema = import_zod5.z.lazy(
2715
- () => import_zod5.z.union([
2716
- import_zod5.z.string(),
2717
- import_zod5.z.number(),
2718
- import_zod5.z.boolean(),
2719
- import_zod5.z.null(),
2720
- import_zod5.z.array(JsonValueSchema),
2721
- import_zod5.z.record(import_zod5.z.string(), JsonValueSchema)
2722
- ])
2723
- );
2724
- var JsonObjectSchema = import_zod5.z.record(import_zod5.z.string(), JsonValueSchema);
2725
- async function readErrorBody(res) {
2726
- const text2 = await res.text().catch(() => "");
2727
- try {
2728
- return JsonValueSchema.parse(JSON.parse(text2));
2729
- } catch {
2730
- return text2;
2731
- }
2732
- }
2733
- var thrownErrorSchema = import_zod5.z.object({
2734
- message: import_zod5.z.string().optional(),
2735
- status: import_zod5.z.number().optional(),
2736
- statusCode: import_zod5.z.number().optional(),
2737
- responseBody: import_zod5.z.string().optional()
2738
- });
2739
- function describeThrown(cause) {
2740
- const parsed = thrownErrorSchema.safeParse(cause);
2741
- if (!parsed.success) return { message: String(cause), status: void 0, body: String(cause) };
2742
- const { message, status, statusCode, responseBody } = parsed.data;
2743
- const body = responseBody ?? message ?? String(cause);
2744
- return { message: message ?? String(cause), status: status ?? statusCode, body };
2745
- }
2746
-
2747
- // src/adapters/fal.ts
2748
2795
  var MUSE_T2I_ENDPOINT = "meta/muse-image/text-to-image";
2749
2796
  var MUSE_EDIT_ENDPOINT = "meta/muse-image/edit";
2750
2797
  var KLING_O1_ENDPOINT = "fal-ai/kling-video/o1/video-to-video/reference";
@@ -2756,10 +2803,33 @@ function defaultCreateFalClient(opts) {
2756
2803
  const client2 = (0, import_client.createFalClient)(opts);
2757
2804
  return {
2758
2805
  async subscribe(endpoint, options) {
2759
- const outcome = await client2.subscribe(endpoint, { input: options.input });
2806
+ const outcome = await client2.subscribe(endpoint, options);
2760
2807
  const unwrapped = falSubscribePayloadSchema.safeParse(outcome);
2761
2808
  if (unwrapped.success) return unwrapped.data.data;
2762
2809
  return JsonValueSchema.parse(outcome);
2810
+ },
2811
+ queue: {
2812
+ async submit(endpoint, options) {
2813
+ const submitted = await client2.queue.submit(endpoint, {
2814
+ input: options.input,
2815
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2816
+ });
2817
+ return { requestId: submitted.request_id };
2818
+ },
2819
+ async status(endpoint, options) {
2820
+ const current = await client2.queue.status(endpoint, {
2821
+ requestId: options.requestId,
2822
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2823
+ });
2824
+ return { status: current.status };
2825
+ },
2826
+ async result(endpoint, options) {
2827
+ const outcome = await client2.queue.result(endpoint, {
2828
+ requestId: options.requestId,
2829
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2830
+ });
2831
+ return JsonValueSchema.parse(outcome.data);
2832
+ }
2763
2833
  }
2764
2834
  };
2765
2835
  }
@@ -2801,15 +2871,17 @@ var falSdkThrownSchema = import_zod6.z.object({
2801
2871
  message: import_zod6.z.string().optional()
2802
2872
  });
2803
2873
  function falSdkError(cause, model) {
2804
- if (isModelKitError(cause)) return cause;
2805
2874
  const parsed = falSdkThrownSchema.safeParse(cause);
2806
2875
  if (parsed.success) {
2807
2876
  const status = parsed.data.status ?? parsed.data.statusCode;
2808
2877
  const body = parsed.data.body ?? parsed.data.message ?? String(cause);
2809
- return falError(status, body, model);
2878
+ return classifyThrown("fal", cause, model, { status, body: liftDetail(body) });
2810
2879
  }
2811
2880
  const info = describeThrown(cause);
2812
- return falError(info.status, info.body, model);
2881
+ return classifyThrown("fal", cause, model, {
2882
+ status: info.status,
2883
+ body: liftDetail(info.body)
2884
+ });
2813
2885
  }
2814
2886
  function gatewayConfig(ctx) {
2815
2887
  const cf = ctx.routing.cloudflare;
@@ -2891,7 +2963,7 @@ async function passthroughRequest(ctx, endpoint, input) {
2891
2963
  }
2892
2964
  return JsonValueSchema.parse(await resultRes.json());
2893
2965
  }
2894
- async function subscribe(ctx, deps, endpoint, input) {
2966
+ function falClientOf(ctx, deps) {
2895
2967
  const falKey = ctx.keys.fal;
2896
2968
  if (!falKey) {
2897
2969
  throw new ModelKitError({
@@ -2902,12 +2974,19 @@ async function subscribe(ctx, deps, endpoint, input) {
2902
2974
  retryable: false
2903
2975
  });
2904
2976
  }
2905
- const client2 = deps.createFalClient({ credentials: falKey });
2977
+ return deps.createFalClient({ credentials: falKey, fetch: ctx.fetch });
2978
+ }
2979
+ async function subscribe(ctx, deps, endpoint, input) {
2980
+ const client2 = falClientOf(ctx, deps);
2981
+ const options = {
2982
+ input,
2983
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
2984
+ };
2906
2985
  try {
2907
2986
  return await withRetry(
2908
2987
  async () => {
2909
2988
  try {
2910
- return await client2.subscribe(endpoint, { input });
2989
+ return await client2.subscribe(endpoint, options);
2911
2990
  } catch (cause) {
2912
2991
  throw falSdkError(cause, ctx.model.id);
2913
2992
  }
@@ -3041,13 +3120,14 @@ function klingO1Input(req) {
3041
3120
  });
3042
3121
  }
3043
3122
  const duration = Math.min(10, Math.max(3, Math.round(req.durationSeconds ?? 5)));
3044
- const ratio = req.aspectRatio === "16:9" || req.aspectRatio === "9:16" || req.aspectRatio === "1:1" ? req.aspectRatio : "auto";
3045
3123
  const input = {
3046
3124
  prompt: req.prompt,
3047
3125
  video_url: source,
3048
- duration: String(duration),
3049
- aspect_ratio: ratio
3126
+ duration: String(duration)
3050
3127
  };
3128
+ if (req.aspectRatio !== "adaptive") {
3129
+ input.aspect_ratio = req.aspectRatio === "16:9" || req.aspectRatio === "9:16" || req.aspectRatio === "1:1" ? req.aspectRatio : "auto";
3130
+ }
3051
3131
  const refs = (req.referenceImages ?? []).map(refToUrl);
3052
3132
  if (refs.length > 0) input.image_urls = refs;
3053
3133
  return input;
@@ -3076,13 +3156,7 @@ async function generateFalVideo(req, ctx, deps) {
3076
3156
  if (ctx.routing.fal === "cloudflare-passthrough") {
3077
3157
  return await passthroughVideoJob(ctx, req, KLING_O1_ENDPOINT, input);
3078
3158
  }
3079
- const result2 = await runJob(ctx, deps, KLING_O1_ENDPOINT, input);
3080
- return completedVideoJob(
3081
- ctx,
3082
- req,
3083
- extractVideoUrl(result2, KLING_O1_ENDPOINT, ctx.model.id),
3084
- result2
3085
- );
3159
+ return await submitQueueJob(ctx, req, deps, KLING_O1_ENDPOINT, input);
3086
3160
  }
3087
3161
  const family = minimaxFamily(providerModelId);
3088
3162
  const refs = {
@@ -3111,19 +3185,81 @@ async function generateFalVideo(req, ctx, deps) {
3111
3185
  if (ctx.routing.fal === "cloudflare-passthrough") {
3112
3186
  return await passthroughVideoJob(ctx, req, endpoint, base);
3113
3187
  }
3114
- const result = await runJob(ctx, deps, endpoint, base);
3115
- return completedVideoJob(ctx, req, extractVideoUrl(result, endpoint, ctx.model.id), result);
3188
+ return await submitQueueJob(ctx, req, deps, endpoint, base);
3116
3189
  }
3117
- function completedVideoJob(ctx, req, url, raw) {
3190
+ async function submitQueueJob(ctx, req, deps, endpoint, input) {
3191
+ const client2 = falClientOf(ctx, deps);
3192
+ let submitted;
3193
+ try {
3194
+ submitted = await withRetry(
3195
+ async () => {
3196
+ try {
3197
+ return await client2.queue.submit(endpoint, {
3198
+ input,
3199
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
3200
+ });
3201
+ } catch (cause) {
3202
+ throw falSdkError(cause, ctx.model.id);
3203
+ }
3204
+ },
3205
+ ctx.signal !== void 0 ? { signal: ctx.signal } : {}
3206
+ );
3207
+ } catch (cause) {
3208
+ throw falSdkError(cause, ctx.model.id);
3209
+ }
3210
+ return queuedVideoJob(ctx, req, client2, endpoint, submitted.requestId);
3211
+ }
3212
+ function queuedVideoJob(ctx, req, client2, endpoint, requestId) {
3213
+ const readStatus = async () => {
3214
+ try {
3215
+ const options = {
3216
+ requestId,
3217
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
3218
+ };
3219
+ return (await client2.queue.status(endpoint, options)).status;
3220
+ } catch (cause) {
3221
+ throw falSdkError(cause, ctx.model.id);
3222
+ }
3223
+ };
3118
3224
  const duration = req.durationSeconds ?? 5;
3119
- const result = { video: { url }, usage: videoUsage(ctx, req, duration), raw };
3120
3225
  return {
3121
- jobId: url,
3226
+ jobId: requestId,
3122
3227
  async poll() {
3123
- return { status: "succeeded", raw };
3228
+ try {
3229
+ const status = await readStatus();
3230
+ if (status === "COMPLETED") return { status: "succeeded" };
3231
+ if (status === "IN_QUEUE") return { status: "pending" };
3232
+ return { status: "running" };
3233
+ } catch (cause) {
3234
+ if (isModelKitError(cause) && !cause.retryable)
3235
+ return { status: "failed" };
3236
+ return { status: "pending" };
3237
+ }
3124
3238
  },
3125
- async result() {
3126
- return result;
3239
+ async result(opts) {
3240
+ const signal = opts?.signal ?? ctx.signal;
3241
+ const pollOptions = {
3242
+ intervalMs: opts?.pollIntervalMs ?? PASSTHROUGH_POLL_MS,
3243
+ timeoutMs: opts?.timeoutMs ?? 15 * 6e4
3244
+ };
3245
+ if (signal !== void 0) pollOptions.signal = signal;
3246
+ const queueOptions = {
3247
+ requestId,
3248
+ ...signal !== void 0 ? { abortSignal: signal } : {}
3249
+ };
3250
+ const payload = await pollUntil(async () => {
3251
+ try {
3252
+ const current = await client2.queue.status(endpoint, queueOptions);
3253
+ if (current.status !== "COMPLETED") return void 0;
3254
+ return await client2.queue.result(endpoint, queueOptions);
3255
+ } catch (cause) {
3256
+ const err = falSdkError(cause, ctx.model.id);
3257
+ if (err.retryable) return void 0;
3258
+ throw err;
3259
+ }
3260
+ }, pollOptions);
3261
+ const url = extractVideoUrl(payload, endpoint, ctx.model.id);
3262
+ return { video: { url }, usage: videoUsage(ctx, req, duration), raw: payload };
3127
3263
  }
3128
3264
  };
3129
3265
  }
@@ -3474,9 +3610,7 @@ function sdkStatus(cause) {
3474
3610
  return describeThrown(cause).status;
3475
3611
  }
3476
3612
  function throwSdkError(cause, model) {
3477
- if (cause instanceof ModelKitError) throw cause;
3478
- const info = describeThrown(cause);
3479
- throw classifyHttpError(info.status, info.body, "google-genai", model);
3613
+ throw classifyThrown("google-genai", cause, model);
3480
3614
  }
3481
3615
  function toBase64(bytes) {
3482
3616
  return Buffer.from(bytes).toString("base64");
@@ -3680,12 +3814,17 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3680
3814
  const duration = req.durationSeconds ?? 8;
3681
3815
  const images = req.referenceImages ?? [];
3682
3816
  const videos = req.referenceVideos ?? [];
3683
- const task = req.sourceVideo ? "edit" : videos.length > 0 || images.length > 1 ? "reference_to_video" : req.firstFrame || images.length === 1 ? "image_to_video" : "text_to_video";
3684
- const responseFormat = { type: "video" };
3685
- if (req.sourceVideo === void 0) responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
3686
- const omniResolution = toOmniResolution(req.resolution);
3687
- if (omniResolution !== void 0) responseFormat.resolution = omniResolution;
3688
- responseFormat.duration = `${duration}s`;
3817
+ const task = req.sourceVideo ? "edit" : req.firstFrame ? "image_to_video" : images.length > 0 || videos.length > 0 ? "reference_to_video" : "text_to_video";
3818
+ const isOmniV1 = providerModelId === "gemini-omni-flash-preview";
3819
+ const responseFormat = { type: "video", delivery: "uri" };
3820
+ if (req.sourceVideo === void 0 && req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
3821
+ responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
3822
+ }
3823
+ if (!isOmniV1) {
3824
+ const omniResolution = toOmniResolution(req.resolution);
3825
+ if (omniResolution !== void 0) responseFormat.resolution = omniResolution;
3826
+ }
3827
+ if (req.durationSeconds !== void 0) responseFormat.duration = `${req.durationSeconds}s`;
3689
3828
  const client2 = createGenAIClient({ apiKey });
3690
3829
  const uploadedByUri = /* @__PURE__ */ new Map();
3691
3830
  const uploadedNames = [];
@@ -3709,7 +3848,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3709
3848
  model: providerModelId,
3710
3849
  input,
3711
3850
  response_format: responseFormat,
3712
- generation_config: { video_config: { task } }
3851
+ generation_config: { video_config: { task } },
3852
+ store: true
3713
3853
  });
3714
3854
  const createRetryOptions = { attempts: 3 };
3715
3855
  if (ctx.signal !== void 0) createRetryOptions.signal = ctx.signal;
@@ -3791,23 +3931,14 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3791
3931
  };
3792
3932
  return inline;
3793
3933
  });
3794
- const inlineRetryOptions = { attempts: 3 };
3795
- if (ctx.signal !== void 0) inlineRetryOptions.signal = ctx.signal;
3796
3934
  try {
3797
- interaction = await withRetry(async () => {
3798
- try {
3799
- return await callCreate(inlineParts);
3800
- } catch (inlineCause) {
3801
- throwSdkError(inlineCause, modelId);
3802
- }
3803
- }, inlineRetryOptions);
3935
+ interaction = await callCreate(inlineParts);
3804
3936
  } catch (inlineCause) {
3805
3937
  throwSdkError(inlineCause, modelId);
3806
3938
  }
3807
3939
  }
3808
- } catch (cause) {
3940
+ } finally {
3809
3941
  await cleanupUploads();
3810
- throw cause;
3811
3942
  }
3812
3943
  const jobId = interaction.id ?? "gemini-omni-interaction";
3813
3944
  const usage2 = videoUsage2(ctx, req, duration);
@@ -3836,47 +3967,43 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3836
3967
  timeoutMs: opts?.timeoutMs ?? RESULT_TIMEOUT_MS2
3837
3968
  };
3838
3969
  if (signal !== void 0) pollOptions.signal = signal;
3839
- try {
3840
- const done = await pollUntil(async () => {
3841
- const current = await getInteraction();
3842
- const status = (current.status ?? "").toUpperCase();
3843
- if (status === "COMPLETED") return current;
3844
- if (status === "FAILED") {
3845
- throw classifyHttpError(
3846
- void 0,
3847
- `Gemini Omni interaction failed: ${JSON.stringify(current).slice(0, 500)}`,
3848
- "google-genai",
3849
- modelId
3850
- );
3851
- }
3852
- return void 0;
3853
- }, pollOptions);
3854
- const video = extractOmniVideo(done, modelId);
3855
- if (video.data) {
3856
- return {
3857
- video: {
3858
- bytes: Buffer.from(video.data, "base64"),
3859
- mime: video.mime_type ?? "video/mp4"
3860
- },
3861
- usage: usage2,
3862
- raw: done
3863
- };
3970
+ const done = await pollUntil(async () => {
3971
+ const current = await getInteraction();
3972
+ const status = (current.status ?? "").toUpperCase();
3973
+ if (status === "COMPLETED") return current;
3974
+ if (status === "FAILED") {
3975
+ throw classifyHttpError(
3976
+ void 0,
3977
+ `Gemini Omni interaction failed: ${JSON.stringify(current).slice(0, 500)}`,
3978
+ "google-genai",
3979
+ modelId
3980
+ );
3864
3981
  }
3865
- if (video.uri)
3866
- return {
3867
- video: await downloadVideo(ctx, video.uri, apiKey, signal),
3868
- usage: usage2,
3869
- raw: done
3870
- };
3871
- throw classifyHttpError(
3872
- void 0,
3873
- "No video content in Gemini Omni response",
3874
- "google-genai",
3875
- modelId
3876
- );
3877
- } finally {
3878
- await cleanupUploads();
3982
+ return void 0;
3983
+ }, pollOptions);
3984
+ const video = extractOmniVideo(done, modelId);
3985
+ if (video.data) {
3986
+ return {
3987
+ video: {
3988
+ bytes: Buffer.from(video.data, "base64"),
3989
+ mime: video.mime_type ?? "video/mp4"
3990
+ },
3991
+ usage: usage2,
3992
+ raw: done
3993
+ };
3879
3994
  }
3995
+ if (video.uri)
3996
+ return {
3997
+ video: await downloadVideo(ctx, video.uri, apiKey, signal),
3998
+ usage: usage2,
3999
+ raw: done
4000
+ };
4001
+ throw classifyHttpError(
4002
+ void 0,
4003
+ "No video content in Gemini Omni response",
4004
+ "google-genai",
4005
+ modelId
4006
+ );
3880
4007
  }
3881
4008
  };
3882
4009
  }
@@ -4045,8 +4172,14 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4045
4172
  content.push({ type: "text", text: req.prompt });
4046
4173
  void ctx.call.postCropToAspect;
4047
4174
  const imageConfig = {};
4048
- if (req.aspectRatio !== void 0) imageConfig.aspectRatio = req.aspectRatio;
4175
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4176
+ imageConfig.aspectRatio = req.aspectRatio;
4049
4177
  if (req.size !== void 0) imageConfig.imageSize = req.size;
4178
+ const googleOptions = {
4179
+ imageConfig,
4180
+ responseModalities: ["IMAGE"]
4181
+ };
4182
+ if (req.safetySettings !== void 0) googleOptions.safetySettings = req.safetySettings;
4050
4183
  const retryOptions = {};
4051
4184
  if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4052
4185
  const result = await withRetry(async () => {
@@ -4058,22 +4191,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4058
4191
  messages: [{ role: "user", content }],
4059
4192
  maxRetries: 0,
4060
4193
  providerOptions: {
4061
- google: {
4062
- imageConfig,
4063
- responseModalities: ["IMAGE"],
4064
- safetySettings: [
4065
- {
4066
- category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
4067
- threshold: "OFF"
4068
- },
4069
- { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "OFF" },
4070
- {
4071
- category: "HARM_CATEGORY_DANGEROUS_CONTENT",
4072
- threshold: "OFF"
4073
- },
4074
- { category: "HARM_CATEGORY_HARASSMENT", threshold: "OFF" }
4075
- ]
4076
- }
4194
+ google: googleOptions
4077
4195
  },
4078
4196
  abortSignal: signal
4079
4197
  });
@@ -4260,6 +4378,7 @@ var KLING_MAX_INTERVAL_MS = 1e4;
4260
4378
  var KLING_TIMEOUT_MS = 15 * 6e4;
4261
4379
  var DOP_INTERVAL_MS = 5e3;
4262
4380
  var DOP_TIMEOUT_MS = 5 * 6e4;
4381
+ var DOP_FALLBACK_DURATION_SECONDS = 5;
4263
4382
  var DEFAULT_NEGATIVE_PROMPT = "text, watermark, copyright, blur, low quality, distortion, abstract, weird, deformed";
4264
4383
  function credentials(ctx) {
4265
4384
  const key = ctx.keys.higgsfield;
@@ -4334,6 +4453,18 @@ function requestInit(ctx, init) {
4334
4453
  if (ctx.signal !== void 0) request.signal = ctx.signal;
4335
4454
  return request;
4336
4455
  }
4456
+ async function createRequest(ctx, url, init) {
4457
+ let res;
4458
+ try {
4459
+ res = await ctx.fetch(url, requestInit(ctx, init));
4460
+ } catch (cause) {
4461
+ throw classifyThrown("higgsfield", cause, ctx.model.id);
4462
+ }
4463
+ if (!res.ok) {
4464
+ throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4465
+ }
4466
+ return res;
4467
+ }
4337
4468
  async function generateKlingVideo(req, ctx) {
4338
4469
  const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4339
4470
  if (!firstFrame) {
@@ -4352,26 +4483,16 @@ async function generateKlingVideo(req, ctx) {
4352
4483
  negative_prompt: req.negativePrompt ?? DEFAULT_NEGATIVE_PROMPT
4353
4484
  };
4354
4485
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
4355
- if (req.aspectRatio !== void 0) body.aspect_ratio = req.aspectRatio;
4486
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4487
+ body.aspect_ratio = req.aspectRatio;
4356
4488
  if (req.lastFrame) body.last_image_url = refToUrl2(req.lastFrame);
4357
4489
  const endpoint = klingEndpoint(ctx.model.providerModelId);
4358
- let createRes;
4359
- try {
4360
- createRes = await ctx.fetch(
4361
- endpoint,
4362
- requestInit(ctx, { method: "POST", body: JSON.stringify(body) })
4363
- );
4364
- } catch (cause) {
4365
- throw networkError(cause, ctx);
4366
- }
4367
- if (!createRes.ok) {
4368
- throw classifyHttpError(
4369
- createRes.status,
4370
- await readBody2(createRes),
4371
- "higgsfield",
4372
- ctx.model.id
4373
- );
4374
- }
4490
+ const retryOptions = {};
4491
+ if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4492
+ const createRes = await withRetry(
4493
+ () => createRequest(ctx, endpoint, { method: "POST", body: JSON.stringify(body) }),
4494
+ retryOptions
4495
+ );
4375
4496
  const created = klingCreateSchema.safeParse(await createRes.json());
4376
4497
  if (!created.success) {
4377
4498
  throw new ModelKitError({
@@ -4451,11 +4572,6 @@ async function generateKlingVideo(req, ctx) {
4451
4572
  }
4452
4573
  };
4453
4574
  }
4454
- function networkError(cause, ctx) {
4455
- if (isModelKitError(cause)) return cause;
4456
- const info = describeThrown(cause);
4457
- return classifyHttpError(info.status, info.body, "higgsfield", ctx.model.id);
4458
- }
4459
4575
  var dopMotionOptionsSchema = import_zod10.z.object({
4460
4576
  modelkit: import_zod10.z.object({ motion: import_zod10.z.string().optional() }).optional()
4461
4577
  });
@@ -4527,26 +4643,15 @@ async function generateDopVideo(req, ctx) {
4527
4643
  params.input_images_end = [{ type: "image_url", image_url: refToUrl2(req.lastFrame) }];
4528
4644
  }
4529
4645
  if (req.seed !== void 0) params.seed = req.seed;
4530
- let createRes;
4531
- try {
4532
- createRes = await ctx.fetch(
4533
- DOP_ENDPOINT,
4534
- requestInit(ctx, {
4535
- method: "POST",
4536
- body: JSON.stringify({ params, webhook: null })
4537
- })
4538
- );
4539
- } catch (cause) {
4540
- throw networkError(cause, ctx);
4541
- }
4542
- if (!createRes.ok) {
4543
- throw classifyHttpError(
4544
- createRes.status,
4545
- await readBody2(createRes),
4546
- "higgsfield",
4547
- ctx.model.id
4548
- );
4549
- }
4646
+ const retryOptions = {};
4647
+ if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4648
+ const createRes = await withRetry(
4649
+ () => createRequest(ctx, DOP_ENDPOINT, {
4650
+ method: "POST",
4651
+ body: JSON.stringify({ params, webhook: null })
4652
+ }),
4653
+ retryOptions
4654
+ );
4550
4655
  const created = dopCreateSchema.safeParse(await createRes.json());
4551
4656
  if (!created.success) {
4552
4657
  throw new ModelKitError({
@@ -4615,7 +4720,10 @@ async function generateDopVideo(req, ctx) {
4615
4720
  };
4616
4721
  if (dopSignal !== void 0) pollSettings.signal = dopSignal;
4617
4722
  const url = await pollUntil(check, pollSettings);
4618
- const result = { video: { url }, usage: videoUsage3(ctx, req) };
4723
+ const result = {
4724
+ video: { url },
4725
+ usage: videoUsage3(ctx, req, req.durationSeconds ?? DOP_FALLBACK_DURATION_SECONDS)
4726
+ };
4619
4727
  return result;
4620
4728
  }
4621
4729
  };
@@ -4797,28 +4905,16 @@ var openaiImageAdapter = {
4797
4905
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
4798
4906
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
4799
4907
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
4800
- let usage2;
4801
- if (inputTokens !== void 0 || outputTokens !== void 0) {
4802
- usage2 = {
4803
- model: ctx.model.id,
4804
- provider: "openai-image",
4805
- modality: "IMAGE",
4806
- unit: "tokens",
4807
- quantity: (inputTokens ?? 0) + (outputTokens ?? 0),
4808
- imageQuality: quality
4809
- };
4810
- if (inputTokens !== void 0) usage2.inputTokens = inputTokens;
4811
- if (outputTokens !== void 0) usage2.outputTokens = outputTokens;
4812
- } else {
4813
- usage2 = {
4814
- model: ctx.model.id,
4815
- provider: "openai-image",
4816
- modality: "IMAGE",
4817
- unit: "images",
4818
- quantity: images.length,
4819
- imageQuality: quality
4820
- };
4821
- }
4908
+ const usage2 = {
4909
+ model: ctx.model.id,
4910
+ provider: "openai-image",
4911
+ modality: "IMAGE",
4912
+ unit: "images",
4913
+ quantity: images.length,
4914
+ imageQuality: quality
4915
+ };
4916
+ if (inputTokens !== void 0) usage2.inputTokens = inputTokens;
4917
+ if (outputTokens !== void 0) usage2.outputTokens = outputTokens;
4822
4918
  if (req.size !== void 0) usage2.imageSize = req.size;
4823
4919
  return { images, usage: usage2, raw: response };
4824
4920
  }
@@ -4871,7 +4967,12 @@ var NANO_BANANA_RATIOS = /* @__PURE__ */ new Set([
4871
4967
  ]);
4872
4968
  async function refToBytes(ctx, ref) {
4873
4969
  if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
4874
- const res = await ctx.fetch(ref.url);
4970
+ let res;
4971
+ try {
4972
+ res = await ctx.fetch(ref.url);
4973
+ } catch (cause) {
4974
+ throw classifyThrown("prodia", cause, ctx.model.id);
4975
+ }
4875
4976
  if (!res.ok) {
4876
4977
  const text2 = await res.text().catch(() => "");
4877
4978
  throw classifyHttpError(res.status, text2, "prodia", ctx.model.id);
@@ -5041,8 +5142,7 @@ async function generateProdiaImage(req, ctx) {
5041
5142
  body: form
5042
5143
  });
5043
5144
  } catch (err) {
5044
- if (isModelKitError(err)) throw err;
5045
- throw transportError("prodia", err, ctx.model.id);
5145
+ throw classifyThrown("prodia", err, ctx.model.id);
5046
5146
  }
5047
5147
  if (!attemptRes.ok) {
5048
5148
  const text2 = await attemptRes.text().catch(() => "");
@@ -5051,8 +5151,7 @@ async function generateProdiaImage(req, ctx) {
5051
5151
  return attemptRes;
5052
5152
  }, retryOpts);
5053
5153
  } catch (err) {
5054
- if (isModelKitError(err)) throw err;
5055
- throw transportError("prodia", err, ctx.model.id);
5154
+ throw classifyThrown("prodia", err, ctx.model.id);
5056
5155
  }
5057
5156
  const bytes = parseImageResponse(
5058
5157
  new Uint8Array(await res.arrayBuffer()),
@@ -5124,7 +5223,7 @@ function replicateError(cause, ctx) {
5124
5223
  const info = describeThrown(cause);
5125
5224
  const nested = replicateResponseStatusSchema.safeParse(cause);
5126
5225
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5127
- return classifyHttpError(status, info.body, "replicate", ctx.model.id);
5226
+ return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
5128
5227
  }
5129
5228
  function isLower(id) {
5130
5229
  return id.toLowerCase();
@@ -5434,7 +5533,7 @@ function klingInput(req) {
5434
5533
  input.start_image = startImage;
5435
5534
  const endImage = images[1];
5436
5535
  if (endImage !== void 0) input.end_image = endImage;
5437
- } else {
5536
+ } else if (req.aspectRatio !== "adaptive") {
5438
5537
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5439
5538
  }
5440
5539
  if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
@@ -5454,7 +5553,7 @@ function klingOmniInput(req) {
5454
5553
  input.start_image = startImage;
5455
5554
  const endImage = images[1];
5456
5555
  if (endImage !== void 0) input.end_image = endImage;
5457
- } else {
5556
+ } else if (req.aspectRatio !== "adaptive") {
5458
5557
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5459
5558
  }
5460
5559
  const refs = (req.referenceImages ?? []).map(refToUrl3);
@@ -5663,11 +5762,10 @@ var xaiResponseStatusSchema = import_zod13.z.object({
5663
5762
  response: import_zod13.z.object({ status: import_zod13.z.number() }).partial()
5664
5763
  });
5665
5764
  function xaiError(cause, ctx) {
5666
- if (isModelKitError(cause)) return cause;
5667
5765
  const info = describeThrown(cause);
5668
5766
  const nested = xaiResponseStatusSchema.safeParse(cause);
5669
5767
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5670
- return classifyHttpError(status, info.body, "xai-video", ctx.model.id);
5768
+ return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
5671
5769
  }
5672
5770
  var xaiMetaSchema = import_zod13.z.object({
5673
5771
  videoUrl: JsonValueSchema.optional(),
@@ -5691,10 +5789,7 @@ async function generateXaiVideo(req, ctx, deps) {
5691
5789
  retryable: false
5692
5790
  });
5693
5791
  }
5694
- const frames = [req.firstFrame, req.lastFrame, ...req.referenceImages ?? []].filter(
5695
- (r) => r !== void 0
5696
- );
5697
- const refUrls = frames.map(refToUrl4).slice(0, 5);
5792
+ const refUrls = (req.referenceImages ?? []).map(refToUrl4).slice(0, 7);
5698
5793
  const resolution = req.resolution === "480p" ? "480p" : "720p";
5699
5794
  const xaiOptions = {
5700
5795
  resolution,
@@ -5705,13 +5800,23 @@ async function generateXaiVideo(req, ctx, deps) {
5705
5800
  xaiOptions.mode = "reference-to-video";
5706
5801
  xaiOptions.referenceImageUrls = refUrls;
5707
5802
  }
5803
+ if (req.lastFrame !== void 0) {
5804
+ ctx.warnings.push({
5805
+ code: "option_ignored",
5806
+ field: "lastFrame",
5807
+ message: "xai-video does not support lastFrame; ignored"
5808
+ });
5809
+ }
5708
5810
  const client2 = deps.createXaiClient({ apiKey });
5709
- const model = (0, import_xai2.createXai)({ apiKey }).video(ctx.model.providerModelId);
5811
+ const model = (0, import_xai2.createXai)({ apiKey, fetch: ctx.fetch }).video(ctx.model.providerModelId);
5710
5812
  const callBody = {
5711
5813
  model,
5712
5814
  prompt: req.prompt,
5713
5815
  providerOptions: { xai: xaiOptions }
5714
5816
  };
5817
+ if (req.firstFrame) {
5818
+ callBody.frameImages = [{ image: refToUrl4(req.firstFrame), frameType: "first_frame" }];
5819
+ }
5715
5820
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5716
5821
  callBody.aspectRatio = req.aspectRatio;
5717
5822
  }
@@ -5797,26 +5902,14 @@ async function mapResult(ctx, req, result) {
5797
5902
  function usage(ctx, req, meta) {
5798
5903
  const costTicks = import_zod13.z.number().safeParse(meta.costInUsdTicks);
5799
5904
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
5800
- if (cost !== void 0) {
5801
- const event2 = {
5802
- model: ctx.model.id,
5803
- provider: "xai-video",
5804
- modality: "VIDEO",
5805
- unit: "reported_cost_usd",
5806
- quantity: cost,
5807
- reportedCostUsd: cost
5808
- };
5809
- if (req.durationSeconds !== void 0) event2.durationSeconds = req.durationSeconds;
5810
- if (req.resolution !== void 0) event2.resolution = req.resolution;
5811
- return event2;
5812
- }
5813
5905
  const event = {
5814
5906
  model: ctx.model.id,
5815
5907
  provider: "xai-video",
5816
5908
  modality: "VIDEO",
5817
- unit: "seconds",
5818
- quantity: req.durationSeconds ?? 0
5909
+ unit: "reported_cost_usd",
5910
+ quantity: cost ?? 0
5819
5911
  };
5912
+ if (cost !== void 0) event.reportedCostUsd = cost;
5820
5913
  if (req.durationSeconds !== void 0) event.durationSeconds = req.durationSeconds;
5821
5914
  if (req.resolution !== void 0) event.resolution = req.resolution;
5822
5915
  return event;