@shop-os/modelkit 0.1.3 → 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
@@ -165,7 +165,19 @@ var Catalog = class _Catalog {
165
165
 
166
166
  // src/catalog/image.ts
167
167
  var IMAGE_USAGE = { unit: "images", modality: "IMAGE" };
168
- var GEMINI_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "4:5", "5:4"];
168
+ var GEMINI_RATIOS = [
169
+ "1:1",
170
+ "2:3",
171
+ "3:2",
172
+ "16:9",
173
+ "9:16",
174
+ "4:3",
175
+ "3:4",
176
+ "21:9",
177
+ "4:5",
178
+ "5:4",
179
+ "adaptive"
180
+ ];
169
181
  function geminiImage(id, label, aliases, sizes) {
170
182
  const model = {
171
183
  id,
@@ -175,7 +187,7 @@ function geminiImage(id, label, aliases, sizes) {
175
187
  adapter: "google-image",
176
188
  providerModelId: id,
177
189
  lifecycle: "active",
178
- constraints: { aspectRatios: [...GEMINI_RATIOS], sizes },
190
+ constraints: { aspectRatios: [...GEMINI_RATIOS], sizes, supports: ["safetySettings"] },
179
191
  defaults: { size: "1K", aspectRatio: "1:1" },
180
192
  usage: { ...IMAGE_USAGE },
181
193
  pricingKind: "image_size"
@@ -188,7 +200,8 @@ var IMAGE_MODELS = [
188
200
  "gemini-3.1-flash-image-preview",
189
201
  "Nano Banana Flash",
190
202
  ["nb-2"],
191
- ["1K", "2K", "4K"]
203
+ // Flash 3.1 is the only Gemini image model with the 512 tier.
204
+ ["512", "1K", "2K", "4K"]
192
205
  ),
193
206
  geminiImage("gemini-3.1-flash-lite-image", "Nano Banana Lite", ["nb-lite"], ["1K"]),
194
207
  // trigger-workflows validates 1K only; pricing seeds 2K/4K rows so allow all three.
@@ -271,7 +284,8 @@ var IMAGE_MODELS = [
271
284
  "9:16",
272
285
  "4:5",
273
286
  "5:4",
274
- "9:21"
287
+ "9:21",
288
+ "adaptive"
275
289
  ],
276
290
  sizes: ["1K"],
277
291
  references: { images: 10 },
@@ -332,9 +346,10 @@ var IMAGE_MODELS = [
332
346
  constraints: {
333
347
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
334
348
  sizes: ["1K"],
335
- supports: ["outputFormat"]
349
+ // flux-2-pro's job type always returns image/png; only the seed is forwarded.
350
+ supports: ["seed"]
336
351
  },
337
- defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png" },
352
+ defaults: { size: "1K", aspectRatio: "1:1" },
338
353
  usage: { ...IMAGE_USAGE },
339
354
  pricingKind: "image_size"
340
355
  },
@@ -352,7 +367,8 @@ var IMAGE_MODELS = [
352
367
  constraints: {
353
368
  aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
354
369
  sizes: ["1K", "2K", "4K"],
355
- requires: ["references"]
370
+ requires: ["references"],
371
+ supports: ["seed"]
356
372
  },
357
373
  defaults: { size: "1K", aspectRatio: "1:1" },
358
374
  usage: { ...IMAGE_USAGE },
@@ -371,7 +387,8 @@ var IMAGE_MODELS = [
371
387
  constraints: {
372
388
  aspectRatios: ["1:1", "2:3", "3:4", "4:3", "9:16", "16:9", "21:9"],
373
389
  sizes: ["1K"],
374
- requires: ["references"]
390
+ requires: ["references"],
391
+ supports: ["seed"]
375
392
  },
376
393
  defaults: { size: "1K", aspectRatio: "1:1" },
377
394
  usage: { ...IMAGE_USAGE },
@@ -391,7 +408,8 @@ var IMAGE_MODELS = [
391
408
  constraints: {
392
409
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4"],
393
410
  sizes: ["1K", "2K", "4K"],
394
- references: { images: 9 }
411
+ references: { images: 9 },
412
+ supports: []
395
413
  },
396
414
  defaults: { size: "1K", aspectRatio: "1:1" },
397
415
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -412,7 +430,8 @@ var IMAGE_MODELS = [
412
430
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"],
413
431
  sizes: [],
414
432
  references: { images: 1 },
415
- requires: ["references"]
433
+ requires: ["references"],
434
+ supports: []
416
435
  },
417
436
  defaults: { aspectRatio: "1:1" },
418
437
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -454,7 +473,8 @@ var OTHER_MODELS = [
454
473
  lifecycle: "active",
455
474
  constraints: {
456
475
  durations: [30],
457
- references: { images: 10 }
476
+ references: { images: 10 },
477
+ supports: []
458
478
  },
459
479
  defaults: {},
460
480
  usage: { unit: "images", modality: "AUDIO" },
@@ -469,7 +489,8 @@ var OTHER_MODELS = [
469
489
  providerModelId: "lyria-3-pro-preview",
470
490
  lifecycle: "active",
471
491
  constraints: {
472
- references: { images: 10 }
492
+ references: { images: 10 },
493
+ supports: []
473
494
  },
474
495
  defaults: {},
475
496
  usage: { unit: "images", modality: "AUDIO" },
@@ -533,8 +554,12 @@ var OTHER_MODELS = [
533
554
  adapter: "replicate",
534
555
  providerModelId: "topazlabs/image-upscale",
535
556
  lifecycle: "active",
536
- constraints: {},
537
- defaults: {},
557
+ constraints: {
558
+ references: { images: 1 },
559
+ requires: ["references"],
560
+ supports: ["scaleFactor", "outputFormat"]
561
+ },
562
+ defaults: { scaleFactor: 2, outputFormat: "png" },
538
563
  usage: { unit: "compute_seconds", modality: "IMAGE" },
539
564
  pricingKind: "flat"
540
565
  },
@@ -548,7 +573,8 @@ var OTHER_MODELS = [
548
573
  lifecycle: "active",
549
574
  constraints: {
550
575
  references: { images: 1 },
551
- requires: ["references"]
576
+ requires: ["references"],
577
+ supports: []
552
578
  },
553
579
  defaults: {},
554
580
  usage: { unit: "images", modality: "IMAGE" },
@@ -567,7 +593,7 @@ function text(id, label, providerModelId, extra) {
567
593
  adapter: "ai-sdk-text",
568
594
  providerModelId,
569
595
  lifecycle: "active",
570
- constraints: {},
596
+ constraints: { supports: [] },
571
597
  defaults: {},
572
598
  usage: { ...TEXT_USAGE },
573
599
  pricingKind: "token",
@@ -590,7 +616,7 @@ var TEXT_MODELS = [
590
616
  text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol"),
591
617
  // Library key "claude-sonnet-4.5" maps to the SDK id "claude-sonnet-4-5".
592
618
  text("claude-sonnet-4-5", "Claude Sonnet 4.5", "claude-sonnet-4-5", {
593
- aliases: ["claude-sonnet-4.5"]
619
+ aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"]
594
620
  }),
595
621
  // Anthropic retired the dated 4.0 ids; callers that still send them get 4.6.
596
622
  text("claude-sonnet-4-6", "Claude Sonnet 4.6", "claude-sonnet-4-6", {
@@ -606,7 +632,7 @@ var TEXT_MODELS = [
606
632
  aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"]
607
633
  }),
608
634
  text("claude-haiku-4-5", "Claude Haiku 4.5", "claude-haiku-4-5", {
609
- aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001"]
635
+ aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"]
610
636
  }),
611
637
  text("claude-opus-5", "Claude Opus 5", "claude-opus-5", {
612
638
  aliases: ["claude-opus-5.0"]
@@ -640,7 +666,7 @@ var TEXT_MODELS = [
640
666
  // src/catalog/video.ts
641
667
  var VIDEO_USAGE = { unit: "seconds", modality: "VIDEO" };
642
668
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
643
- var KLING_RATIOS = ["16:9", "9:16", "1:1"];
669
+ var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
644
670
  var OMNI_RATIOS = ["16:9", "9:16"];
645
671
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
646
672
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
@@ -732,12 +758,15 @@ var VIDEO_MODELS = [
732
758
  providerModelId: "gemini-omni-flash-preview",
733
759
  lifecycle: "active",
734
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.
735
764
  aspectRatios: [...OMNI_RATIOS],
736
- resolutions: ["720p"],
737
765
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
738
- references: { images: 6, videos: 1 }
766
+ references: { images: 6, videos: 1 },
767
+ supports: []
739
768
  },
740
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
769
+ defaults: {},
741
770
  usage: { ...VIDEO_USAGE },
742
771
  pricingKind: "video_per_second"
743
772
  },
@@ -753,9 +782,10 @@ var VIDEO_MODELS = [
753
782
  aspectRatios: [...OMNI_RATIOS],
754
783
  resolutions: ["360p", "720p", "1080p", "4k"],
755
784
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
756
- references: { images: 6, videos: 1 }
785
+ references: { images: 6, videos: 1 },
786
+ supports: []
757
787
  },
758
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
788
+ defaults: {},
759
789
  usage: { ...VIDEO_USAGE },
760
790
  pricingKind: "video_per_second"
761
791
  },
@@ -849,7 +879,8 @@ var VIDEO_MODELS = [
849
879
  aspectRatios: [...GROK_RATIOS],
850
880
  resolutions: ["480p", "720p"],
851
881
  durations: { min: 1, max: 15 },
852
- references: { images: 7 }
882
+ references: { images: 7 },
883
+ supports: []
853
884
  },
854
885
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
855
886
  usage: { unit: "reported_cost_usd", modality: "VIDEO" },
@@ -1039,7 +1070,8 @@ var VIDEO_MODELS = [
1039
1070
  constraints: {
1040
1071
  aspectRatios: [...KLING_RATIOS],
1041
1072
  durations: { min: 3, max: 10 },
1042
- requires: ["sourceVideo"]
1073
+ requires: ["sourceVideo"],
1074
+ supports: []
1043
1075
  },
1044
1076
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1045
1077
  usage: { ...VIDEO_USAGE },
@@ -1072,7 +1104,7 @@ var VIDEO_MODELS = [
1072
1104
  lifecycle: "active",
1073
1105
  constraints: {
1074
1106
  requires: ["firstFrame"],
1075
- supports: ["seed"]
1107
+ supports: ["seed", "lastFrame"]
1076
1108
  },
1077
1109
  defaults: {},
1078
1110
  usage: { ...VIDEO_USAGE },
@@ -1089,7 +1121,7 @@ var MODELS = [
1089
1121
  ];
1090
1122
 
1091
1123
  // src/resolve-options.ts
1092
- var SIZE_ORDER = ["1K", "2K", "4K"];
1124
+ var SIZE_ORDER = ["512", "1K", "2K", "4K"];
1093
1125
  var RESOLUTION_ORDER = ["360p", "480p", "720p", "768p", "1080p", "2k", "4k"];
1094
1126
  function ratioValue(r) {
1095
1127
  if (r === "adaptive") return 1;
@@ -1183,7 +1215,7 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1183
1215
  const warnings = [];
1184
1216
  const c = model.constraints;
1185
1217
  const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1186
- 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)) {
1187
1219
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1188
1220
  warnings.push({
1189
1221
  code: "ratio_coerced",
@@ -1221,7 +1253,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1221
1253
  model: model.id
1222
1254
  });
1223
1255
  }
1224
- dropUnsupported(merged, model, warnings, ["seed", "quality", "count", "outputFormat"]);
1256
+ dropUnsupported(merged, model, warnings, [
1257
+ "seed",
1258
+ "quality",
1259
+ "count",
1260
+ "outputFormat",
1261
+ "scaleFactor",
1262
+ "safetySettings"
1263
+ ]);
1225
1264
  return { request: merged, warnings };
1226
1265
  }
1227
1266
  function resolveVideoOptions(model, request, onUnsupported = "error") {
@@ -1250,7 +1289,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1250
1289
  delete merged.aspectRatio;
1251
1290
  }
1252
1291
  }
1253
- 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)) {
1254
1293
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1255
1294
  warnings.push({
1256
1295
  code: "ratio_coerced",
@@ -1332,8 +1371,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1332
1371
  return { request: merged, warnings };
1333
1372
  }
1334
1373
  function dropUnsupported(req, model, warnings, fields) {
1335
- const supports = model.constraints.supports;
1336
- if (!supports) return;
1374
+ const supports = model.constraints.supports ?? [];
1337
1375
  for (const field of fields) {
1338
1376
  if (req[field] !== void 0 && !supports.includes(field)) {
1339
1377
  warnings.push({
@@ -1411,8 +1449,45 @@ function keysFromEnv(env, prefix = "") {
1411
1449
  }
1412
1450
 
1413
1451
  // src/retry.ts
1452
+ var import_zod2 = require("zod");
1453
+
1454
+ // src/json.ts
1414
1455
  var import_zod = require("zod");
1415
- 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();
1416
1491
  function classifyHttpError(status, body, provider, model) {
1417
1492
  const asText = textBody.safeParse(body);
1418
1493
  const text2 = asText.success ? asText.data : JSON.stringify(body);
@@ -1495,6 +1570,13 @@ function transportError(provider, cause, model) {
1495
1570
  if (model !== void 0) init.model = model;
1496
1571
  return new ModelKitError(init);
1497
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
+ }
1498
1580
  async function pollUntil(check, opts) {
1499
1581
  const start = Date.now();
1500
1582
  let interval = opts.intervalMs;
@@ -1610,7 +1692,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
1610
1692
 
1611
1693
  // src/client.ts
1612
1694
  var import_ai2 = require("ai");
1613
- var import_zod3 = require("zod");
1695
+ var import_zod4 = require("zod");
1614
1696
 
1615
1697
  // src/adapters/media-ref.ts
1616
1698
  function isUrlRef(ref) {
@@ -1665,7 +1747,7 @@ var import_perplexity = require("@ai-sdk/perplexity");
1665
1747
  var import_xai = require("@ai-sdk/xai");
1666
1748
  var import_deepseek = require("@ai-sdk/deepseek");
1667
1749
  var import_moonshotai = require("@ai-sdk/moonshotai");
1668
- var import_zod2 = require("zod");
1750
+ var import_zod3 = require("zod");
1669
1751
  var TEXT_PROVIDERS = [
1670
1752
  "openai",
1671
1753
  "anthropic",
@@ -1676,7 +1758,7 @@ var TEXT_PROVIDERS = [
1676
1758
  "moonshot",
1677
1759
  "minimax"
1678
1760
  ];
1679
- var textProviderSchema = import_zod2.z.enum(TEXT_PROVIDERS);
1761
+ var textProviderSchema = import_zod3.z.enum(TEXT_PROVIDERS);
1680
1762
  function isTextProvider(value) {
1681
1763
  return textProviderSchema.safeParse(value).success;
1682
1764
  }
@@ -1685,9 +1767,9 @@ var OPENAI_COMPATIBLE_BASE_URLS = {
1685
1767
  };
1686
1768
  var GATEWAY_SLUGS = {
1687
1769
  openai: "openai",
1688
- anthropic: "anthropic",
1770
+ anthropic: "anthropic/v1",
1689
1771
  google: "google-ai-studio/v1beta",
1690
- xai: "grok",
1772
+ xai: "grok/v1",
1691
1773
  perplexity: "perplexity-ai",
1692
1774
  deepseek: "deepseek"
1693
1775
  };
@@ -1862,10 +1944,10 @@ function textAbortOptions(sdk, context) {
1862
1944
  if (abortSignal) return { abortSignal };
1863
1945
  return {};
1864
1946
  }
1865
- var catalogId = import_zod3.z.string();
1866
- var exactSize = import_zod3.z.templateLiteral([import_zod3.z.number(), "x", import_zod3.z.number()]);
1867
- var sdkRatio = import_zod3.z.templateLiteral([import_zod3.z.number(), ":", import_zod3.z.number()]);
1868
- 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"]);
1869
1951
  function isCatalogId(model) {
1870
1952
  return catalogId.safeParse(model).success;
1871
1953
  }
@@ -1922,6 +2004,10 @@ function pushIgnored(warnings, field, from, modelId) {
1922
2004
  message: `${modelId} provider instance does not support ${field}; ignored`
1923
2005
  });
1924
2006
  }
2007
+ function logCoercions(logger, modelId, warnings) {
2008
+ if (warnings.length === 0) return;
2009
+ logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
2010
+ }
1925
2011
  function createModelKit(config, adapters) {
1926
2012
  const catalog = new Catalog(MODELS).withOverrides(config.catalogOverride ?? []);
1927
2013
  const logger = config.logger ?? console;
@@ -1955,6 +2041,10 @@ function createModelKit(config, adapters) {
1955
2041
  logger.warn("[modelkit] usage emit failed", err);
1956
2042
  }
1957
2043
  }
2044
+ function withRowUnit(event) {
2045
+ const row = catalog.get(event.model);
2046
+ return row ? { ...event, unit: row.usage.unit } : event;
2047
+ }
1958
2048
  function textTarget(model, call) {
1959
2049
  if (!isCatalogId(model)) {
1960
2050
  return {
@@ -1995,6 +2085,7 @@ function createModelKit(config, adapters) {
1995
2085
  providerOptions,
1996
2086
  references,
1997
2087
  exactSize: exactSizeField,
2088
+ scaleFactor,
1998
2089
  quality: _quality,
1999
2090
  outputFormat: _outputFormat
2000
2091
  } = req;
@@ -2020,6 +2111,9 @@ function createModelKit(config, adapters) {
2020
2111
  if (_quality !== void 0) pushIgnored(warnings, "quality", _quality, model.modelId);
2021
2112
  if (_outputFormat !== void 0)
2022
2113
  pushIgnored(warnings, "outputFormat", _outputFormat, model.modelId);
2114
+ if (scaleFactor !== void 0)
2115
+ pushIgnored(warnings, "scaleFactor", scaleFactor, model.modelId);
2116
+ logCoercions(logger, model.modelId, warnings);
2023
2117
  const abortSignal = combineSignals(req.abortSignal, call.signal);
2024
2118
  if (abortSignal) options.abortSignal = abortSignal;
2025
2119
  const result = await (0, import_ai2.generateImage)(options);
@@ -2103,6 +2197,7 @@ function createModelKit(config, adapters) {
2103
2197
  if (_mode !== void 0) pushIgnored(warnings, "mode", _mode, model.modelId);
2104
2198
  if (providerOptions) options.providerOptions = providerOptions;
2105
2199
  if (abortSignal) options.abortSignal = abortSignal;
2200
+ logCoercions(logger, model.modelId, warnings);
2106
2201
  const pending = (0, import_ai2.experimental_generateVideo)(options);
2107
2202
  let settled;
2108
2203
  let failed = false;
@@ -2161,6 +2256,7 @@ function createModelKit(config, adapters) {
2161
2256
  call.onUnsupported ?? "error"
2162
2257
  );
2163
2258
  warnings.push(...inputWarnings);
2259
+ logCoercions(logger, model.id, warnings);
2164
2260
  const signal = combineSignals(req.abortSignal, call.signal);
2165
2261
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2166
2262
  if (!adapter.generateImage)
@@ -2170,7 +2266,7 @@ function createModelKit(config, adapters) {
2170
2266
  model: model.id
2171
2267
  });
2172
2268
  const result = await adapter.generateImage(request, ctx);
2173
- const usage2 = { ...result.usage, model: model.id };
2269
+ const usage2 = { ...result.usage, model: model.id, unit: model.usage.unit };
2174
2270
  await emit(usage2);
2175
2271
  const images = result.images.map(toGeneratedImage);
2176
2272
  const first = images[0];
@@ -2203,6 +2299,7 @@ function createModelKit(config, adapters) {
2203
2299
  call.onUnsupported ?? "error"
2204
2300
  );
2205
2301
  warnings.push(...inputWarnings);
2302
+ logCoercions(logger, model.id, warnings);
2206
2303
  const signal = combineSignals(req.abortSignal, call.signal);
2207
2304
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2208
2305
  if (!adapter.generateVideo)
@@ -2220,7 +2317,11 @@ function createModelKit(config, adapters) {
2220
2317
  result(opts) {
2221
2318
  if (settled) return settled;
2222
2319
  const pending = result(opts).then(
2223
- (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),
2224
2325
  (cause) => {
2225
2326
  settled = void 0;
2226
2327
  throw cause;
@@ -2240,7 +2341,8 @@ function createModelKit(config, adapters) {
2240
2341
  model: model.id
2241
2342
  });
2242
2343
  }
2243
- const { adapter, ctx } = context(model, call, []);
2344
+ const warnings = [];
2345
+ const { adapter, ctx } = context(model, call, warnings);
2244
2346
  if (!adapter.generateAudio) {
2245
2347
  throw new ModelKitError({
2246
2348
  code: "unsupported_option",
@@ -2252,7 +2354,8 @@ function createModelKit(config, adapters) {
2252
2354
  { ...model.defaults, ...req, model: model.id },
2253
2355
  ctx
2254
2356
  );
2255
- 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 });
2256
2359
  return result;
2257
2360
  },
2258
2361
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
@@ -2292,7 +2395,7 @@ function createModelKit(config, adapters) {
2292
2395
  options.prepareStep ?? options.experimental_prepareStep
2293
2396
  )
2294
2397
  });
2295
- for (const event of steps.usage(result.steps)) await emit(event);
2398
+ for (const event of steps.usage(result.steps)) await emit(withRowUnit(event));
2296
2399
  return result;
2297
2400
  },
2298
2401
  streamText(options, call = {}) {
@@ -2310,7 +2413,7 @@ function createModelKit(config, adapters) {
2310
2413
  providerOptions: {},
2311
2414
  prepareStep: steps.wrap(options.prepareStep),
2312
2415
  onFinish: async (event) => {
2313
- for (const usage2 of steps.usage(event.steps)) await emit(usage2);
2416
+ for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
2314
2417
  await callerOnFinish?.(event);
2315
2418
  }
2316
2419
  });
@@ -2324,7 +2427,7 @@ function createModelKit(config, adapters) {
2324
2427
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions)
2325
2428
  };
2326
2429
  const result = await (0, import_ai2.generateObject)(sdkOptions);
2327
- await emit(textUsageEvent(entry, provider, result.usage));
2430
+ await emit(withRowUnit(textUsageEvent(entry, provider, result.usage)));
2328
2431
  return result;
2329
2432
  },
2330
2433
  streamObject(options, call = {}) {
@@ -2336,7 +2439,7 @@ function createModelKit(config, adapters) {
2336
2439
  model: languageModel2,
2337
2440
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions),
2338
2441
  onFinish: async (event) => {
2339
- await emit(textUsageEvent(entry, provider, event.usage));
2442
+ await emit(withRowUnit(textUsageEvent(entry, provider, event.usage)));
2340
2443
  await callerOnFinish?.(event);
2341
2444
  }
2342
2445
  };
@@ -2346,7 +2449,7 @@ function createModelKit(config, adapters) {
2346
2449
  }
2347
2450
 
2348
2451
  // src/adapters/ark.ts
2349
- var import_zod4 = require("zod");
2452
+ var import_zod5 = require("zod");
2350
2453
  var ARK_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
2351
2454
  var SUBMIT_PATH = "/contents/generations/tasks";
2352
2455
  var SEEDANCE_POLL_INTERVAL_MS = 15e3;
@@ -2404,7 +2507,7 @@ function arkKey(ctx) {
2404
2507
  return key;
2405
2508
  }
2406
2509
  function throwArkError(status, body, model) {
2407
- const parsed = import_zod4.z.string().safeParse(body);
2510
+ const parsed = import_zod5.z.string().safeParse(body);
2408
2511
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2409
2512
  if (/sensitive.?content|inputimage|human.?face/i.test(text2)) {
2410
2513
  const init = {
@@ -2418,6 +2521,16 @@ function throwArkError(status, body, model) {
2418
2521
  if (status !== void 0) init.status = status;
2419
2522
  throw new ModelKitError(init);
2420
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
+ }
2421
2534
  throw classifyHttpError(status, body, "ark", model);
2422
2535
  }
2423
2536
  function seedreamSize(aspect, size) {
@@ -2436,13 +2549,13 @@ function arkUrl(ref) {
2436
2549
  if ("url" in ref) return ref.url;
2437
2550
  return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2438
2551
  }
2439
- var SeedreamImageSchema = import_zod4.z.object({
2440
- url: import_zod4.z.string().optional(),
2441
- 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()
2442
2555
  });
2443
- var SeedreamResponseSchema = import_zod4.z.object({
2444
- data: import_zod4.z.array(SeedreamImageSchema).optional(),
2445
- 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()
2446
2559
  });
2447
2560
  function retryOptsFor(ctx, attempts = 3) {
2448
2561
  const opts = { attempts };
@@ -2453,6 +2566,11 @@ function fetchInitFor(ctx, init) {
2453
2566
  if (ctx.signal !== void 0) init.signal = ctx.signal;
2454
2567
  return init;
2455
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
+ }
2456
2574
  async function generateSeedreamImage(req, ctx) {
2457
2575
  const key = arkKey(ctx);
2458
2576
  const modelId = ctx.model.id;
@@ -2470,14 +2588,11 @@ async function generateSeedreamImage(req, ctx) {
2470
2588
  if (refs.length === 1 && firstRef !== void 0) body.image = firstRef;
2471
2589
  else if (refs.length > 1) body.image = refs;
2472
2590
  const data = await withRetry(async () => {
2473
- const res = await ctx.fetch(
2474
- `${arkBaseUrl(ctx)}/images/generations`,
2475
- fetchInitFor(ctx, {
2476
- method: "POST",
2477
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2478
- body: JSON.stringify(body)
2479
- })
2480
- );
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
+ });
2481
2596
  if (!res.ok) {
2482
2597
  const text2 = await res.text().catch(() => "");
2483
2598
  throwArkError(res.status, text2, modelId);
@@ -2492,7 +2607,7 @@ async function generateSeedreamImage(req, ctx) {
2492
2607
  bytes = Buffer.from(first.b64_json, "base64");
2493
2608
  } else if (first?.url) {
2494
2609
  const imageUrl = first.url;
2495
- const res = await ctx.fetch(imageUrl, fetchInitFor(ctx, {}));
2610
+ const res = await arkFetch(ctx, imageUrl, {});
2496
2611
  if (!res.ok) {
2497
2612
  const text2 = await res.text().catch(() => "");
2498
2613
  throwArkError(res.status, text2, modelId);
@@ -2512,13 +2627,13 @@ async function generateSeedreamImage(req, ctx) {
2512
2627
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
2513
2628
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
2514
2629
  }
2515
- var SeedanceResponseSchema = import_zod4.z.object({
2516
- id: import_zod4.z.string().optional(),
2517
- status: import_zod4.z.string().optional(),
2518
- content: import_zod4.z.object({ video_url: import_zod4.z.string().optional() }).optional(),
2519
- 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()
2520
2635
  });
2521
- 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() });
2522
2637
  function seedanceUsage(ctx, req, duration) {
2523
2638
  const usage2 = {
2524
2639
  model: ctx.model.id,
@@ -2532,7 +2647,7 @@ function seedanceUsage(ctx, req, duration) {
2532
2647
  return usage2;
2533
2648
  }
2534
2649
  function seedanceErrorMessage(error, status) {
2535
- const asString = import_zod4.z.string().safeParse(error);
2650
+ const asString = import_zod5.z.string().safeParse(error);
2536
2651
  if (asString.success) return asString.data;
2537
2652
  const asObject = SeedanceErrorMessageSchema.safeParse(error);
2538
2653
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
@@ -2597,14 +2712,11 @@ async function generateSeedanceVideo(req, ctx) {
2597
2712
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
2598
2713
  if (req.seed !== void 0) body.seed = req.seed;
2599
2714
  const submit = await withRetry(async () => {
2600
- const res = await ctx.fetch(
2601
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}`,
2602
- fetchInitFor(ctx, {
2603
- method: "POST",
2604
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2605
- body: JSON.stringify(body)
2606
- })
2607
- );
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
+ });
2608
2720
  if (!res.ok) {
2609
2721
  const text2 = await res.text().catch(() => "");
2610
2722
  throwArkError(res.status, text2, modelId);
@@ -2617,12 +2729,9 @@ async function generateSeedanceVideo(req, ctx) {
2617
2729
  const jobId = submit.id;
2618
2730
  const usage2 = seedanceUsage(ctx, req, duration);
2619
2731
  const fetchStatus = async () => {
2620
- const res = await ctx.fetch(
2621
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`,
2622
- fetchInitFor(ctx, {
2623
- headers: { Authorization: `Bearer ${key}` }
2624
- })
2625
- );
2732
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
2733
+ headers: { Authorization: `Bearer ${key}` }
2734
+ });
2626
2735
  if (!res.ok) {
2627
2736
  if (res.status === 429 || res.status >= 500) return void 0;
2628
2737
  const text2 = await res.text().catch(() => "");
@@ -2683,43 +2792,6 @@ async function generateSeedanceVideo(req, ctx) {
2683
2792
  // src/adapters/fal.ts
2684
2793
  var import_zod6 = require("zod");
2685
2794
  var import_client = require("@fal-ai/client");
2686
-
2687
- // src/json.ts
2688
- var import_zod5 = require("zod");
2689
- var JsonValueSchema = import_zod5.z.lazy(
2690
- () => import_zod5.z.union([
2691
- import_zod5.z.string(),
2692
- import_zod5.z.number(),
2693
- import_zod5.z.boolean(),
2694
- import_zod5.z.null(),
2695
- import_zod5.z.array(JsonValueSchema),
2696
- import_zod5.z.record(import_zod5.z.string(), JsonValueSchema)
2697
- ])
2698
- );
2699
- var JsonObjectSchema = import_zod5.z.record(import_zod5.z.string(), JsonValueSchema);
2700
- async function readErrorBody(res) {
2701
- const text2 = await res.text().catch(() => "");
2702
- try {
2703
- return JsonValueSchema.parse(JSON.parse(text2));
2704
- } catch {
2705
- return text2;
2706
- }
2707
- }
2708
- var thrownErrorSchema = import_zod5.z.object({
2709
- message: import_zod5.z.string().optional(),
2710
- status: import_zod5.z.number().optional(),
2711
- statusCode: import_zod5.z.number().optional(),
2712
- responseBody: import_zod5.z.string().optional()
2713
- });
2714
- function describeThrown(cause) {
2715
- const parsed = thrownErrorSchema.safeParse(cause);
2716
- if (!parsed.success) return { message: String(cause), status: void 0, body: String(cause) };
2717
- const { message, status, statusCode, responseBody } = parsed.data;
2718
- const body = responseBody ?? message ?? String(cause);
2719
- return { message: message ?? String(cause), status: status ?? statusCode, body };
2720
- }
2721
-
2722
- // src/adapters/fal.ts
2723
2795
  var MUSE_T2I_ENDPOINT = "meta/muse-image/text-to-image";
2724
2796
  var MUSE_EDIT_ENDPOINT = "meta/muse-image/edit";
2725
2797
  var KLING_O1_ENDPOINT = "fal-ai/kling-video/o1/video-to-video/reference";
@@ -2731,10 +2803,33 @@ function defaultCreateFalClient(opts) {
2731
2803
  const client2 = (0, import_client.createFalClient)(opts);
2732
2804
  return {
2733
2805
  async subscribe(endpoint, options) {
2734
- const outcome = await client2.subscribe(endpoint, { input: options.input });
2806
+ const outcome = await client2.subscribe(endpoint, options);
2735
2807
  const unwrapped = falSubscribePayloadSchema.safeParse(outcome);
2736
2808
  if (unwrapped.success) return unwrapped.data.data;
2737
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
+ }
2738
2833
  }
2739
2834
  };
2740
2835
  }
@@ -2776,15 +2871,17 @@ var falSdkThrownSchema = import_zod6.z.object({
2776
2871
  message: import_zod6.z.string().optional()
2777
2872
  });
2778
2873
  function falSdkError(cause, model) {
2779
- if (isModelKitError(cause)) return cause;
2780
2874
  const parsed = falSdkThrownSchema.safeParse(cause);
2781
2875
  if (parsed.success) {
2782
2876
  const status = parsed.data.status ?? parsed.data.statusCode;
2783
2877
  const body = parsed.data.body ?? parsed.data.message ?? String(cause);
2784
- return falError(status, body, model);
2878
+ return classifyThrown("fal", cause, model, { status, body: liftDetail(body) });
2785
2879
  }
2786
2880
  const info = describeThrown(cause);
2787
- return falError(info.status, info.body, model);
2881
+ return classifyThrown("fal", cause, model, {
2882
+ status: info.status,
2883
+ body: liftDetail(info.body)
2884
+ });
2788
2885
  }
2789
2886
  function gatewayConfig(ctx) {
2790
2887
  const cf = ctx.routing.cloudflare;
@@ -2866,7 +2963,7 @@ async function passthroughRequest(ctx, endpoint, input) {
2866
2963
  }
2867
2964
  return JsonValueSchema.parse(await resultRes.json());
2868
2965
  }
2869
- async function subscribe(ctx, deps, endpoint, input) {
2966
+ function falClientOf(ctx, deps) {
2870
2967
  const falKey = ctx.keys.fal;
2871
2968
  if (!falKey) {
2872
2969
  throw new ModelKitError({
@@ -2877,12 +2974,19 @@ async function subscribe(ctx, deps, endpoint, input) {
2877
2974
  retryable: false
2878
2975
  });
2879
2976
  }
2880
- 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
+ };
2881
2985
  try {
2882
2986
  return await withRetry(
2883
2987
  async () => {
2884
2988
  try {
2885
- return await client2.subscribe(endpoint, { input });
2989
+ return await client2.subscribe(endpoint, options);
2886
2990
  } catch (cause) {
2887
2991
  throw falSdkError(cause, ctx.model.id);
2888
2992
  }
@@ -3016,13 +3120,14 @@ function klingO1Input(req) {
3016
3120
  });
3017
3121
  }
3018
3122
  const duration = Math.min(10, Math.max(3, Math.round(req.durationSeconds ?? 5)));
3019
- const ratio = req.aspectRatio === "16:9" || req.aspectRatio === "9:16" || req.aspectRatio === "1:1" ? req.aspectRatio : "auto";
3020
3123
  const input = {
3021
3124
  prompt: req.prompt,
3022
3125
  video_url: source,
3023
- duration: String(duration),
3024
- aspect_ratio: ratio
3126
+ duration: String(duration)
3025
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
+ }
3026
3131
  const refs = (req.referenceImages ?? []).map(refToUrl);
3027
3132
  if (refs.length > 0) input.image_urls = refs;
3028
3133
  return input;
@@ -3051,13 +3156,7 @@ async function generateFalVideo(req, ctx, deps) {
3051
3156
  if (ctx.routing.fal === "cloudflare-passthrough") {
3052
3157
  return await passthroughVideoJob(ctx, req, KLING_O1_ENDPOINT, input);
3053
3158
  }
3054
- const result2 = await runJob(ctx, deps, KLING_O1_ENDPOINT, input);
3055
- return completedVideoJob(
3056
- ctx,
3057
- req,
3058
- extractVideoUrl(result2, KLING_O1_ENDPOINT, ctx.model.id),
3059
- result2
3060
- );
3159
+ return await submitQueueJob(ctx, req, deps, KLING_O1_ENDPOINT, input);
3061
3160
  }
3062
3161
  const family = minimaxFamily(providerModelId);
3063
3162
  const refs = {
@@ -3086,19 +3185,81 @@ async function generateFalVideo(req, ctx, deps) {
3086
3185
  if (ctx.routing.fal === "cloudflare-passthrough") {
3087
3186
  return await passthroughVideoJob(ctx, req, endpoint, base);
3088
3187
  }
3089
- const result = await runJob(ctx, deps, endpoint, base);
3090
- return completedVideoJob(ctx, req, extractVideoUrl(result, endpoint, ctx.model.id), result);
3188
+ return await submitQueueJob(ctx, req, deps, endpoint, base);
3189
+ }
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);
3091
3211
  }
3092
- function completedVideoJob(ctx, req, url, raw) {
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
+ };
3093
3224
  const duration = req.durationSeconds ?? 5;
3094
- const result = { video: { url }, usage: videoUsage(ctx, req, duration), raw };
3095
3225
  return {
3096
- jobId: url,
3226
+ jobId: requestId,
3097
3227
  async poll() {
3098
- 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
+ }
3099
3238
  },
3100
- async result() {
3101
- 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 };
3102
3263
  }
3103
3264
  };
3104
3265
  }
@@ -3449,9 +3610,7 @@ function sdkStatus(cause) {
3449
3610
  return describeThrown(cause).status;
3450
3611
  }
3451
3612
  function throwSdkError(cause, model) {
3452
- if (cause instanceof ModelKitError) throw cause;
3453
- const info = describeThrown(cause);
3454
- throw classifyHttpError(info.status, info.body, "google-genai", model);
3613
+ throw classifyThrown("google-genai", cause, model);
3455
3614
  }
3456
3615
  function toBase64(bytes) {
3457
3616
  return Buffer.from(bytes).toString("base64");
@@ -3655,12 +3814,17 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3655
3814
  const duration = req.durationSeconds ?? 8;
3656
3815
  const images = req.referenceImages ?? [];
3657
3816
  const videos = req.referenceVideos ?? [];
3658
- 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";
3659
- const responseFormat = { type: "video" };
3660
- if (req.sourceVideo === void 0) responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
3661
- const omniResolution = toOmniResolution(req.resolution);
3662
- if (omniResolution !== void 0) responseFormat.resolution = omniResolution;
3663
- 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`;
3664
3828
  const client2 = createGenAIClient({ apiKey });
3665
3829
  const uploadedByUri = /* @__PURE__ */ new Map();
3666
3830
  const uploadedNames = [];
@@ -3684,7 +3848,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3684
3848
  model: providerModelId,
3685
3849
  input,
3686
3850
  response_format: responseFormat,
3687
- generation_config: { video_config: { task } }
3851
+ generation_config: { video_config: { task } },
3852
+ store: true
3688
3853
  });
3689
3854
  const createRetryOptions = { attempts: 3 };
3690
3855
  if (ctx.signal !== void 0) createRetryOptions.signal = ctx.signal;
@@ -3766,23 +3931,14 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3766
3931
  };
3767
3932
  return inline;
3768
3933
  });
3769
- const inlineRetryOptions = { attempts: 3 };
3770
- if (ctx.signal !== void 0) inlineRetryOptions.signal = ctx.signal;
3771
3934
  try {
3772
- interaction = await withRetry(async () => {
3773
- try {
3774
- return await callCreate(inlineParts);
3775
- } catch (inlineCause) {
3776
- throwSdkError(inlineCause, modelId);
3777
- }
3778
- }, inlineRetryOptions);
3935
+ interaction = await callCreate(inlineParts);
3779
3936
  } catch (inlineCause) {
3780
3937
  throwSdkError(inlineCause, modelId);
3781
3938
  }
3782
3939
  }
3783
- } catch (cause) {
3940
+ } finally {
3784
3941
  await cleanupUploads();
3785
- throw cause;
3786
3942
  }
3787
3943
  const jobId = interaction.id ?? "gemini-omni-interaction";
3788
3944
  const usage2 = videoUsage2(ctx, req, duration);
@@ -3811,47 +3967,43 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3811
3967
  timeoutMs: opts?.timeoutMs ?? RESULT_TIMEOUT_MS2
3812
3968
  };
3813
3969
  if (signal !== void 0) pollOptions.signal = signal;
3814
- try {
3815
- const done = await pollUntil(async () => {
3816
- const current = await getInteraction();
3817
- const status = (current.status ?? "").toUpperCase();
3818
- if (status === "COMPLETED") return current;
3819
- if (status === "FAILED") {
3820
- throw classifyHttpError(
3821
- void 0,
3822
- `Gemini Omni interaction failed: ${JSON.stringify(current).slice(0, 500)}`,
3823
- "google-genai",
3824
- modelId
3825
- );
3826
- }
3827
- return void 0;
3828
- }, pollOptions);
3829
- const video = extractOmniVideo(done, modelId);
3830
- if (video.data) {
3831
- return {
3832
- video: {
3833
- bytes: Buffer.from(video.data, "base64"),
3834
- mime: video.mime_type ?? "video/mp4"
3835
- },
3836
- usage: usage2,
3837
- raw: done
3838
- };
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
+ );
3839
3981
  }
3840
- if (video.uri)
3841
- return {
3842
- video: await downloadVideo(ctx, video.uri, apiKey, signal),
3843
- usage: usage2,
3844
- raw: done
3845
- };
3846
- throw classifyHttpError(
3847
- void 0,
3848
- "No video content in Gemini Omni response",
3849
- "google-genai",
3850
- modelId
3851
- );
3852
- } finally {
3853
- 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
+ };
3854
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
+ );
3855
4007
  }
3856
4008
  };
3857
4009
  }
@@ -4020,8 +4172,14 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4020
4172
  content.push({ type: "text", text: req.prompt });
4021
4173
  void ctx.call.postCropToAspect;
4022
4174
  const imageConfig = {};
4023
- if (req.aspectRatio !== void 0) imageConfig.aspectRatio = req.aspectRatio;
4175
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4176
+ imageConfig.aspectRatio = req.aspectRatio;
4024
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;
4025
4183
  const retryOptions = {};
4026
4184
  if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4027
4185
  const result = await withRetry(async () => {
@@ -4033,22 +4191,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4033
4191
  messages: [{ role: "user", content }],
4034
4192
  maxRetries: 0,
4035
4193
  providerOptions: {
4036
- google: {
4037
- imageConfig,
4038
- responseModalities: ["IMAGE"],
4039
- safetySettings: [
4040
- {
4041
- category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
4042
- threshold: "OFF"
4043
- },
4044
- { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "OFF" },
4045
- {
4046
- category: "HARM_CATEGORY_DANGEROUS_CONTENT",
4047
- threshold: "OFF"
4048
- },
4049
- { category: "HARM_CATEGORY_HARASSMENT", threshold: "OFF" }
4050
- ]
4051
- }
4194
+ google: googleOptions
4052
4195
  },
4053
4196
  abortSignal: signal
4054
4197
  });
@@ -4077,6 +4220,10 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4077
4220
  imageQuality: "auto"
4078
4221
  };
4079
4222
  if (req.size !== void 0) usage2.imageSize = req.size;
4223
+ if (result.usage?.inputTokens !== void 0)
4224
+ usage2.inputTokens = result.usage.inputTokens;
4225
+ if (result.usage?.outputTokens !== void 0)
4226
+ usage2.outputTokens = result.usage.outputTokens;
4080
4227
  return { images, usage: usage2, raw: result };
4081
4228
  }
4082
4229
  };
@@ -4231,6 +4378,7 @@ var KLING_MAX_INTERVAL_MS = 1e4;
4231
4378
  var KLING_TIMEOUT_MS = 15 * 6e4;
4232
4379
  var DOP_INTERVAL_MS = 5e3;
4233
4380
  var DOP_TIMEOUT_MS = 5 * 6e4;
4381
+ var DOP_FALLBACK_DURATION_SECONDS = 5;
4234
4382
  var DEFAULT_NEGATIVE_PROMPT = "text, watermark, copyright, blur, low quality, distortion, abstract, weird, deformed";
4235
4383
  function credentials(ctx) {
4236
4384
  const key = ctx.keys.higgsfield;
@@ -4305,6 +4453,18 @@ function requestInit(ctx, init) {
4305
4453
  if (ctx.signal !== void 0) request.signal = ctx.signal;
4306
4454
  return request;
4307
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
+ }
4308
4468
  async function generateKlingVideo(req, ctx) {
4309
4469
  const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4310
4470
  if (!firstFrame) {
@@ -4323,26 +4483,16 @@ async function generateKlingVideo(req, ctx) {
4323
4483
  negative_prompt: req.negativePrompt ?? DEFAULT_NEGATIVE_PROMPT
4324
4484
  };
4325
4485
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
4326
- 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;
4327
4488
  if (req.lastFrame) body.last_image_url = refToUrl2(req.lastFrame);
4328
4489
  const endpoint = klingEndpoint(ctx.model.providerModelId);
4329
- let createRes;
4330
- try {
4331
- createRes = await ctx.fetch(
4332
- endpoint,
4333
- requestInit(ctx, { method: "POST", body: JSON.stringify(body) })
4334
- );
4335
- } catch (cause) {
4336
- throw networkError(cause, ctx);
4337
- }
4338
- if (!createRes.ok) {
4339
- throw classifyHttpError(
4340
- createRes.status,
4341
- await readBody2(createRes),
4342
- "higgsfield",
4343
- ctx.model.id
4344
- );
4345
- }
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
+ );
4346
4496
  const created = klingCreateSchema.safeParse(await createRes.json());
4347
4497
  if (!created.success) {
4348
4498
  throw new ModelKitError({
@@ -4422,11 +4572,6 @@ async function generateKlingVideo(req, ctx) {
4422
4572
  }
4423
4573
  };
4424
4574
  }
4425
- function networkError(cause, ctx) {
4426
- if (isModelKitError(cause)) return cause;
4427
- const info = describeThrown(cause);
4428
- return classifyHttpError(info.status, info.body, "higgsfield", ctx.model.id);
4429
- }
4430
4575
  var dopMotionOptionsSchema = import_zod10.z.object({
4431
4576
  modelkit: import_zod10.z.object({ motion: import_zod10.z.string().optional() }).optional()
4432
4577
  });
@@ -4498,26 +4643,15 @@ async function generateDopVideo(req, ctx) {
4498
4643
  params.input_images_end = [{ type: "image_url", image_url: refToUrl2(req.lastFrame) }];
4499
4644
  }
4500
4645
  if (req.seed !== void 0) params.seed = req.seed;
4501
- let createRes;
4502
- try {
4503
- createRes = await ctx.fetch(
4504
- DOP_ENDPOINT,
4505
- requestInit(ctx, {
4506
- method: "POST",
4507
- body: JSON.stringify({ params, webhook: null })
4508
- })
4509
- );
4510
- } catch (cause) {
4511
- throw networkError(cause, ctx);
4512
- }
4513
- if (!createRes.ok) {
4514
- throw classifyHttpError(
4515
- createRes.status,
4516
- await readBody2(createRes),
4517
- "higgsfield",
4518
- ctx.model.id
4519
- );
4520
- }
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
+ );
4521
4655
  const created = dopCreateSchema.safeParse(await createRes.json());
4522
4656
  if (!created.success) {
4523
4657
  throw new ModelKitError({
@@ -4586,7 +4720,10 @@ async function generateDopVideo(req, ctx) {
4586
4720
  };
4587
4721
  if (dopSignal !== void 0) pollSettings.signal = dopSignal;
4588
4722
  const url = await pollUntil(check, pollSettings);
4589
- 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
+ };
4590
4727
  return result;
4591
4728
  }
4592
4729
  };
@@ -4608,7 +4745,7 @@ function aspectRatioToSize(ratio, tier) {
4608
4745
  };
4609
4746
  const MIN_PIXELS = 655360;
4610
4747
  const MAX_PIXELS = 8294400;
4611
- const maxLong = TIER_LONG_EDGE[tier];
4748
+ const maxLong = TIER_LONG_EDGE[tier] ?? 1024;
4612
4749
  const RATIO_MAP = /* @__PURE__ */ new Map([
4613
4750
  ["1:1", [1, 1]],
4614
4751
  ["16:9", [16, 9]],
@@ -4768,28 +4905,16 @@ var openaiImageAdapter = {
4768
4905
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
4769
4906
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
4770
4907
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
4771
- let usage2;
4772
- if (inputTokens !== void 0 || outputTokens !== void 0) {
4773
- usage2 = {
4774
- model: ctx.model.id,
4775
- provider: "openai-image",
4776
- modality: "IMAGE",
4777
- unit: "tokens",
4778
- quantity: (inputTokens ?? 0) + (outputTokens ?? 0),
4779
- imageQuality: quality
4780
- };
4781
- if (inputTokens !== void 0) usage2.inputTokens = inputTokens;
4782
- if (outputTokens !== void 0) usage2.outputTokens = outputTokens;
4783
- } else {
4784
- usage2 = {
4785
- model: ctx.model.id,
4786
- provider: "openai-image",
4787
- modality: "IMAGE",
4788
- unit: "images",
4789
- quantity: images.length,
4790
- imageQuality: quality
4791
- };
4792
- }
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;
4793
4918
  if (req.size !== void 0) usage2.imageSize = req.size;
4794
4919
  return { images, usage: usage2, raw: response };
4795
4920
  }
@@ -4842,7 +4967,12 @@ var NANO_BANANA_RATIOS = /* @__PURE__ */ new Set([
4842
4967
  ]);
4843
4968
  async function refToBytes(ctx, ref) {
4844
4969
  if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
4845
- 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
+ }
4846
4976
  if (!res.ok) {
4847
4977
  const text2 = await res.text().catch(() => "");
4848
4978
  throw classifyHttpError(res.status, text2, "prodia", ctx.model.id);
@@ -5012,8 +5142,7 @@ async function generateProdiaImage(req, ctx) {
5012
5142
  body: form
5013
5143
  });
5014
5144
  } catch (err) {
5015
- if (isModelKitError(err)) throw err;
5016
- throw transportError("prodia", err, ctx.model.id);
5145
+ throw classifyThrown("prodia", err, ctx.model.id);
5017
5146
  }
5018
5147
  if (!attemptRes.ok) {
5019
5148
  const text2 = await attemptRes.text().catch(() => "");
@@ -5022,8 +5151,7 @@ async function generateProdiaImage(req, ctx) {
5022
5151
  return attemptRes;
5023
5152
  }, retryOpts);
5024
5153
  } catch (err) {
5025
- if (isModelKitError(err)) throw err;
5026
- throw transportError("prodia", err, ctx.model.id);
5154
+ throw classifyThrown("prodia", err, ctx.model.id);
5027
5155
  }
5028
5156
  const bytes = parseImageResponse(
5029
5157
  new Uint8Array(await res.arrayBuffer()),
@@ -5095,7 +5223,7 @@ function replicateError(cause, ctx) {
5095
5223
  const info = describeThrown(cause);
5096
5224
  const nested = replicateResponseStatusSchema.safeParse(cause);
5097
5225
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5098
- return classifyHttpError(status, info.body, "replicate", ctx.model.id);
5226
+ return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
5099
5227
  }
5100
5228
  function isLower(id) {
5101
5229
  return id.toLowerCase();
@@ -5242,6 +5370,9 @@ function isUpscaler(providerModelId) {
5242
5370
  const id = isLower(providerModelId);
5243
5371
  return id.includes("upscal") || id.includes("crystal") || id.includes("topaz");
5244
5372
  }
5373
+ function isTopazUpscaler(providerModelId) {
5374
+ return isLower(providerModelId).includes("topazlabs/image-upscale");
5375
+ }
5245
5376
  function isQwen(providerModelId) {
5246
5377
  return isLower(providerModelId).includes("qwen");
5247
5378
  }
@@ -5291,8 +5422,36 @@ function wanImageSize(aspectRatio, size) {
5291
5422
  }
5292
5423
  async function generateReplicateImage(req, ctx, deps) {
5293
5424
  const id = ctx.model.providerModelId;
5294
- const input = { prompt: req.prompt };
5295
- if (isUpscaler(id)) {
5425
+ let input;
5426
+ if (isTopazUpscaler(id)) {
5427
+ const first = (req.references ?? [])[0];
5428
+ if (!first) {
5429
+ throw new ModelKitError({
5430
+ code: "missing_input",
5431
+ message: `${ctx.model.id} requires a reference image to upscale`,
5432
+ provider: "replicate",
5433
+ model: ctx.model.id,
5434
+ retryable: false
5435
+ });
5436
+ }
5437
+ let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
5438
+ if (format !== "png" && format !== "jpg") {
5439
+ ctx.warnings.push({
5440
+ code: "option_ignored",
5441
+ field: "outputFormat",
5442
+ from: format,
5443
+ message: "topazlabs/image-upscale supports only png and jpg; using png"
5444
+ });
5445
+ format = "png";
5446
+ }
5447
+ input = {
5448
+ image: refToUrl3(first),
5449
+ enhance_model: "Standard V2",
5450
+ output_format: format,
5451
+ upscale_factor: `${req.scaleFactor ?? 2}x`,
5452
+ face_enhancement: true
5453
+ };
5454
+ } else if (isUpscaler(id)) {
5296
5455
  const refs = req.references ?? [];
5297
5456
  const first = refs[0];
5298
5457
  if (!first) {
@@ -5304,24 +5463,29 @@ async function generateReplicateImage(req, ctx, deps) {
5304
5463
  retryable: false
5305
5464
  });
5306
5465
  }
5307
- input.image = refToUrl3(first);
5308
- input.creativity = 0;
5309
- input.scale_factor = 2;
5310
- input.output_format = "png";
5466
+ const imageInput = { prompt: req.prompt };
5467
+ imageInput.image = refToUrl3(first);
5468
+ imageInput.creativity = 0;
5469
+ imageInput.scale_factor = 2;
5470
+ imageInput.output_format = "png";
5471
+ input = imageInput;
5311
5472
  } else if (isWanImage(id)) {
5312
5473
  const refs = (req.references ?? []).map(refToUrl3);
5313
- if (refs.length > 0) input.images = refs;
5314
- input.size = wanImageSize(req.aspectRatio, req.size);
5474
+ const imageInput = { prompt: req.prompt };
5475
+ if (refs.length > 0) imageInput.images = refs;
5476
+ imageInput.size = wanImageSize(req.aspectRatio, req.size);
5477
+ input = imageInput;
5315
5478
  } else if (isQwen(id)) {
5316
5479
  const refs = (req.references ?? []).map(refToUrl3);
5317
5480
  const firstUrl = refs[0];
5481
+ const imageInput = { prompt: req.prompt };
5318
5482
  if (firstUrl !== void 0) {
5319
- input.image = firstUrl;
5320
- if (!isQwenEditPlus(id)) input.match_input_image = true;
5483
+ imageInput.image = firstUrl;
5484
+ if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
5321
5485
  }
5322
5486
  const ratios = isQwenEditPlus(id) ? QWEN_EDIT_RATIOS : QWEN_IMAGE_RATIOS;
5323
5487
  if (req.aspectRatio !== void 0) {
5324
- if (ratios.has(req.aspectRatio)) input.aspect_ratio = req.aspectRatio;
5488
+ if (ratios.has(req.aspectRatio)) imageInput.aspect_ratio = req.aspectRatio;
5325
5489
  else
5326
5490
  ctx.warnings.push({
5327
5491
  code: "option_ignored",
@@ -5331,18 +5495,21 @@ async function generateReplicateImage(req, ctx, deps) {
5331
5495
  });
5332
5496
  }
5333
5497
  if (isQwenEditPlus(id) && req.outputFormat !== void 0) {
5334
- input.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5498
+ imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5335
5499
  }
5500
+ input = imageInput;
5336
5501
  } else {
5337
5502
  const refs = req.references ?? [];
5338
5503
  const first = refs[0];
5339
- if (first) input.image = refToUrl3(first);
5504
+ const imageInput = { prompt: req.prompt };
5505
+ if (first) imageInput.image = refToUrl3(first);
5506
+ input = imageInput;
5340
5507
  }
5341
5508
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
5342
5509
  const file = await download(ctx, url);
5343
5510
  const usage2 = imageUsage2(ctx, req);
5344
5511
  usage2.quantity = predictTime;
5345
- return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage2, raw };
5512
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage2, raw, outputUrl: url };
5346
5513
  }
5347
5514
  function wanSize(aspectRatio) {
5348
5515
  if (!aspectRatio || aspectRatio === "adaptive" || aspectRatio === "1:1") return "2K";
@@ -5366,7 +5533,7 @@ function klingInput(req) {
5366
5533
  input.start_image = startImage;
5367
5534
  const endImage = images[1];
5368
5535
  if (endImage !== void 0) input.end_image = endImage;
5369
- } else {
5536
+ } else if (req.aspectRatio !== "adaptive") {
5370
5537
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5371
5538
  }
5372
5539
  if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
@@ -5386,7 +5553,7 @@ function klingOmniInput(req) {
5386
5553
  input.start_image = startImage;
5387
5554
  const endImage = images[1];
5388
5555
  if (endImage !== void 0) input.end_image = endImage;
5389
- } else {
5556
+ } else if (req.aspectRatio !== "adaptive") {
5390
5557
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5391
5558
  }
5392
5559
  const refs = (req.referenceImages ?? []).map(refToUrl3);
@@ -5595,11 +5762,10 @@ var xaiResponseStatusSchema = import_zod13.z.object({
5595
5762
  response: import_zod13.z.object({ status: import_zod13.z.number() }).partial()
5596
5763
  });
5597
5764
  function xaiError(cause, ctx) {
5598
- if (isModelKitError(cause)) return cause;
5599
5765
  const info = describeThrown(cause);
5600
5766
  const nested = xaiResponseStatusSchema.safeParse(cause);
5601
5767
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5602
- return classifyHttpError(status, info.body, "xai-video", ctx.model.id);
5768
+ return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
5603
5769
  }
5604
5770
  var xaiMetaSchema = import_zod13.z.object({
5605
5771
  videoUrl: JsonValueSchema.optional(),
@@ -5623,10 +5789,7 @@ async function generateXaiVideo(req, ctx, deps) {
5623
5789
  retryable: false
5624
5790
  });
5625
5791
  }
5626
- const frames = [req.firstFrame, req.lastFrame, ...req.referenceImages ?? []].filter(
5627
- (r) => r !== void 0
5628
- );
5629
- const refUrls = frames.map(refToUrl4).slice(0, 5);
5792
+ const refUrls = (req.referenceImages ?? []).map(refToUrl4).slice(0, 7);
5630
5793
  const resolution = req.resolution === "480p" ? "480p" : "720p";
5631
5794
  const xaiOptions = {
5632
5795
  resolution,
@@ -5637,13 +5800,23 @@ async function generateXaiVideo(req, ctx, deps) {
5637
5800
  xaiOptions.mode = "reference-to-video";
5638
5801
  xaiOptions.referenceImageUrls = refUrls;
5639
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
+ }
5640
5810
  const client2 = deps.createXaiClient({ apiKey });
5641
- 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);
5642
5812
  const callBody = {
5643
5813
  model,
5644
5814
  prompt: req.prompt,
5645
5815
  providerOptions: { xai: xaiOptions }
5646
5816
  };
5817
+ if (req.firstFrame) {
5818
+ callBody.frameImages = [{ image: refToUrl4(req.firstFrame), frameType: "first_frame" }];
5819
+ }
5647
5820
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5648
5821
  callBody.aspectRatio = req.aspectRatio;
5649
5822
  }
@@ -5729,26 +5902,14 @@ async function mapResult(ctx, req, result) {
5729
5902
  function usage(ctx, req, meta) {
5730
5903
  const costTicks = import_zod13.z.number().safeParse(meta.costInUsdTicks);
5731
5904
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
5732
- if (cost !== void 0) {
5733
- const event2 = {
5734
- model: ctx.model.id,
5735
- provider: "xai-video",
5736
- modality: "VIDEO",
5737
- unit: "reported_cost_usd",
5738
- quantity: cost,
5739
- reportedCostUsd: cost
5740
- };
5741
- if (req.durationSeconds !== void 0) event2.durationSeconds = req.durationSeconds;
5742
- if (req.resolution !== void 0) event2.resolution = req.resolution;
5743
- return event2;
5744
- }
5745
5905
  const event = {
5746
5906
  model: ctx.model.id,
5747
5907
  provider: "xai-video",
5748
5908
  modality: "VIDEO",
5749
- unit: "seconds",
5750
- quantity: req.durationSeconds ?? 0
5909
+ unit: "reported_cost_usd",
5910
+ quantity: cost ?? 0
5751
5911
  };
5912
+ if (cost !== void 0) event.reportedCostUsd = cost;
5752
5913
  if (req.durationSeconds !== void 0) event.durationSeconds = req.durationSeconds;
5753
5914
  if (req.resolution !== void 0) event.resolution = req.resolution;
5754
5915
  return event;