@shop-os/modelkit 0.1.5 → 0.1.6

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
@@ -68,6 +68,7 @@ __export(index_exports, {
68
68
  prodiaAdapter: () => prodiaAdapter,
69
69
  readErrorBody: () => readErrorBody,
70
70
  replicateAdapter: () => replicateAdapter,
71
+ resolveAudioOptions: () => resolveAudioOptions,
71
72
  resolveImageOptions: () => resolveImageOptions,
72
73
  resolveKeys: () => resolveKeys,
73
74
  resolveVideoOptions: () => resolveVideoOptions,
@@ -187,7 +188,11 @@ function geminiImage(id, label, aliases, sizes) {
187
188
  adapter: "google-image",
188
189
  providerModelId: id,
189
190
  lifecycle: "active",
190
- constraints: { aspectRatios: [...GEMINI_RATIOS], sizes, supports: ["safetySettings"] },
191
+ constraints: {
192
+ aspectRatios: [...GEMINI_RATIOS],
193
+ sizes,
194
+ supports: ["safetySettings", "temperature"]
195
+ },
191
196
  defaults: { size: "1K", aspectRatio: "1:1" },
192
197
  usage: { ...IMAGE_USAGE },
193
198
  pricingKind: "image_size"
@@ -326,8 +331,20 @@ var IMAGE_MODELS = [
326
331
  constraints: {
327
332
  // 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
328
333
  // omits the ratio instead. Advertise only sizes the adapter can send.
329
- aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
330
- sizes: ["1K", "2K"],
334
+ aspectRatios: [
335
+ "1:1",
336
+ "2:3",
337
+ "3:2",
338
+ "4:3",
339
+ "3:4",
340
+ "4:5",
341
+ "5:4",
342
+ "9:16",
343
+ "16:9",
344
+ "21:9",
345
+ "9:21"
346
+ ],
347
+ sizes: ["1K", "2K", "4K"],
331
348
  references: { images: 10 },
332
349
  supports: ["seed"]
333
350
  },
@@ -557,7 +574,7 @@ var OTHER_MODELS = [
557
574
  constraints: {
558
575
  references: { images: 1 },
559
576
  requires: ["references"],
560
- supports: ["scaleFactor", "outputFormat"]
577
+ supports: ["scaleFactor", "outputFormat", "upscale"]
561
578
  },
562
579
  defaults: { scaleFactor: 2, outputFormat: "png" },
563
580
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -804,7 +821,7 @@ var VIDEO_MODELS = [
804
821
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
805
822
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
806
823
  ratioIgnoredWith: ["firstFrame"],
807
- supports: ["generateAudio", "seed", "lastFrame"]
824
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
808
825
  },
809
826
  defaults: {
810
827
  durationSeconds: 5,
@@ -829,7 +846,7 @@ var VIDEO_MODELS = [
829
846
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
830
847
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
831
848
  ratioIgnoredWith: ["firstFrame"],
832
- supports: ["generateAudio", "seed", "lastFrame"]
849
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
833
850
  },
834
851
  defaults: {
835
852
  durationSeconds: 5,
@@ -855,7 +872,7 @@ var VIDEO_MODELS = [
855
872
  durations: { min: 4, max: 30 },
856
873
  references: { images: 30, videos: 10, audios: 10 },
857
874
  ratioIgnoredWith: ["firstFrame"],
858
- supports: ["generateAudio", "seed", "lastFrame"]
875
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
859
876
  },
860
877
  defaults: {
861
878
  durationSeconds: 5,
@@ -882,7 +899,8 @@ var VIDEO_MODELS = [
882
899
  references: { images: 7 },
883
900
  supports: []
884
901
  },
885
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
902
+ // No resolution default: xAI picks its own unless the caller asks.
903
+ defaults: { durationSeconds: 8, aspectRatio: "16:9" },
886
904
  usage: { unit: "reported_cost_usd", modality: "VIDEO" },
887
905
  pricingKind: "video_per_second"
888
906
  },
@@ -976,7 +994,7 @@ var VIDEO_MODELS = [
976
994
  aspectRatios: [...H3_RATIOS],
977
995
  resolutions: ["480p", "768p", "2k", "4k"],
978
996
  durations: { min: 5, max: 15 },
979
- supports: ["seed", "promptExpansion"]
997
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
980
998
  },
981
999
  defaults: {
982
1000
  durationSeconds: 5,
@@ -999,7 +1017,7 @@ var VIDEO_MODELS = [
999
1017
  aspectRatios: [...H3_RATIOS],
1000
1018
  resolutions: ["480p", "768p"],
1001
1019
  durations: { min: 5, max: 15 },
1002
- supports: ["seed", "promptExpansion"]
1020
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1003
1021
  },
1004
1022
  defaults: {
1005
1023
  durationSeconds: 5,
@@ -1023,7 +1041,7 @@ var VIDEO_MODELS = [
1023
1041
  resolutions: ["480p", "768p", "2k", "4k"],
1024
1042
  durations: { min: 5, max: 15 },
1025
1043
  references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1026
- supports: ["seed", "promptExpansion"]
1044
+ supports: ["seed", "promptExpansion", "safetyChecker"]
1027
1045
  },
1028
1046
  defaults: {
1029
1047
  durationSeconds: 5,
@@ -1047,7 +1065,7 @@ var VIDEO_MODELS = [
1047
1065
  resolutions: ["480p", "768p"],
1048
1066
  durations: { min: 5, max: 15 },
1049
1067
  references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1050
- supports: ["seed", "promptExpansion"]
1068
+ supports: ["seed", "promptExpansion", "safetyChecker"]
1051
1069
  },
1052
1070
  defaults: {
1053
1071
  durationSeconds: 5,
@@ -1175,19 +1193,22 @@ function resolveTier(field, code, requested, supported, order, model, onUnsuppor
1175
1193
  });
1176
1194
  return to;
1177
1195
  }
1178
- function resolveDuration(requested, durations, model, warnings) {
1196
+ function resolveDuration(requested, durations, model, onUnsupported, warnings) {
1179
1197
  if (requested === void 0 || !durations) return requested;
1180
- let to = requested;
1181
- if (Array.isArray(durations)) {
1182
- if (durations.includes(requested)) return requested;
1183
- to = durations.reduce(
1184
- (best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
1185
- durations[0] ?? requested
1186
- );
1187
- } else {
1188
- to = Math.min(Math.max(requested, durations.min), durations.max);
1189
- if (to === requested) return requested;
1198
+ const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
1199
+ if (inSet) return requested;
1200
+ if (onUnsupported === "error") {
1201
+ const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
1202
+ throw new ModelKitError({
1203
+ code: "unsupported_option",
1204
+ message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
1205
+ model: model.id
1206
+ });
1190
1207
  }
1208
+ const to = Array.isArray(durations) ? durations.reduce(
1209
+ (best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
1210
+ durations[0] ?? requested
1211
+ ) : Math.min(Math.max(requested, durations.min), durations.max);
1191
1212
  warnings.push({
1192
1213
  code: "duration_coerced",
1193
1214
  field: "durationSeconds",
@@ -1197,6 +1218,26 @@ function resolveDuration(requested, durations, model, warnings) {
1197
1218
  });
1198
1219
  return to;
1199
1220
  }
1221
+ function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
1222
+ if (requested === void 0 || requested === "adaptive" || !supported) return requested;
1223
+ if (supported.includes(requested)) return requested;
1224
+ if (onUnsupported === "error") {
1225
+ throw new ModelKitError({
1226
+ code: "unsupported_option",
1227
+ message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
1228
+ model: model.id
1229
+ });
1230
+ }
1231
+ const to = nearestAspectRatio(requested, supported);
1232
+ warnings.push({
1233
+ code: "ratio_coerced",
1234
+ field: "aspectRatio",
1235
+ from: requested,
1236
+ to,
1237
+ message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
1238
+ });
1239
+ return to;
1240
+ }
1200
1241
  function compact(refs) {
1201
1242
  return (refs ?? []).filter((r) => Boolean(r));
1202
1243
  }
@@ -1215,17 +1256,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1215
1256
  const warnings = [];
1216
1257
  const c = model.constraints;
1217
1258
  const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1218
- if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1219
- const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1220
- warnings.push({
1221
- code: "ratio_coerced",
1222
- field: "aspectRatio",
1223
- from: merged.aspectRatio,
1224
- to,
1225
- message: `aspect ratio ${merged.aspectRatio} coerced to ${to} for ${model.id}`
1226
- });
1227
- merged.aspectRatio = to;
1228
- }
1259
+ const aspectRatio = resolveAspectRatio(
1260
+ merged.aspectRatio,
1261
+ c.aspectRatios,
1262
+ model,
1263
+ onUnsupported,
1264
+ warnings
1265
+ );
1266
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
1229
1267
  const size = resolveTier(
1230
1268
  "size",
1231
1269
  "size_coerced",
@@ -1259,7 +1297,9 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1259
1297
  "count",
1260
1298
  "outputFormat",
1261
1299
  "scaleFactor",
1262
- "safetySettings"
1300
+ "safetySettings",
1301
+ "temperature",
1302
+ "upscale"
1263
1303
  ]);
1264
1304
  return { request: merged, warnings };
1265
1305
  }
@@ -1289,17 +1329,14 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1289
1329
  delete merged.aspectRatio;
1290
1330
  }
1291
1331
  }
1292
- if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1293
- const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1294
- warnings.push({
1295
- code: "ratio_coerced",
1296
- field: "aspectRatio",
1297
- from: merged.aspectRatio,
1298
- to,
1299
- message: `aspect ratio ${merged.aspectRatio} coerced to ${to} for ${model.id}`
1300
- });
1301
- merged.aspectRatio = to;
1302
- }
1332
+ const aspectRatio = resolveAspectRatio(
1333
+ merged.aspectRatio,
1334
+ c.aspectRatios,
1335
+ model,
1336
+ onUnsupported,
1337
+ warnings
1338
+ );
1339
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
1303
1340
  const resolution = resolveTier(
1304
1341
  "resolution",
1305
1342
  "resolution_coerced",
@@ -1311,7 +1348,13 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1311
1348
  warnings
1312
1349
  );
1313
1350
  if (resolution !== void 0) merged.resolution = resolution;
1314
- const duration = resolveDuration(merged.durationSeconds, c.durations, model, warnings);
1351
+ const duration = resolveDuration(
1352
+ merged.durationSeconds,
1353
+ c.durations,
1354
+ model,
1355
+ onUnsupported,
1356
+ warnings
1357
+ );
1315
1358
  if (duration !== void 0) merged.durationSeconds = duration;
1316
1359
  const limits = c.references ?? {};
1317
1360
  let images = trim(
@@ -1366,10 +1409,45 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1366
1409
  "cfgScale",
1367
1410
  "generateAudio",
1368
1411
  "promptExpansion",
1369
- "lastFrame"
1412
+ "lastFrame",
1413
+ "watermark",
1414
+ "safetyChecker"
1370
1415
  ]);
1371
1416
  return { request: merged, warnings };
1372
1417
  }
1418
+ function resolveAudioOptions(model, request, onUnsupported = "error") {
1419
+ const warnings = [];
1420
+ const c = model.constraints;
1421
+ const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1422
+ for (const input of c.requires ?? []) {
1423
+ const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
1424
+ if (!present)
1425
+ throw new ModelKitError({
1426
+ code: "missing_input",
1427
+ message: `${model.id} requires ${input}`,
1428
+ model: model.id
1429
+ });
1430
+ }
1431
+ const duration = resolveDuration(
1432
+ merged.durationSeconds,
1433
+ c.durations,
1434
+ model,
1435
+ onUnsupported,
1436
+ warnings
1437
+ );
1438
+ if (duration !== void 0) merged.durationSeconds = duration;
1439
+ const references = trim(
1440
+ "references",
1441
+ compact(merged.references),
1442
+ c.references?.images ?? c.references?.total,
1443
+ model,
1444
+ warnings
1445
+ );
1446
+ if (references.length > 0) merged.references = references;
1447
+ else delete merged.references;
1448
+ dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
1449
+ return { request: merged, warnings };
1450
+ }
1373
1451
  function dropUnsupported(req, model, warnings, fields) {
1374
1452
  const supports = model.constraints.supports ?? [];
1375
1453
  for (const field of fields) {
@@ -1411,6 +1489,9 @@ function hasAll(keys, names) {
1411
1489
  (n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
1412
1490
  );
1413
1491
  }
1492
+ function missingEnterpriseKeys(config, names) {
1493
+ return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
1494
+ }
1414
1495
  function resolveKeys(config, names, tier = "pro") {
1415
1496
  if (tier === "enterprise" && hasAll(config.keys.enterprise, names))
1416
1497
  return config.keys.enterprise;
@@ -1443,7 +1524,6 @@ function keysFromEnv(env, prefix = "") {
1443
1524
  set("prodia", pick("PRODIA_API_KEY", "PRODIA_TOKEN"));
1444
1525
  set("higgsfield", pick("HIGGSFIELD_API_KEY"));
1445
1526
  set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
1446
- set("openrouter", pick("OPENROUTER_API_KEY"));
1447
1527
  set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
1448
1528
  return keys;
1449
1529
  }
@@ -1491,7 +1571,9 @@ var textBody = import_zod2.z.string();
1491
1571
  function classifyHttpError(status, body, provider, model) {
1492
1572
  const asText = textBody.safeParse(body);
1493
1573
  const text2 = asText.success ? asText.data : JSON.stringify(body);
1494
- const blocked = /content_policy|safety|blockReason|PROHIBITED_CONTENT|moderation/i.test(text2);
1574
+ const blocked = /content_policy_violation|blockReason|PROHIBITED_CONTENT|moderation_blocked|safety(?![_A-Za-z])/i.test(
1575
+ text2
1576
+ );
1495
1577
  let code = "provider_rejected";
1496
1578
  if (blocked) code = "content_blocked";
1497
1579
  else if (status === 401 || status === 403) code = "auth";
@@ -1512,8 +1594,8 @@ function classifyHttpError(status, body, provider, model) {
1512
1594
  }
1513
1595
  function shouldRetry(err) {
1514
1596
  if (err instanceof ModelKitError) return err.retryable;
1515
- if (err.name === "AbortError" || /ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message))
1516
- return true;
1597
+ if (err.name === "AbortError") return false;
1598
+ if (/ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message)) return true;
1517
1599
  return false;
1518
1600
  }
1519
1601
  async function withRetry(fn, opts = {}) {
@@ -1698,6 +1780,12 @@ var import_zod4 = require("zod");
1698
1780
  function isUrlRef(ref) {
1699
1781
  return "url" in ref;
1700
1782
  }
1783
+ function abortedError() {
1784
+ return new ModelKitError({ code: "timeout", message: "aborted", retryable: false });
1785
+ }
1786
+ function throwIfAborted(signal) {
1787
+ if (signal?.aborted) throw abortedError();
1788
+ }
1701
1789
  function mediaRefToBase64(bytes) {
1702
1790
  let binary = "";
1703
1791
  const CHUNK = 32768;
@@ -1712,10 +1800,34 @@ function base64ToBytes(b64) {
1712
1800
  for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
1713
1801
  return out;
1714
1802
  }
1715
- async function mediaRefToBytes(ref, fetch) {
1803
+ function mediaRefToDataUrl(ref) {
1804
+ if (isUrlRef(ref)) return ref.url;
1805
+ return `data:${ref.mime};base64,${mediaRefToBase64(ref.bytes)}`;
1806
+ }
1807
+ var refToUrl = mediaRefToDataUrl;
1808
+ async function readBody(res) {
1809
+ const text2 = await res.text().catch(() => "");
1810
+ try {
1811
+ const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
1812
+ return decoded.success ? decoded.data : text2;
1813
+ } catch {
1814
+ return text2;
1815
+ }
1816
+ }
1817
+ async function mediaRefToBytes(ref, fetch, options = {}) {
1716
1818
  if (!isUrlRef(ref)) return { bytes: ref.bytes, mime: ref.mime };
1717
- const res = await fetch(ref.url);
1718
- if (!res.ok) throw new Error(`reference fetch failed (${res.status}): ${ref.url}`);
1819
+ const init = {};
1820
+ if (options.signal !== void 0) init.signal = options.signal;
1821
+ const res = await fetch(ref.url, init);
1822
+ if (!res.ok) {
1823
+ const text2 = await res.text().catch(() => "");
1824
+ throw classifyHttpError(
1825
+ res.status,
1826
+ text2,
1827
+ options.provider ?? "media-reference",
1828
+ options.model
1829
+ );
1830
+ }
1719
1831
  const mime = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() || "image/png";
1720
1832
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
1721
1833
  }
@@ -1773,16 +1885,6 @@ var GATEWAY_SLUGS = {
1773
1885
  perplexity: "perplexity-ai",
1774
1886
  deepseek: "deepseek"
1775
1887
  };
1776
- var OPENROUTER_VENDORS = {
1777
- openai: "openai",
1778
- anthropic: "anthropic",
1779
- google: "google",
1780
- xai: "x-ai",
1781
- perplexity: "perplexity",
1782
- deepseek: "deepseek",
1783
- moonshot: "moonshotai",
1784
- minimax: "minimax"
1785
- };
1786
1888
  function detectTextProvider(modelId) {
1787
1889
  const id = modelId.toLowerCase();
1788
1890
  if (id.startsWith("claude") || id.includes("anthropic.")) return "anthropic";
@@ -1799,14 +1901,17 @@ function detectTextProvider(modelId) {
1799
1901
  message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
1800
1902
  });
1801
1903
  }
1802
- function textKeyName(model, routing) {
1803
- if (routing.text === "openrouter") return "openrouter";
1904
+ function textKeyName(model, _routing) {
1804
1905
  return textProviderOf(model);
1805
1906
  }
1806
1907
  function textProviderOf(model) {
1807
1908
  const explicit = model.providerOptions?.["modelkit"]?.["provider"];
1808
1909
  return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
1809
1910
  }
1911
+ function textUsesCloudflareGateway(model, routing) {
1912
+ if (routing.text !== "cloudflare") return false;
1913
+ return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
1914
+ }
1810
1915
  function nativeClientFor(provider) {
1811
1916
  switch (provider) {
1812
1917
  case "openai":
@@ -1839,16 +1944,6 @@ function resolveTextRoute(ctx) {
1839
1944
  retryable: false
1840
1945
  });
1841
1946
  }
1842
- if (mode === "openrouter") {
1843
- const modelId = ctx.model.providerModelId.includes("/") ? ctx.model.providerModelId : `${OPENROUTER_VENDORS[provider]}/${ctx.model.providerModelId}`;
1844
- return {
1845
- provider,
1846
- client: "openai-compatible",
1847
- modelId,
1848
- keyName: "openrouter",
1849
- baseURL: "https://openrouter.ai/api/v1"
1850
- };
1851
- }
1852
1947
  const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
1853
1948
  const route2 = {
1854
1949
  provider,
@@ -1916,7 +2011,7 @@ var aiSdkTextAdapter = {
1916
2011
  case "openai-compatible":
1917
2012
  return (0, import_openai.createOpenAI)({
1918
2013
  ...settings,
1919
- name: route2.provider === "openai" ? "openai" : ctx.routing.text === "openrouter" ? "openrouter" : route2.provider
2014
+ name: route2.provider
1920
2015
  }).chat(route2.modelId);
1921
2016
  case "openai":
1922
2017
  return (0, import_openai.createOpenAI)(settings)(route2.modelId);
@@ -1929,8 +2024,9 @@ function requiredKeys(model, config) {
1929
2024
  if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
1930
2025
  return ["cloudflare"];
1931
2026
  if (model.adapter === "ai-sdk-text") {
1932
- const names = [textKeyName(model, config.routing ?? {})];
1933
- if (config.routing?.text === "cloudflare") names.push("cloudflare");
2027
+ const routing = config.routing ?? {};
2028
+ const names = [textKeyName(model, routing)];
2029
+ if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
1934
2030
  return names;
1935
2031
  }
1936
2032
  return ADAPTER_KEYS[model.adapter];
@@ -2004,6 +2100,11 @@ function pushIgnored(warnings, field, from, modelId) {
2004
2100
  message: `${modelId} provider instance does not support ${field}; ignored`
2005
2101
  });
2006
2102
  }
2103
+ function withoutModelkit(options) {
2104
+ if (!options) return {};
2105
+ const { modelkit: _modelkit, ...rest } = options;
2106
+ return rest;
2107
+ }
2007
2108
  function logCoercions(logger, modelId, warnings) {
2008
2109
  if (warnings.length === 0) return;
2009
2110
  logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
@@ -2020,7 +2121,16 @@ function createModelKit(config, adapters) {
2020
2121
  message: `No adapter registered for ${model.adapter}`,
2021
2122
  model: model.id
2022
2123
  });
2023
- const keys = resolveKeys(config, requiredKeys(model, config), call.tier);
2124
+ const names = requiredKeys(model, config);
2125
+ if (call.tier === "enterprise") {
2126
+ const missing = missingEnterpriseKeys(config, names);
2127
+ if (missing.length > 0)
2128
+ logger.warn(
2129
+ `[modelkit] enterprise keys incomplete for ${model.adapter}; using pro`,
2130
+ { missing }
2131
+ );
2132
+ }
2133
+ const keys = resolveKeys(config, names, call.tier);
2024
2134
  const ctx = {
2025
2135
  model,
2026
2136
  keys,
@@ -2341,8 +2451,15 @@ function createModelKit(config, adapters) {
2341
2451
  model: model.id
2342
2452
  });
2343
2453
  }
2344
- const warnings = [];
2345
- const { adapter, ctx } = context(model, call, warnings);
2454
+ const { abortSignal: _signal, ...request } = req;
2455
+ const { request: resolved, warnings } = resolveAudioOptions(
2456
+ model,
2457
+ request,
2458
+ call.onUnsupported ?? "error"
2459
+ );
2460
+ logCoercions(logger, model.id, warnings);
2461
+ const signal = combineSignals(req.abortSignal, call.signal);
2462
+ const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2346
2463
  if (!adapter.generateAudio) {
2347
2464
  throw new ModelKitError({
2348
2465
  code: "unsupported_option",
@@ -2350,11 +2467,7 @@ function createModelKit(config, adapters) {
2350
2467
  model: model.id
2351
2468
  });
2352
2469
  }
2353
- const result = await adapter.generateAudio(
2354
- { ...model.defaults, ...req, model: model.id },
2355
- ctx
2356
- );
2357
- logCoercions(logger, model.id, warnings);
2470
+ const result = await adapter.generateAudio(resolved, ctx);
2358
2471
  await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
2359
2472
  return result;
2360
2473
  },
@@ -2375,7 +2488,7 @@ function createModelKit(config, adapters) {
2375
2488
  });
2376
2489
  return {
2377
2490
  model,
2378
- providerOptions: entry.providerOptions ?? {},
2491
+ providerOptions: withoutModelkit(entry.providerOptions),
2379
2492
  catalog: entry
2380
2493
  };
2381
2494
  },
@@ -2411,7 +2524,9 @@ function createModelKit(config, adapters) {
2411
2524
  ...textAbortOptions(options.abortSignal, call.signal),
2412
2525
  model: target.languageModel,
2413
2526
  providerOptions: {},
2414
- prepareStep: steps.wrap(options.prepareStep),
2527
+ prepareStep: steps.wrap(
2528
+ options.prepareStep ?? options.experimental_prepareStep
2529
+ ),
2415
2530
  onFinish: async (event) => {
2416
2531
  for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
2417
2532
  await callerOnFinish?.(event);
@@ -2468,6 +2583,7 @@ var SEEDREAM_SIZES = {
2468
2583
  "3:2": "1248x832",
2469
2584
  "2:3": "832x1248",
2470
2585
  "21:9": "1568x672",
2586
+ "9:21": "672x1568",
2471
2587
  "4:5": "864x1080",
2472
2588
  "5:4": "1080x864"
2473
2589
  },
@@ -2480,16 +2596,34 @@ var SEEDREAM_SIZES = {
2480
2596
  "3:2": "2496x1664",
2481
2597
  "2:3": "1664x2496",
2482
2598
  "21:9": "3136x1344",
2599
+ "9:21": "1344x3136",
2483
2600
  "4:5": "1728x2160",
2484
2601
  "5:4": "2160x1728"
2602
+ },
2603
+ // 4K keeps the long edge at Ark's 4096 cap (a doubled 2K entry would exceed
2604
+ // it); sides are multiples of 16.
2605
+ "4K": {
2606
+ "1:1": "4096x4096",
2607
+ "4:3": "4096x3072",
2608
+ "3:4": "3072x4096",
2609
+ "16:9": "4096x2304",
2610
+ "9:16": "2304x4096",
2611
+ "3:2": "4096x2736",
2612
+ "2:3": "2736x4096",
2613
+ "21:9": "4096x1760",
2614
+ "9:21": "1760x4096",
2615
+ "4:5": "3280x4096",
2616
+ "5:4": "4096x3280"
2485
2617
  }
2486
2618
  };
2487
2619
  var arkAdapter = {
2488
2620
  id: "ark",
2489
2621
  async generateImage(req, ctx) {
2622
+ throwIfAborted(ctx.signal);
2490
2623
  return generateSeedreamImage(req, ctx);
2491
2624
  },
2492
2625
  async generateVideo(req, ctx) {
2626
+ throwIfAborted(ctx.signal);
2493
2627
  return generateSeedanceVideo(req, ctx);
2494
2628
  }
2495
2629
  };
@@ -2509,7 +2643,7 @@ function arkKey(ctx) {
2509
2643
  function throwArkError(status, body, model) {
2510
2644
  const parsed = import_zod5.z.string().safeParse(body);
2511
2645
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2512
- if (/sensitive.?content|inputimage|human.?face/i.test(text2)) {
2646
+ if (/sensitive.?content|human.?face/i.test(text2)) {
2513
2647
  const init = {
2514
2648
  code: "content_blocked",
2515
2649
  message: `ark rejected the request: ${text2.slice(0, 500)}`,
@@ -2534,7 +2668,7 @@ function throwArkError(status, body, model) {
2534
2668
  throw classifyHttpError(status, body, "ark", model);
2535
2669
  }
2536
2670
  function seedreamSize(aspect, size) {
2537
- const tier = size === "1K" ? "1K" : "2K";
2671
+ const tier = size === "4K" || size === "1K" ? size : "2K";
2538
2672
  const table = SEEDREAM_SIZES[tier];
2539
2673
  return table[aspect ?? ""] ?? table["1:1"] ?? "2048x2048";
2540
2674
  }
@@ -2545,10 +2679,6 @@ function sniffedImageMime(bytes) {
2545
2679
  return "image/webp";
2546
2680
  return "image/jpeg";
2547
2681
  }
2548
- function arkUrl(ref) {
2549
- if ("url" in ref) return ref.url;
2550
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2551
- }
2552
2682
  var SeedreamImageSchema = import_zod5.z.object({
2553
2683
  url: import_zod5.z.string().optional(),
2554
2684
  b64_json: import_zod5.z.string().optional()
@@ -2575,7 +2705,7 @@ async function generateSeedreamImage(req, ctx) {
2575
2705
  const key = arkKey(ctx);
2576
2706
  const modelId = ctx.model.id;
2577
2707
  const size = seedreamSize(req.aspectRatio, req.size);
2578
- const refs = (req.references ?? []).map(arkUrl);
2708
+ const refs = (req.references ?? []).map(refToUrl);
2579
2709
  const body = {
2580
2710
  model: ctx.model.providerModelId,
2581
2711
  prompt: req.prompt,
@@ -2627,10 +2757,18 @@ async function generateSeedreamImage(req, ctx) {
2627
2757
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
2628
2758
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
2629
2759
  }
2760
+ var SeedanceUsageSchema = import_zod5.z.object({
2761
+ total_tokens: import_zod5.z.number().optional(),
2762
+ completion_tokens: import_zod5.z.number().optional()
2763
+ });
2630
2764
  var SeedanceResponseSchema = import_zod5.z.object({
2631
2765
  id: import_zod5.z.string().optional(),
2632
2766
  status: import_zod5.z.string().optional(),
2633
2767
  content: import_zod5.z.object({ video_url: import_zod5.z.string().optional() }).optional(),
2768
+ usage: SeedanceUsageSchema.optional(),
2769
+ duration: import_zod5.z.number().optional(),
2770
+ framespersecond: import_zod5.z.number().optional(),
2771
+ resolution: import_zod5.z.string().optional(),
2634
2772
  error: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.object({ message: import_zod5.z.string().optional() })]).optional()
2635
2773
  });
2636
2774
  var SeedanceErrorMessageSchema = import_zod5.z.object({ message: import_zod5.z.string().optional() });
@@ -2662,42 +2800,42 @@ async function generateSeedanceVideo(req, ctx) {
2662
2800
  if (req.firstFrame) {
2663
2801
  content.push({
2664
2802
  type: "image_url",
2665
- image_url: { url: arkUrl(req.firstFrame) },
2803
+ image_url: { url: refToUrl(req.firstFrame) },
2666
2804
  role: "first_frame"
2667
2805
  });
2668
2806
  }
2669
2807
  if (req.lastFrame) {
2670
2808
  content.push({
2671
2809
  type: "image_url",
2672
- image_url: { url: arkUrl(req.lastFrame) },
2810
+ image_url: { url: refToUrl(req.lastFrame) },
2673
2811
  role: "last_frame"
2674
2812
  });
2675
2813
  }
2676
2814
  for (const ref of req.referenceImages ?? []) {
2677
2815
  content.push({
2678
2816
  type: "image_url",
2679
- image_url: { url: arkUrl(ref) },
2817
+ image_url: { url: refToUrl(ref) },
2680
2818
  role: "reference_image"
2681
2819
  });
2682
2820
  }
2683
2821
  if (req.sourceVideo) {
2684
2822
  content.push({
2685
2823
  type: "video_url",
2686
- video_url: { url: arkUrl(req.sourceVideo) },
2824
+ video_url: { url: refToUrl(req.sourceVideo) },
2687
2825
  role: "reference_video"
2688
2826
  });
2689
2827
  }
2690
2828
  for (const ref of req.referenceVideos ?? []) {
2691
2829
  content.push({
2692
2830
  type: "video_url",
2693
- video_url: { url: arkUrl(ref) },
2831
+ video_url: { url: refToUrl(ref) },
2694
2832
  role: "reference_video"
2695
2833
  });
2696
2834
  }
2697
2835
  for (const ref of req.referenceAudios ?? []) {
2698
2836
  content.push({
2699
2837
  type: "audio_url",
2700
- audio_url: { url: arkUrl(ref) },
2838
+ audio_url: { url: refToUrl(ref) },
2701
2839
  role: "reference_audio"
2702
2840
  });
2703
2841
  }
@@ -2711,6 +2849,7 @@ async function generateSeedanceVideo(req, ctx) {
2711
2849
  if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
2712
2850
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
2713
2851
  if (req.seed !== void 0) body.seed = req.seed;
2852
+ if (req.watermark !== void 0) body.watermark = req.watermark;
2714
2853
  const submit = await withRetry(async () => {
2715
2854
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
2716
2855
  method: "POST",
@@ -2774,6 +2913,11 @@ async function generateSeedanceVideo(req, ctx) {
2774
2913
  "Seedance task succeeded but returned no video_url",
2775
2914
  modelId
2776
2915
  );
2916
+ const tokens = polled.usage;
2917
+ if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
2918
+ usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
2919
+ usage2.outputTokens = tokens.completion_tokens;
2920
+ }
2777
2921
  return {
2778
2922
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
2779
2923
  usage: usage2,
@@ -2837,24 +2981,17 @@ var defaultDeps = { createFalClient: defaultCreateFalClient };
2837
2981
  function createFalAdapter(deps = defaultDeps) {
2838
2982
  return {
2839
2983
  id: "fal",
2840
- generateImage: (req, ctx) => generateMuseImage(req, ctx, deps),
2841
- generateVideo: (req, ctx) => generateFalVideo(req, ctx, deps)
2984
+ generateImage: (req, ctx) => {
2985
+ throwIfAborted(ctx.signal);
2986
+ return generateMuseImage(req, ctx, deps);
2987
+ },
2988
+ generateVideo: (req, ctx) => {
2989
+ throwIfAborted(ctx.signal);
2990
+ return generateFalVideo(req, ctx, deps);
2991
+ }
2842
2992
  };
2843
2993
  }
2844
2994
  var falAdapter = createFalAdapter();
2845
- function refToUrl(ref) {
2846
- if ("url" in ref) return ref.url;
2847
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2848
- }
2849
- async function readBody(res) {
2850
- const text2 = await res.text().catch(() => "");
2851
- try {
2852
- const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
2853
- return decoded.success ? decoded.data : text2;
2854
- } catch {
2855
- return text2;
2856
- }
2857
- }
2858
2995
  var falDetailSchema = import_zod6.z.object({ detail: JsonValueSchema });
2859
2996
  function liftDetail(body) {
2860
2997
  const parsed = falDetailSchema.safeParse(body);
@@ -3091,8 +3228,12 @@ async function generateMuseImage(req, ctx, deps) {
3091
3228
  raw: payload
3092
3229
  };
3093
3230
  }
3231
+ var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
3232
+ "minimax/h3-max",
3233
+ "minimax/h3-max/reference-to-video"
3234
+ ]);
3094
3235
  function minimaxFamily(providerModelId) {
3095
- return providerModelId.toLowerCase().includes("h3-max") ? "h3-max" : "h3";
3236
+ return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
3096
3237
  }
3097
3238
  function minimaxBase(req, family) {
3098
3239
  const resolution = (family === "h3-max" ? req.resolution ?? "768p" : req.resolution ?? "2k").toUpperCase();
@@ -3100,14 +3241,17 @@ function minimaxBase(req, family) {
3100
3241
  prompt: req.prompt.trim(),
3101
3242
  duration: req.durationSeconds ?? 5,
3102
3243
  resolution,
3103
- prompt_expansion_mode: req.promptExpansion ?? "balanced",
3104
- enable_safety_checker: true
3244
+ prompt_expansion_mode: req.promptExpansion ?? "balanced"
3105
3245
  };
3246
+ if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
3106
3247
  if (req.seed !== void 0) input.seed = req.seed;
3107
3248
  return input;
3108
3249
  }
3250
+ var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
3251
+ "fal-ai/kling-video/o1/video-to-video/reference"
3252
+ ]);
3109
3253
  function isKling(providerModelId) {
3110
- return providerModelId.toLowerCase().includes("kling");
3254
+ return KLING_MODEL_IDS.has(providerModelId.toLowerCase());
3111
3255
  }
3112
3256
  function klingO1Input(req) {
3113
3257
  const source = req.sourceVideo ? refToUrl(req.sourceVideo) : void 0;
@@ -3180,7 +3324,9 @@ async function generateFalVideo(req, ctx, deps) {
3180
3324
  if (lastFrame) base.end_image_url = lastFrame;
3181
3325
  } else {
3182
3326
  endpoint = `minimax/${family}/text-to-video`;
3183
- base.aspect_ratio = req.aspectRatio ?? "adaptive";
3327
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
3328
+ base.aspect_ratio = req.aspectRatio;
3329
+ }
3184
3330
  }
3185
3331
  if (ctx.routing.fal === "cloudflare-passthrough") {
3186
3332
  return await passthroughVideoJob(ctx, req, endpoint, base);
@@ -3666,6 +3812,14 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
3666
3812
  model: modelId
3667
3813
  });
3668
3814
  }
3815
+ if (req.lastFrame !== void 0 && req.firstFrame === void 0) {
3816
+ throw new ModelKitError({
3817
+ code: "missing_input",
3818
+ message: `${modelId} requires firstFrame when lastFrame is set`,
3819
+ provider: "google-genai",
3820
+ model: modelId
3821
+ });
3822
+ }
3669
3823
  const duration = req.durationSeconds ?? 8;
3670
3824
  const personGeneration = req.firstFrame ?? refs.length > 0 ? "allow_adult" : "allow_all";
3671
3825
  let image;
@@ -3732,7 +3886,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
3732
3886
  throwSdkError(cause, modelId);
3733
3887
  }
3734
3888
  };
3735
- const jobId = operation.name ?? "veo-operation";
3889
+ const jobId = operation.name ?? crypto.randomUUID();
3736
3890
  const usage2 = videoUsage2(ctx, req, duration);
3737
3891
  return {
3738
3892
  jobId,
@@ -3871,6 +4025,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3871
4025
  });
3872
4026
  }
3873
4027
  for (const ref of videos) {
4028
+ if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
3874
4029
  const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "video/mp4", modelId);
3875
4030
  parts.push({
3876
4031
  type: "video",
@@ -3879,6 +4034,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3879
4034
  });
3880
4035
  }
3881
4036
  if (req.firstFrame) {
4037
+ if (req.firstFrame.label !== void 0)
4038
+ parts.push({ type: "text", text: req.firstFrame.label });
3882
4039
  const media = await resolveMedia(
3883
4040
  req.firstFrame,
3884
4041
  ctx.fetch,
@@ -3897,6 +4054,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3897
4054
  }
3898
4055
  }
3899
4056
  for (const ref of images) {
4057
+ if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
3900
4058
  const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
3901
4059
  if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
3902
4060
  parts.push({
@@ -3940,7 +4098,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3940
4098
  } finally {
3941
4099
  await cleanupUploads();
3942
4100
  }
3943
- const jobId = interaction.id ?? "gemini-omni-interaction";
4101
+ const jobId = interaction.id ?? crypto.randomUUID();
3944
4102
  const usage2 = videoUsage2(ctx, req, duration);
3945
4103
  const getInteraction = async () => {
3946
4104
  try {
@@ -4166,11 +4324,11 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4166
4324
  const model = google(ctx.model.providerModelId);
4167
4325
  const content = [];
4168
4326
  for (const ref of req.references ?? []) {
4327
+ if (ref.label !== void 0) content.push({ type: "text", text: ref.label });
4169
4328
  if ("url" in ref) content.push({ type: "image", image: ref.url });
4170
4329
  else content.push({ type: "image", image: ref.bytes, mediaType: ref.mime });
4171
4330
  }
4172
4331
  content.push({ type: "text", text: req.prompt });
4173
- void ctx.call.postCropToAspect;
4174
4332
  const imageConfig = {};
4175
4333
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4176
4334
  imageConfig.aspectRatio = req.aspectRatio;
@@ -4186,7 +4344,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4186
4344
  const timeout = AbortSignal.timeout(GEMINI_IMAGE_TIMEOUT_MS);
4187
4345
  const signal = ctx.signal !== void 0 ? AbortSignal.any([ctx.signal, timeout]) : timeout;
4188
4346
  try {
4189
- return await deps.runTextGeneration({
4347
+ const genOptions = {
4190
4348
  model,
4191
4349
  messages: [{ role: "user", content }],
4192
4350
  maxRetries: 0,
@@ -4194,7 +4352,9 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4194
4352
  google: googleOptions
4195
4353
  },
4196
4354
  abortSignal: signal
4197
- });
4355
+ };
4356
+ if (req.temperature !== void 0) genOptions.temperature = req.temperature;
4357
+ return await deps.runTextGeneration(genOptions);
4198
4358
  } catch (cause) {
4199
4359
  throw toProviderError(cause, ctx);
4200
4360
  }
@@ -4398,26 +4558,14 @@ function headers(ctx) {
4398
4558
  const { key, secret } = credentials(ctx);
4399
4559
  return { "Content-Type": "application/json", "hf-api-key": key, "hf-secret": secret };
4400
4560
  }
4401
- function refToUrl2(ref) {
4402
- if ("url" in ref) return ref.url;
4403
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
4404
- }
4405
- async function readBody2(res) {
4406
- const text2 = await res.text().catch(() => "");
4407
- try {
4408
- const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
4409
- return decoded.success ? decoded.data : text2;
4410
- } catch {
4411
- return text2;
4412
- }
4413
- }
4414
4561
  function klingEndpoint(providerModelId) {
4415
4562
  if (providerModelId.startsWith("http")) return providerModelId;
4416
4563
  const path = providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId;
4417
4564
  return `${PLATFORM}/${path}`;
4418
4565
  }
4419
- function isDop(providerModelId) {
4420
- return providerModelId.toLowerCase().includes("dop");
4566
+ var DOP_MODEL_IDS = /* @__PURE__ */ new Set(["dop", "dop-preview"]);
4567
+ function higgsfieldVideoKind(providerModelId) {
4568
+ return DOP_MODEL_IDS.has(providerModelId.toLowerCase()) ? "dop" : "kling";
4421
4569
  }
4422
4570
  function videoUsage3(ctx, req, duration) {
4423
4571
  const event = {
@@ -4461,12 +4609,12 @@ async function createRequest(ctx, url, init) {
4461
4609
  throw classifyThrown("higgsfield", cause, ctx.model.id);
4462
4610
  }
4463
4611
  if (!res.ok) {
4464
- throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4612
+ throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
4465
4613
  }
4466
4614
  return res;
4467
4615
  }
4468
4616
  async function generateKlingVideo(req, ctx) {
4469
- const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4617
+ const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
4470
4618
  if (!firstFrame) {
4471
4619
  throw new ModelKitError({
4472
4620
  code: "missing_input",
@@ -4485,7 +4633,7 @@ async function generateKlingVideo(req, ctx) {
4485
4633
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
4486
4634
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4487
4635
  body.aspect_ratio = req.aspectRatio;
4488
- if (req.lastFrame) body.last_image_url = refToUrl2(req.lastFrame);
4636
+ if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
4489
4637
  const endpoint = klingEndpoint(ctx.model.providerModelId);
4490
4638
  const retryOptions = {};
4491
4639
  if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
@@ -4511,9 +4659,9 @@ async function generateKlingVideo(req, ctx) {
4511
4659
  } catch {
4512
4660
  return void 0;
4513
4661
  }
4514
- if (res.status >= 500) return void 0;
4662
+ if (res.status === 429 || res.status >= 500) return void 0;
4515
4663
  if (!res.ok) {
4516
- throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4664
+ throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
4517
4665
  }
4518
4666
  const payload = JsonValueSchema.parse(await res.json());
4519
4667
  const parsed = klingStatusSchema.safeParse(payload);
@@ -4620,7 +4768,7 @@ function dopUrl(body) {
4620
4768
  var dopCreateSchema = import_zod10.z.object({ id: import_zod10.z.string() });
4621
4769
  var dopStatusSchema = import_zod10.z.object({ status: import_zod10.z.string().optional() });
4622
4770
  async function generateDopVideo(req, ctx) {
4623
- const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4771
+ const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
4624
4772
  if (!firstFrame) {
4625
4773
  throw new ModelKitError({
4626
4774
  code: "missing_input",
@@ -4640,7 +4788,7 @@ async function generateDopVideo(req, ctx) {
4640
4788
  webhook: null
4641
4789
  };
4642
4790
  if (req.lastFrame) {
4643
- params.input_images_end = [{ type: "image_url", image_url: refToUrl2(req.lastFrame) }];
4791
+ params.input_images_end = [{ type: "image_url", image_url: refToUrl(req.lastFrame) }];
4644
4792
  }
4645
4793
  if (req.seed !== void 0) params.seed = req.seed;
4646
4794
  const retryOptions = {};
@@ -4730,7 +4878,10 @@ async function generateDopVideo(req, ctx) {
4730
4878
  }
4731
4879
  var higgsfieldAdapter = {
4732
4880
  id: "higgsfield",
4733
- generateVideo: (req, ctx) => isDop(ctx.model.providerModelId) ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx)
4881
+ generateVideo: (req, ctx) => {
4882
+ throwIfAborted(ctx.signal);
4883
+ return higgsfieldVideoKind(ctx.model.providerModelId) === "dop" ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx);
4884
+ }
4734
4885
  };
4735
4886
 
4736
4887
  // src/adapters/openai-image.ts
@@ -4825,6 +4976,7 @@ var openaiUsageSchema = import_zod11.z.object({
4825
4976
  var openaiImageAdapter = {
4826
4977
  id: "openai-image",
4827
4978
  async generateImage(req, ctx) {
4979
+ throwIfAborted(ctx.signal);
4828
4980
  const apiKey = ctx.keys.openai;
4829
4981
  if (!apiKey)
4830
4982
  throw new ModelKitError({
@@ -4834,6 +4986,13 @@ var openaiImageAdapter = {
4834
4986
  model: ctx.model.id,
4835
4987
  retryable: false
4836
4988
  });
4989
+ if ((req.references ?? []).some((ref) => ref.label !== void 0)) {
4990
+ ctx.warnings.push({
4991
+ code: "option_ignored",
4992
+ field: "references.label",
4993
+ message: "openai-image cannot express reference labels; ignoring them"
4994
+ });
4995
+ }
4837
4996
  const client2 = new import_openai2.default({ apiKey, fetch: ctx.fetch, maxRetries: 0 });
4838
4997
  const size = req.exactSize !== void 0 ? req.exactSize : req.aspectRatio === void 0 || req.aspectRatio === "adaptive" ? void 0 : aspectRatioToSize(req.aspectRatio, req.size ?? "1K");
4839
4998
  const refs = req.references ?? [];
@@ -4847,24 +5006,34 @@ var openaiImageAdapter = {
4847
5006
  try {
4848
5007
  if (!isEdit) {
4849
5008
  if (size !== void 0) {
4850
- return await client2.images.generate({
5009
+ return await client2.images.generate(
5010
+ {
5011
+ model: ctx.model.providerModelId,
5012
+ prompt: req.prompt,
5013
+ size,
5014
+ quality: sdkQuality,
5015
+ ...count
5016
+ },
5017
+ { signal: ctx.signal }
5018
+ );
5019
+ }
5020
+ return await client2.images.generate(
5021
+ {
4851
5022
  model: ctx.model.providerModelId,
4852
5023
  prompt: req.prompt,
4853
- size,
4854
5024
  quality: sdkQuality,
4855
5025
  ...count
4856
- });
4857
- }
4858
- return await client2.images.generate({
4859
- model: ctx.model.providerModelId,
4860
- prompt: req.prompt,
4861
- quality: sdkQuality,
4862
- ...count
4863
- });
5026
+ },
5027
+ { signal: ctx.signal }
5028
+ );
4864
5029
  }
4865
5030
  const files = await Promise.all(
4866
5031
  refs.slice(0, MAX_EDIT_REFERENCES).map(async (ref, i) => {
4867
- const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch);
5032
+ const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch, {
5033
+ signal: ctx.signal,
5034
+ provider: "openai-image",
5035
+ model: ctx.model.id
5036
+ });
4868
5037
  const ext = mime.includes("jpeg") ? "jpg" : mime.includes("webp") ? "webp" : "png";
4869
5038
  return new File([bytes], `ref-${i}.${ext}`, { type: mime });
4870
5039
  })
@@ -4872,22 +5041,28 @@ var openaiImageAdapter = {
4872
5041
  const single = files.length === 1 ? files[0] : void 0;
4873
5042
  const imageInput = single ?? files;
4874
5043
  if (size !== void 0) {
4875
- return await client2.images.edit({
5044
+ return await client2.images.edit(
5045
+ {
5046
+ model: ctx.model.providerModelId,
5047
+ image: imageInput,
5048
+ prompt: req.prompt,
5049
+ size,
5050
+ quality: sdkQuality,
5051
+ ...count
5052
+ },
5053
+ { signal: ctx.signal }
5054
+ );
5055
+ }
5056
+ return await client2.images.edit(
5057
+ {
4876
5058
  model: ctx.model.providerModelId,
4877
5059
  image: imageInput,
4878
5060
  prompt: req.prompt,
4879
- size,
4880
5061
  quality: sdkQuality,
4881
5062
  ...count
4882
- });
4883
- }
4884
- return await client2.images.edit({
4885
- model: ctx.model.providerModelId,
4886
- image: imageInput,
4887
- prompt: req.prompt,
4888
- quality: sdkQuality,
4889
- ...count
4890
- });
5063
+ },
5064
+ { signal: ctx.signal }
5065
+ );
4891
5066
  } catch (cause) {
4892
5067
  throw toProviderError2(cause, ctx);
4893
5068
  }
@@ -4969,7 +5144,7 @@ async function refToBytes(ctx, ref) {
4969
5144
  if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
4970
5145
  let res;
4971
5146
  try {
4972
- res = await ctx.fetch(ref.url);
5147
+ res = await ctx.fetch(ref.url, ctx.signal ? { signal: ctx.signal } : {});
4973
5148
  } catch (cause) {
4974
5149
  throw classifyThrown("prodia", cause, ctx.model.id);
4975
5150
  }
@@ -5015,6 +5190,12 @@ function emptyImage() {
5015
5190
  retryable: false
5016
5191
  });
5017
5192
  }
5193
+ function inputExtension(mime) {
5194
+ if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
5195
+ if (mime.includes("webp")) return "webp";
5196
+ if (mime.includes("gif")) return "gif";
5197
+ return "png";
5198
+ }
5018
5199
  function isBgRemove(providerModelId) {
5019
5200
  const id = providerModelId.toLowerCase();
5020
5201
  return id.includes("remove-background") || id.includes("bg-remove");
@@ -5023,6 +5204,7 @@ function isKlein(providerModelId) {
5023
5204
  return providerModelId.toLowerCase().includes("klein");
5024
5205
  }
5025
5206
  async function generateProdiaImage(req, ctx) {
5207
+ throwIfAborted(ctx.signal);
5026
5208
  const key = ctx.keys.prodia;
5027
5209
  if (!key) {
5028
5210
  throw new ModelKitError({
@@ -5121,7 +5303,9 @@ async function generateProdiaImage(req, ctx) {
5121
5303
  "input",
5122
5304
  // Uint8Array<ArrayBufferLike> is not a valid BlobPart under the
5123
5305
  // strict lib types; copy into a fresh ArrayBuffer-backed view.
5124
- new File([new Uint8Array(input.bytes)], `input-${i}.jpg`, { type: "image/jpeg" })
5306
+ new File([new Uint8Array(input.bytes)], `input-${i}.${inputExtension(input.mime)}`, {
5307
+ type: input.mime
5308
+ })
5125
5309
  );
5126
5310
  });
5127
5311
  const retryOpts = {
@@ -5136,11 +5320,13 @@ async function generateProdiaImage(req, ctx) {
5136
5320
  res = await withRetry(async () => {
5137
5321
  let attemptRes;
5138
5322
  try {
5139
- attemptRes = await ctx.fetch(PRODIA_JOB_URL, {
5323
+ const init = {
5140
5324
  method: "POST",
5141
5325
  headers: { Authorization: `Bearer ${key}`, Accept: accept },
5142
5326
  body: form
5143
- });
5327
+ };
5328
+ if (ctx.signal !== void 0) init.signal = ctx.signal;
5329
+ attemptRes = await ctx.fetch(PRODIA_JOB_URL, init);
5144
5330
  } catch (err) {
5145
5331
  throw classifyThrown("prodia", err, ctx.model.id);
5146
5332
  }
@@ -5201,11 +5387,7 @@ function client(ctx, deps) {
5201
5387
  retryable: false
5202
5388
  });
5203
5389
  }
5204
- return deps.createReplicateClient({ auth: token });
5205
- }
5206
- function refToUrl3(ref) {
5207
- if ("url" in ref) return ref.url;
5208
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
5390
+ return deps.createReplicateClient({ auth: token, fetch: ctx.fetch });
5209
5391
  }
5210
5392
  function route(providerModelId) {
5211
5393
  if (providerModelId.includes(":")) {
@@ -5225,8 +5407,9 @@ function replicateError(cause, ctx) {
5225
5407
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5226
5408
  return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
5227
5409
  }
5228
- function isLower(id) {
5229
- return id.toLowerCase();
5410
+ function baseModelId(providerModelId) {
5411
+ const colon = providerModelId.indexOf(":");
5412
+ return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
5230
5413
  }
5231
5414
  function predictionErrorBody(cause) {
5232
5415
  const parsed = JsonValueSchema.safeParse(cause);
@@ -5274,6 +5457,7 @@ function noOutput() {
5274
5457
  });
5275
5458
  }
5276
5459
  async function runPrediction(ctx, input, deps) {
5460
+ throwIfAborted(ctx.signal);
5277
5461
  const api = client(ctx, deps);
5278
5462
  const createOptions = { ...route(ctx.model.providerModelId), input };
5279
5463
  let prediction;
@@ -5281,12 +5465,14 @@ async function runPrediction(ctx, input, deps) {
5281
5465
  prediction = await withRetry(
5282
5466
  async () => {
5283
5467
  try {
5284
- return await api.predictions.create(createOptions);
5468
+ return await api.predictions.create(
5469
+ ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
5470
+ );
5285
5471
  } catch (cause) {
5286
5472
  throw replicateError(cause, ctx);
5287
5473
  }
5288
5474
  },
5289
- ctx.signal ? { signal: ctx.signal } : {}
5475
+ { attempts: 1 }
5290
5476
  );
5291
5477
  } catch (cause) {
5292
5478
  throw replicateError(cause, ctx);
@@ -5299,7 +5485,10 @@ async function runPrediction(ctx, input, deps) {
5299
5485
  const done = await pollUntil(async () => {
5300
5486
  let current;
5301
5487
  try {
5302
- current = await api.predictions.get(prediction.id);
5488
+ current = await api.predictions.get(
5489
+ prediction.id,
5490
+ ctx.signal ? { signal: ctx.signal } : void 0
5491
+ );
5303
5492
  } catch (cause) {
5304
5493
  throw replicateError(cause, ctx);
5305
5494
  }
@@ -5366,21 +5555,32 @@ async function download(ctx, url) {
5366
5555
  const mime = res.headers.get("content-type") ?? "image/png";
5367
5556
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
5368
5557
  }
5369
- function isUpscaler(providerModelId) {
5370
- const id = isLower(providerModelId);
5371
- return id.includes("upscal") || id.includes("crystal") || id.includes("topaz");
5372
- }
5373
- function isTopazUpscaler(providerModelId) {
5374
- return isLower(providerModelId).includes("topazlabs/image-upscale");
5375
- }
5376
- function isQwen(providerModelId) {
5377
- return isLower(providerModelId).includes("qwen");
5378
- }
5379
- function isWanImage(providerModelId) {
5380
- return isLower(providerModelId).includes("wan-2.7");
5558
+ var REPLICATE_IMAGE_KINDS = {
5559
+ "topazlabs/image-upscale": "topaz",
5560
+ "philz1337x/crystal-upscaler": "upscaler",
5561
+ "wan-video/wan-2.7-image-pro": "wan",
5562
+ "qwen/qwen-image-2-pro": "qwen-image",
5563
+ "qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
5564
+ };
5565
+ function imageKind(providerModelId) {
5566
+ return REPLICATE_IMAGE_KINDS[baseModelId(providerModelId)] ?? "generic";
5567
+ }
5568
+ var REPLICATE_VIDEO_KINDS = {
5569
+ "kling-video/v2.5-turbo/pro/image-to-video": "kling",
5570
+ "kling-video/v3.0/pro/image-to-video": "kling",
5571
+ "kwaivgi/kling-v3-video": "kling",
5572
+ "kwaivgi/kling-v3-omni-video": "kling-omni",
5573
+ "minimax/hailuo-02": "hailuo"
5574
+ };
5575
+ function videoKind(providerModelId) {
5576
+ return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)] ?? "wan";
5381
5577
  }
5382
- function isQwenEditPlus(providerModelId) {
5383
- return isLower(providerModelId).includes("edit");
5578
+ var REPLICATE_AUDIO_KINDS = {
5579
+ "zsxkib/mmaudio": "mmaudio",
5580
+ "elevenlabs/music": "elevenlabs"
5581
+ };
5582
+ function audioKind(providerModelId) {
5583
+ return REPLICATE_AUDIO_KINDS[baseModelId(providerModelId)] ?? "lyria";
5384
5584
  }
5385
5585
  var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
5386
5586
  "1:1",
@@ -5423,87 +5623,113 @@ function wanImageSize(aspectRatio, size) {
5423
5623
  async function generateReplicateImage(req, ctx, deps) {
5424
5624
  const id = ctx.model.providerModelId;
5425
5625
  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
- });
5626
+ switch (imageKind(id)) {
5627
+ case "topaz": {
5628
+ const first = (req.references ?? [])[0];
5629
+ if (!first) {
5630
+ throw new ModelKitError({
5631
+ code: "missing_input",
5632
+ message: `${ctx.model.id} requires a reference image to upscale`,
5633
+ provider: "replicate",
5634
+ model: ctx.model.id,
5635
+ retryable: false
5636
+ });
5637
+ }
5638
+ let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
5639
+ if (format !== "png" && format !== "jpg") {
5640
+ ctx.warnings.push({
5641
+ code: "option_ignored",
5642
+ field: "outputFormat",
5643
+ from: format,
5644
+ message: "topazlabs/image-upscale supports only png and jpg; using png"
5645
+ });
5646
+ format = "png";
5647
+ }
5648
+ const upscale = req.upscale;
5649
+ const topaz = {
5650
+ image: refToUrl(first),
5651
+ enhance_model: upscale?.enhanceModel ?? "Standard V2",
5652
+ output_format: format,
5653
+ upscale_factor: `${req.scaleFactor ?? 2}x`,
5654
+ face_enhancement: upscale?.faceEnhancement ?? false
5655
+ };
5656
+ if (upscale?.subjectDetection !== void 0)
5657
+ topaz.subject_detection = upscale.subjectDetection;
5658
+ if (upscale?.faceEnhancementCreativity !== void 0)
5659
+ topaz.face_enhancement_creativity = upscale.faceEnhancementCreativity;
5660
+ if (upscale?.faceEnhancementStrength !== void 0)
5661
+ topaz.face_enhancement_strength = upscale.faceEnhancementStrength;
5662
+ input = topaz;
5663
+ break;
5436
5664
  }
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";
5665
+ case "upscaler": {
5666
+ const first = (req.references ?? [])[0];
5667
+ if (!first) {
5668
+ throw new ModelKitError({
5669
+ code: "missing_input",
5670
+ message: `${ctx.model.id} requires a reference image to upscale`,
5671
+ provider: "replicate",
5672
+ model: ctx.model.id,
5673
+ retryable: false
5674
+ });
5675
+ }
5676
+ const imageInput = { prompt: req.prompt };
5677
+ imageInput.image = refToUrl(first);
5678
+ imageInput.creativity = 0;
5679
+ imageInput.scale_factor = 2;
5680
+ imageInput.output_format = "png";
5681
+ input = imageInput;
5682
+ break;
5446
5683
  }
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)) {
5455
- const refs = req.references ?? [];
5456
- const first = refs[0];
5457
- if (!first) {
5458
- throw new ModelKitError({
5459
- code: "missing_input",
5460
- message: `${ctx.model.id} requires a reference image to upscale`,
5461
- provider: "replicate",
5462
- model: ctx.model.id,
5463
- retryable: false
5464
- });
5684
+ case "wan": {
5685
+ const refs = (req.references ?? []).map(refToUrl);
5686
+ const imageInput = { prompt: req.prompt };
5687
+ if (refs.length > 0) imageInput.images = refs;
5688
+ imageInput.size = wanImageSize(req.aspectRatio, req.size);
5689
+ input = imageInput;
5690
+ break;
5465
5691
  }
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;
5472
- } else if (isWanImage(id)) {
5473
- const refs = (req.references ?? []).map(refToUrl3);
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;
5478
- } else if (isQwen(id)) {
5479
- const refs = (req.references ?? []).map(refToUrl3);
5480
- const firstUrl = refs[0];
5481
- const imageInput = { prompt: req.prompt };
5482
- if (firstUrl !== void 0) {
5483
- imageInput.image = firstUrl;
5484
- if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
5692
+ case "qwen-image": {
5693
+ const refs = (req.references ?? []).map(refToUrl);
5694
+ const firstUrl = refs[0];
5695
+ const imageInput = { prompt: req.prompt };
5696
+ if (firstUrl !== void 0) {
5697
+ imageInput.image = firstUrl;
5698
+ imageInput.match_input_image = true;
5699
+ } else if (req.aspectRatio !== void 0 && QWEN_IMAGE_RATIOS.has(req.aspectRatio)) {
5700
+ imageInput.aspect_ratio = req.aspectRatio;
5701
+ }
5702
+ input = imageInput;
5703
+ break;
5485
5704
  }
5486
- const ratios = isQwenEditPlus(id) ? QWEN_EDIT_RATIOS : QWEN_IMAGE_RATIOS;
5487
- if (req.aspectRatio !== void 0) {
5488
- if (ratios.has(req.aspectRatio)) imageInput.aspect_ratio = req.aspectRatio;
5489
- else
5490
- ctx.warnings.push({
5491
- code: "option_ignored",
5492
- field: "aspectRatio",
5493
- from: req.aspectRatio,
5494
- message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
5495
- });
5705
+ case "qwen-edit": {
5706
+ const refs = (req.references ?? []).map(refToUrl);
5707
+ const firstUrl = refs[0];
5708
+ const imageInput = { prompt: req.prompt };
5709
+ if (firstUrl !== void 0) imageInput.image = firstUrl;
5710
+ if (req.aspectRatio !== void 0) {
5711
+ if (QWEN_EDIT_RATIOS.has(req.aspectRatio))
5712
+ imageInput.aspect_ratio = req.aspectRatio;
5713
+ else
5714
+ ctx.warnings.push({
5715
+ code: "option_ignored",
5716
+ field: "aspectRatio",
5717
+ from: req.aspectRatio,
5718
+ message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
5719
+ });
5720
+ }
5721
+ if (req.outputFormat !== void 0) {
5722
+ imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5723
+ }
5724
+ input = imageInput;
5725
+ break;
5496
5726
  }
5497
- if (isQwenEditPlus(id) && req.outputFormat !== void 0) {
5498
- imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5727
+ default: {
5728
+ const first = (req.references ?? [])[0];
5729
+ const imageInput = { prompt: req.prompt };
5730
+ if (first) imageInput.image = refToUrl(first);
5731
+ input = imageInput;
5499
5732
  }
5500
- input = imageInput;
5501
- } else {
5502
- const refs = req.references ?? [];
5503
- const first = refs[0];
5504
- const imageInput = { prompt: req.prompt };
5505
- if (first) imageInput.image = refToUrl3(first);
5506
- input = imageInput;
5507
5733
  }
5508
5734
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
5509
5735
  const file = await download(ctx, url);
@@ -5520,8 +5746,8 @@ function wanSize(aspectRatio) {
5520
5746
  return w > h ? "2048*1152" : "1536*2048";
5521
5747
  }
5522
5748
  function klingInput(req) {
5523
- const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl3);
5524
- if (req.lastFrame) images.push(refToUrl3(req.lastFrame));
5749
+ const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
5750
+ if (req.lastFrame) images.push(refToUrl(req.lastFrame));
5525
5751
  const input = {
5526
5752
  prompt: req.prompt,
5527
5753
  duration: req.durationSeconds ?? 10,
@@ -5539,13 +5765,18 @@ function klingInput(req) {
5539
5765
  if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
5540
5766
  return input;
5541
5767
  }
5768
+ function klingOmniMode(req) {
5769
+ if (req.resolution === "1080p") return "pro";
5770
+ if (req.resolution === "720p") return "standard";
5771
+ return req.mode ?? "standard";
5772
+ }
5542
5773
  function klingOmniInput(req) {
5543
- const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl3);
5544
- if (req.lastFrame) images.push(refToUrl3(req.lastFrame));
5774
+ const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
5775
+ if (req.lastFrame) images.push(refToUrl(req.lastFrame));
5545
5776
  const input = {
5546
5777
  prompt: req.prompt,
5547
5778
  duration: req.durationSeconds ?? 10,
5548
- mode: req.mode ?? "standard",
5779
+ mode: klingOmniMode(req),
5549
5780
  generate_audio: req.generateAudio ?? false
5550
5781
  };
5551
5782
  const startImage = images[0];
@@ -5556,7 +5787,7 @@ function klingOmniInput(req) {
5556
5787
  } else if (req.aspectRatio !== "adaptive") {
5557
5788
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5558
5789
  }
5559
- const refs = (req.referenceImages ?? []).map(refToUrl3);
5790
+ const refs = (req.referenceImages ?? []).map(refToUrl);
5560
5791
  if (refs.length > 0) input.reference_images = refs;
5561
5792
  return input;
5562
5793
  }
@@ -5567,8 +5798,8 @@ function hailuoInput(req) {
5567
5798
  resolution: req.resolution ?? "768p",
5568
5799
  prompt_optimizer: true
5569
5800
  };
5570
- if (req.firstFrame) input.first_frame_image = refToUrl3(req.firstFrame);
5571
- if (req.lastFrame) input.last_frame_image = refToUrl3(req.lastFrame);
5801
+ if (req.firstFrame) input.first_frame_image = refToUrl(req.firstFrame);
5802
+ if (req.lastFrame) input.last_frame_image = refToUrl(req.lastFrame);
5572
5803
  return input;
5573
5804
  }
5574
5805
  function wanInput(req) {
@@ -5577,12 +5808,13 @@ function wanInput(req) {
5577
5808
  duration: req.durationSeconds ?? 5,
5578
5809
  size: wanSize(req.aspectRatio)
5579
5810
  };
5580
- if (req.firstFrame) input.image = refToUrl3(req.firstFrame);
5811
+ if (req.firstFrame) input.image = refToUrl(req.firstFrame);
5581
5812
  return input;
5582
5813
  }
5583
5814
  async function generateReplicateVideo(req, ctx, deps) {
5584
- const id = isLower(ctx.model.providerModelId);
5585
- const input = id.includes("kling") ? id.includes("omni") ? klingOmniInput(req) : klingInput(req) : id.includes("hailuo") ? hailuoInput(req) : wanInput(req);
5815
+ throwIfAborted(ctx.signal);
5816
+ const kind = videoKind(ctx.model.providerModelId);
5817
+ const input = kind === "kling" ? klingInput(req) : kind === "kling-omni" ? klingOmniInput(req) : kind === "hailuo" ? hailuoInput(req) : wanInput(req);
5586
5818
  const api = client(ctx, deps);
5587
5819
  const createOptions = { ...route(ctx.model.providerModelId), input };
5588
5820
  let prediction;
@@ -5590,12 +5822,14 @@ async function generateReplicateVideo(req, ctx, deps) {
5590
5822
  prediction = await withRetry(
5591
5823
  async () => {
5592
5824
  try {
5593
- return await api.predictions.create(createOptions);
5825
+ return await api.predictions.create(
5826
+ ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
5827
+ );
5594
5828
  } catch (cause) {
5595
5829
  throw replicateError(cause, ctx);
5596
5830
  }
5597
5831
  },
5598
- ctx.signal ? { signal: ctx.signal } : {}
5832
+ { attempts: 1 }
5599
5833
  );
5600
5834
  } catch (cause) {
5601
5835
  throw replicateError(cause, ctx);
@@ -5604,7 +5838,10 @@ async function generateReplicateVideo(req, ctx, deps) {
5604
5838
  const check = async () => {
5605
5839
  let current;
5606
5840
  try {
5607
- current = await api.predictions.get(jobId);
5841
+ current = await api.predictions.get(
5842
+ jobId,
5843
+ ctx.signal ? { signal: ctx.signal } : void 0
5844
+ );
5608
5845
  } catch (cause) {
5609
5846
  throw replicateError(cause, ctx);
5610
5847
  }
@@ -5705,7 +5942,7 @@ function mmaudioInput(req, ctx) {
5705
5942
  });
5706
5943
  }
5707
5944
  const input = {
5708
- video: refToUrl3(video),
5945
+ video: refToUrl(video),
5709
5946
  duration: req.durationSeconds ?? 8,
5710
5947
  seed: req.seed ?? -1
5711
5948
  };
@@ -5724,8 +5961,8 @@ function predictionRaw(prediction) {
5724
5961
  return raw;
5725
5962
  }
5726
5963
  async function generateReplicateAudio(req, ctx, deps) {
5727
- const id = isLower(ctx.model.providerModelId);
5728
- const input = id.includes("mmaudio") ? mmaudioInput(req, ctx) : id.includes("elevenlabs") ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
5964
+ const kind = audioKind(ctx.model.providerModelId);
5965
+ const input = kind === "mmaudio" ? mmaudioInput(req, ctx) : kind === "elevenlabs" ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
5729
5966
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
5730
5967
  const usage2 = audioUsage(ctx, req);
5731
5968
  if (ctx.model.usage.unit === "seconds") {
@@ -5754,10 +5991,6 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
5754
5991
  };
5755
5992
  }
5756
5993
  var xaiVideoAdapter = createXaiVideoAdapter();
5757
- function refToUrl4(ref) {
5758
- if ("url" in ref) return ref.url;
5759
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
5760
- }
5761
5994
  var xaiResponseStatusSchema = import_zod13.z.object({
5762
5995
  response: import_zod13.z.object({ status: import_zod13.z.number() }).partial()
5763
5996
  });
@@ -5789,13 +6022,14 @@ async function generateXaiVideo(req, ctx, deps) {
5789
6022
  retryable: false
5790
6023
  });
5791
6024
  }
5792
- const refUrls = (req.referenceImages ?? []).map(refToUrl4).slice(0, 7);
5793
- const resolution = req.resolution === "480p" ? "480p" : "720p";
6025
+ const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
5794
6026
  const xaiOptions = {
5795
- resolution,
5796
6027
  pollIntervalMs: POLL_INTERVAL_MS2,
5797
6028
  pollTimeoutMs: POLL_TIMEOUT_MS2
5798
6029
  };
6030
+ if (req.resolution === "480p" || req.resolution === "720p" || req.resolution === "1080p") {
6031
+ xaiOptions.resolution = req.resolution;
6032
+ }
5799
6033
  if (refUrls.length > 0) {
5800
6034
  xaiOptions.mode = "reference-to-video";
5801
6035
  xaiOptions.referenceImageUrls = refUrls;
@@ -5815,7 +6049,7 @@ async function generateXaiVideo(req, ctx, deps) {
5815
6049
  providerOptions: { xai: xaiOptions }
5816
6050
  };
5817
6051
  if (req.firstFrame) {
5818
- callBody.frameImages = [{ image: refToUrl4(req.firstFrame), frameType: "first_frame" }];
6052
+ callBody.frameImages = [{ image: refToUrl(req.firstFrame), frameType: "first_frame" }];
5819
6053
  }
5820
6054
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5821
6055
  callBody.aspectRatio = req.aspectRatio;
@@ -5851,7 +6085,8 @@ async function generateXaiVideo(req, ctx, deps) {
5851
6085
  return settled;
5852
6086
  };
5853
6087
  return {
5854
- jobId: `${ctx.model.id}-grok`,
6088
+ // xAI exposes no request id on the synchronous handle, so each job gets a fresh one.
6089
+ jobId: crypto.randomUUID(),
5855
6090
  async poll() {
5856
6091
  if (failed !== void 0) return { status: "failed" };
5857
6092
  return settled ? { status: "succeeded" } : { status: "pending" };
@@ -5986,6 +6221,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
5986
6221
  prodiaAdapter,
5987
6222
  readErrorBody,
5988
6223
  replicateAdapter,
6224
+ resolveAudioOptions,
5989
6225
  resolveImageOptions,
5990
6226
  resolveKeys,
5991
6227
  resolveVideoOptions,