@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.js CHANGED
@@ -105,7 +105,11 @@ function geminiImage(id, label, aliases, sizes) {
105
105
  adapter: "google-image",
106
106
  providerModelId: id,
107
107
  lifecycle: "active",
108
- constraints: { aspectRatios: [...GEMINI_RATIOS], sizes, supports: ["safetySettings"] },
108
+ constraints: {
109
+ aspectRatios: [...GEMINI_RATIOS],
110
+ sizes,
111
+ supports: ["safetySettings", "temperature"]
112
+ },
109
113
  defaults: { size: "1K", aspectRatio: "1:1" },
110
114
  usage: { ...IMAGE_USAGE },
111
115
  pricingKind: "image_size"
@@ -244,8 +248,20 @@ var IMAGE_MODELS = [
244
248
  constraints: {
245
249
  // 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
246
250
  // omits the ratio instead. Advertise only sizes the adapter can send.
247
- aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
248
- sizes: ["1K", "2K"],
251
+ aspectRatios: [
252
+ "1:1",
253
+ "2:3",
254
+ "3:2",
255
+ "4:3",
256
+ "3:4",
257
+ "4:5",
258
+ "5:4",
259
+ "9:16",
260
+ "16:9",
261
+ "21:9",
262
+ "9:21"
263
+ ],
264
+ sizes: ["1K", "2K", "4K"],
249
265
  references: { images: 10 },
250
266
  supports: ["seed"]
251
267
  },
@@ -475,7 +491,7 @@ var OTHER_MODELS = [
475
491
  constraints: {
476
492
  references: { images: 1 },
477
493
  requires: ["references"],
478
- supports: ["scaleFactor", "outputFormat"]
494
+ supports: ["scaleFactor", "outputFormat", "upscale"]
479
495
  },
480
496
  defaults: { scaleFactor: 2, outputFormat: "png" },
481
497
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -722,7 +738,7 @@ var VIDEO_MODELS = [
722
738
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
723
739
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
724
740
  ratioIgnoredWith: ["firstFrame"],
725
- supports: ["generateAudio", "seed", "lastFrame"]
741
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
726
742
  },
727
743
  defaults: {
728
744
  durationSeconds: 5,
@@ -747,7 +763,7 @@ var VIDEO_MODELS = [
747
763
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
748
764
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
749
765
  ratioIgnoredWith: ["firstFrame"],
750
- supports: ["generateAudio", "seed", "lastFrame"]
766
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
751
767
  },
752
768
  defaults: {
753
769
  durationSeconds: 5,
@@ -773,7 +789,7 @@ var VIDEO_MODELS = [
773
789
  durations: { min: 4, max: 30 },
774
790
  references: { images: 30, videos: 10, audios: 10 },
775
791
  ratioIgnoredWith: ["firstFrame"],
776
- supports: ["generateAudio", "seed", "lastFrame"]
792
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
777
793
  },
778
794
  defaults: {
779
795
  durationSeconds: 5,
@@ -800,7 +816,8 @@ var VIDEO_MODELS = [
800
816
  references: { images: 7 },
801
817
  supports: []
802
818
  },
803
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
819
+ // No resolution default: xAI picks its own unless the caller asks.
820
+ defaults: { durationSeconds: 8, aspectRatio: "16:9" },
804
821
  usage: { unit: "reported_cost_usd", modality: "VIDEO" },
805
822
  pricingKind: "video_per_second"
806
823
  },
@@ -894,7 +911,7 @@ var VIDEO_MODELS = [
894
911
  aspectRatios: [...H3_RATIOS],
895
912
  resolutions: ["480p", "768p", "2k", "4k"],
896
913
  durations: { min: 5, max: 15 },
897
- supports: ["seed", "promptExpansion"]
914
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
898
915
  },
899
916
  defaults: {
900
917
  durationSeconds: 5,
@@ -917,7 +934,7 @@ var VIDEO_MODELS = [
917
934
  aspectRatios: [...H3_RATIOS],
918
935
  resolutions: ["480p", "768p"],
919
936
  durations: { min: 5, max: 15 },
920
- supports: ["seed", "promptExpansion"]
937
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
921
938
  },
922
939
  defaults: {
923
940
  durationSeconds: 5,
@@ -941,7 +958,7 @@ var VIDEO_MODELS = [
941
958
  resolutions: ["480p", "768p", "2k", "4k"],
942
959
  durations: { min: 5, max: 15 },
943
960
  references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
944
- supports: ["seed", "promptExpansion"]
961
+ supports: ["seed", "promptExpansion", "safetyChecker"]
945
962
  },
946
963
  defaults: {
947
964
  durationSeconds: 5,
@@ -965,7 +982,7 @@ var VIDEO_MODELS = [
965
982
  resolutions: ["480p", "768p"],
966
983
  durations: { min: 5, max: 15 },
967
984
  references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
968
- supports: ["seed", "promptExpansion"]
985
+ supports: ["seed", "promptExpansion", "safetyChecker"]
969
986
  },
970
987
  defaults: {
971
988
  durationSeconds: 5,
@@ -1093,19 +1110,22 @@ function resolveTier(field, code, requested, supported, order, model, onUnsuppor
1093
1110
  });
1094
1111
  return to;
1095
1112
  }
1096
- function resolveDuration(requested, durations, model, warnings) {
1113
+ function resolveDuration(requested, durations, model, onUnsupported, warnings) {
1097
1114
  if (requested === void 0 || !durations) return requested;
1098
- let to = requested;
1099
- if (Array.isArray(durations)) {
1100
- if (durations.includes(requested)) return requested;
1101
- to = durations.reduce(
1102
- (best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
1103
- durations[0] ?? requested
1104
- );
1105
- } else {
1106
- to = Math.min(Math.max(requested, durations.min), durations.max);
1107
- if (to === requested) return requested;
1115
+ const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
1116
+ if (inSet) return requested;
1117
+ if (onUnsupported === "error") {
1118
+ const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
1119
+ throw new ModelKitError({
1120
+ code: "unsupported_option",
1121
+ message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
1122
+ model: model.id
1123
+ });
1108
1124
  }
1125
+ const to = Array.isArray(durations) ? durations.reduce(
1126
+ (best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
1127
+ durations[0] ?? requested
1128
+ ) : Math.min(Math.max(requested, durations.min), durations.max);
1109
1129
  warnings.push({
1110
1130
  code: "duration_coerced",
1111
1131
  field: "durationSeconds",
@@ -1115,6 +1135,26 @@ function resolveDuration(requested, durations, model, warnings) {
1115
1135
  });
1116
1136
  return to;
1117
1137
  }
1138
+ function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
1139
+ if (requested === void 0 || requested === "adaptive" || !supported) return requested;
1140
+ if (supported.includes(requested)) return requested;
1141
+ if (onUnsupported === "error") {
1142
+ throw new ModelKitError({
1143
+ code: "unsupported_option",
1144
+ message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
1145
+ model: model.id
1146
+ });
1147
+ }
1148
+ const to = nearestAspectRatio(requested, supported);
1149
+ warnings.push({
1150
+ code: "ratio_coerced",
1151
+ field: "aspectRatio",
1152
+ from: requested,
1153
+ to,
1154
+ message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
1155
+ });
1156
+ return to;
1157
+ }
1118
1158
  function compact(refs) {
1119
1159
  return (refs ?? []).filter((r) => Boolean(r));
1120
1160
  }
@@ -1133,17 +1173,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1133
1173
  const warnings = [];
1134
1174
  const c = model.constraints;
1135
1175
  const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1136
- if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1137
- const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1138
- warnings.push({
1139
- code: "ratio_coerced",
1140
- field: "aspectRatio",
1141
- from: merged.aspectRatio,
1142
- to,
1143
- message: `aspect ratio ${merged.aspectRatio} coerced to ${to} for ${model.id}`
1144
- });
1145
- merged.aspectRatio = to;
1146
- }
1176
+ const aspectRatio = resolveAspectRatio(
1177
+ merged.aspectRatio,
1178
+ c.aspectRatios,
1179
+ model,
1180
+ onUnsupported,
1181
+ warnings
1182
+ );
1183
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
1147
1184
  const size = resolveTier(
1148
1185
  "size",
1149
1186
  "size_coerced",
@@ -1177,7 +1214,9 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1177
1214
  "count",
1178
1215
  "outputFormat",
1179
1216
  "scaleFactor",
1180
- "safetySettings"
1217
+ "safetySettings",
1218
+ "temperature",
1219
+ "upscale"
1181
1220
  ]);
1182
1221
  return { request: merged, warnings };
1183
1222
  }
@@ -1207,17 +1246,14 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1207
1246
  delete merged.aspectRatio;
1208
1247
  }
1209
1248
  }
1210
- if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1211
- const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1212
- warnings.push({
1213
- code: "ratio_coerced",
1214
- field: "aspectRatio",
1215
- from: merged.aspectRatio,
1216
- to,
1217
- message: `aspect ratio ${merged.aspectRatio} coerced to ${to} for ${model.id}`
1218
- });
1219
- merged.aspectRatio = to;
1220
- }
1249
+ const aspectRatio = resolveAspectRatio(
1250
+ merged.aspectRatio,
1251
+ c.aspectRatios,
1252
+ model,
1253
+ onUnsupported,
1254
+ warnings
1255
+ );
1256
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
1221
1257
  const resolution = resolveTier(
1222
1258
  "resolution",
1223
1259
  "resolution_coerced",
@@ -1229,7 +1265,13 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1229
1265
  warnings
1230
1266
  );
1231
1267
  if (resolution !== void 0) merged.resolution = resolution;
1232
- const duration = resolveDuration(merged.durationSeconds, c.durations, model, warnings);
1268
+ const duration = resolveDuration(
1269
+ merged.durationSeconds,
1270
+ c.durations,
1271
+ model,
1272
+ onUnsupported,
1273
+ warnings
1274
+ );
1233
1275
  if (duration !== void 0) merged.durationSeconds = duration;
1234
1276
  const limits = c.references ?? {};
1235
1277
  let images = trim(
@@ -1284,10 +1326,45 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1284
1326
  "cfgScale",
1285
1327
  "generateAudio",
1286
1328
  "promptExpansion",
1287
- "lastFrame"
1329
+ "lastFrame",
1330
+ "watermark",
1331
+ "safetyChecker"
1288
1332
  ]);
1289
1333
  return { request: merged, warnings };
1290
1334
  }
1335
+ function resolveAudioOptions(model, request, onUnsupported = "error") {
1336
+ const warnings = [];
1337
+ const c = model.constraints;
1338
+ const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1339
+ for (const input of c.requires ?? []) {
1340
+ const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
1341
+ if (!present)
1342
+ throw new ModelKitError({
1343
+ code: "missing_input",
1344
+ message: `${model.id} requires ${input}`,
1345
+ model: model.id
1346
+ });
1347
+ }
1348
+ const duration = resolveDuration(
1349
+ merged.durationSeconds,
1350
+ c.durations,
1351
+ model,
1352
+ onUnsupported,
1353
+ warnings
1354
+ );
1355
+ if (duration !== void 0) merged.durationSeconds = duration;
1356
+ const references = trim(
1357
+ "references",
1358
+ compact(merged.references),
1359
+ c.references?.images ?? c.references?.total,
1360
+ model,
1361
+ warnings
1362
+ );
1363
+ if (references.length > 0) merged.references = references;
1364
+ else delete merged.references;
1365
+ dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
1366
+ return { request: merged, warnings };
1367
+ }
1291
1368
  function dropUnsupported(req, model, warnings, fields) {
1292
1369
  const supports = model.constraints.supports ?? [];
1293
1370
  for (const field of fields) {
@@ -1329,6 +1406,9 @@ function hasAll(keys, names) {
1329
1406
  (n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
1330
1407
  );
1331
1408
  }
1409
+ function missingEnterpriseKeys(config, names) {
1410
+ return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
1411
+ }
1332
1412
  function resolveKeys(config, names, tier = "pro") {
1333
1413
  if (tier === "enterprise" && hasAll(config.keys.enterprise, names))
1334
1414
  return config.keys.enterprise;
@@ -1361,7 +1441,6 @@ function keysFromEnv(env, prefix = "") {
1361
1441
  set("prodia", pick("PRODIA_API_KEY", "PRODIA_TOKEN"));
1362
1442
  set("higgsfield", pick("HIGGSFIELD_API_KEY"));
1363
1443
  set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
1364
- set("openrouter", pick("OPENROUTER_API_KEY"));
1365
1444
  set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
1366
1445
  return keys;
1367
1446
  }
@@ -1409,7 +1488,9 @@ var textBody = z2.string();
1409
1488
  function classifyHttpError(status, body, provider, model) {
1410
1489
  const asText = textBody.safeParse(body);
1411
1490
  const text2 = asText.success ? asText.data : JSON.stringify(body);
1412
- const blocked = /content_policy|safety|blockReason|PROHIBITED_CONTENT|moderation/i.test(text2);
1491
+ const blocked = /content_policy_violation|blockReason|PROHIBITED_CONTENT|moderation_blocked|safety(?![_A-Za-z])/i.test(
1492
+ text2
1493
+ );
1413
1494
  let code = "provider_rejected";
1414
1495
  if (blocked) code = "content_blocked";
1415
1496
  else if (status === 401 || status === 403) code = "auth";
@@ -1430,8 +1511,8 @@ function classifyHttpError(status, body, provider, model) {
1430
1511
  }
1431
1512
  function shouldRetry(err) {
1432
1513
  if (err instanceof ModelKitError) return err.retryable;
1433
- if (err.name === "AbortError" || /ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message))
1434
- return true;
1514
+ if (err.name === "AbortError") return false;
1515
+ if (/ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message)) return true;
1435
1516
  return false;
1436
1517
  }
1437
1518
  async function withRetry(fn, opts = {}) {
@@ -1623,6 +1704,12 @@ import { z as z4 } from "zod";
1623
1704
  function isUrlRef(ref) {
1624
1705
  return "url" in ref;
1625
1706
  }
1707
+ function abortedError() {
1708
+ return new ModelKitError({ code: "timeout", message: "aborted", retryable: false });
1709
+ }
1710
+ function throwIfAborted(signal) {
1711
+ if (signal?.aborted) throw abortedError();
1712
+ }
1626
1713
  function mediaRefToBase64(bytes) {
1627
1714
  let binary = "";
1628
1715
  const CHUNK = 32768;
@@ -1637,10 +1724,34 @@ function base64ToBytes(b64) {
1637
1724
  for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
1638
1725
  return out;
1639
1726
  }
1640
- async function mediaRefToBytes(ref, fetch) {
1727
+ function mediaRefToDataUrl(ref) {
1728
+ if (isUrlRef(ref)) return ref.url;
1729
+ return `data:${ref.mime};base64,${mediaRefToBase64(ref.bytes)}`;
1730
+ }
1731
+ var refToUrl = mediaRefToDataUrl;
1732
+ async function readBody(res) {
1733
+ const text2 = await res.text().catch(() => "");
1734
+ try {
1735
+ const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
1736
+ return decoded.success ? decoded.data : text2;
1737
+ } catch {
1738
+ return text2;
1739
+ }
1740
+ }
1741
+ async function mediaRefToBytes(ref, fetch, options = {}) {
1641
1742
  if (!isUrlRef(ref)) return { bytes: ref.bytes, mime: ref.mime };
1642
- const res = await fetch(ref.url);
1643
- if (!res.ok) throw new Error(`reference fetch failed (${res.status}): ${ref.url}`);
1743
+ const init = {};
1744
+ if (options.signal !== void 0) init.signal = options.signal;
1745
+ const res = await fetch(ref.url, init);
1746
+ if (!res.ok) {
1747
+ const text2 = await res.text().catch(() => "");
1748
+ throw classifyHttpError(
1749
+ res.status,
1750
+ text2,
1751
+ options.provider ?? "media-reference",
1752
+ options.model
1753
+ );
1754
+ }
1644
1755
  const mime = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() || "image/png";
1645
1756
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
1646
1757
  }
@@ -1698,16 +1809,6 @@ var GATEWAY_SLUGS = {
1698
1809
  perplexity: "perplexity-ai",
1699
1810
  deepseek: "deepseek"
1700
1811
  };
1701
- var OPENROUTER_VENDORS = {
1702
- openai: "openai",
1703
- anthropic: "anthropic",
1704
- google: "google",
1705
- xai: "x-ai",
1706
- perplexity: "perplexity",
1707
- deepseek: "deepseek",
1708
- moonshot: "moonshotai",
1709
- minimax: "minimax"
1710
- };
1711
1812
  function detectTextProvider(modelId) {
1712
1813
  const id = modelId.toLowerCase();
1713
1814
  if (id.startsWith("claude") || id.includes("anthropic.")) return "anthropic";
@@ -1724,14 +1825,17 @@ function detectTextProvider(modelId) {
1724
1825
  message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
1725
1826
  });
1726
1827
  }
1727
- function textKeyName(model, routing) {
1728
- if (routing.text === "openrouter") return "openrouter";
1828
+ function textKeyName(model, _routing) {
1729
1829
  return textProviderOf(model);
1730
1830
  }
1731
1831
  function textProviderOf(model) {
1732
1832
  const explicit = model.providerOptions?.["modelkit"]?.["provider"];
1733
1833
  return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
1734
1834
  }
1835
+ function textUsesCloudflareGateway(model, routing) {
1836
+ if (routing.text !== "cloudflare") return false;
1837
+ return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
1838
+ }
1735
1839
  function nativeClientFor(provider) {
1736
1840
  switch (provider) {
1737
1841
  case "openai":
@@ -1764,16 +1868,6 @@ function resolveTextRoute(ctx) {
1764
1868
  retryable: false
1765
1869
  });
1766
1870
  }
1767
- if (mode === "openrouter") {
1768
- const modelId = ctx.model.providerModelId.includes("/") ? ctx.model.providerModelId : `${OPENROUTER_VENDORS[provider]}/${ctx.model.providerModelId}`;
1769
- return {
1770
- provider,
1771
- client: "openai-compatible",
1772
- modelId,
1773
- keyName: "openrouter",
1774
- baseURL: "https://openrouter.ai/api/v1"
1775
- };
1776
- }
1777
1871
  const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
1778
1872
  const route2 = {
1779
1873
  provider,
@@ -1841,7 +1935,7 @@ var aiSdkTextAdapter = {
1841
1935
  case "openai-compatible":
1842
1936
  return createOpenAI({
1843
1937
  ...settings,
1844
- name: route2.provider === "openai" ? "openai" : ctx.routing.text === "openrouter" ? "openrouter" : route2.provider
1938
+ name: route2.provider
1845
1939
  }).chat(route2.modelId);
1846
1940
  case "openai":
1847
1941
  return createOpenAI(settings)(route2.modelId);
@@ -1854,8 +1948,9 @@ function requiredKeys(model, config) {
1854
1948
  if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
1855
1949
  return ["cloudflare"];
1856
1950
  if (model.adapter === "ai-sdk-text") {
1857
- const names = [textKeyName(model, config.routing ?? {})];
1858
- if (config.routing?.text === "cloudflare") names.push("cloudflare");
1951
+ const routing = config.routing ?? {};
1952
+ const names = [textKeyName(model, routing)];
1953
+ if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
1859
1954
  return names;
1860
1955
  }
1861
1956
  return ADAPTER_KEYS[model.adapter];
@@ -1929,6 +2024,11 @@ function pushIgnored(warnings, field, from, modelId) {
1929
2024
  message: `${modelId} provider instance does not support ${field}; ignored`
1930
2025
  });
1931
2026
  }
2027
+ function withoutModelkit(options) {
2028
+ if (!options) return {};
2029
+ const { modelkit: _modelkit, ...rest } = options;
2030
+ return rest;
2031
+ }
1932
2032
  function logCoercions(logger, modelId, warnings) {
1933
2033
  if (warnings.length === 0) return;
1934
2034
  logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
@@ -1945,7 +2045,16 @@ function createModelKit(config, adapters) {
1945
2045
  message: `No adapter registered for ${model.adapter}`,
1946
2046
  model: model.id
1947
2047
  });
1948
- const keys = resolveKeys(config, requiredKeys(model, config), call.tier);
2048
+ const names = requiredKeys(model, config);
2049
+ if (call.tier === "enterprise") {
2050
+ const missing = missingEnterpriseKeys(config, names);
2051
+ if (missing.length > 0)
2052
+ logger.warn(
2053
+ `[modelkit] enterprise keys incomplete for ${model.adapter}; using pro`,
2054
+ { missing }
2055
+ );
2056
+ }
2057
+ const keys = resolveKeys(config, names, call.tier);
1949
2058
  const ctx = {
1950
2059
  model,
1951
2060
  keys,
@@ -2266,8 +2375,15 @@ function createModelKit(config, adapters) {
2266
2375
  model: model.id
2267
2376
  });
2268
2377
  }
2269
- const warnings = [];
2270
- const { adapter, ctx } = context(model, call, warnings);
2378
+ const { abortSignal: _signal, ...request } = req;
2379
+ const { request: resolved, warnings } = resolveAudioOptions(
2380
+ model,
2381
+ request,
2382
+ call.onUnsupported ?? "error"
2383
+ );
2384
+ logCoercions(logger, model.id, warnings);
2385
+ const signal = combineSignals(req.abortSignal, call.signal);
2386
+ const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2271
2387
  if (!adapter.generateAudio) {
2272
2388
  throw new ModelKitError({
2273
2389
  code: "unsupported_option",
@@ -2275,11 +2391,7 @@ function createModelKit(config, adapters) {
2275
2391
  model: model.id
2276
2392
  });
2277
2393
  }
2278
- const result = await adapter.generateAudio(
2279
- { ...model.defaults, ...req, model: model.id },
2280
- ctx
2281
- );
2282
- logCoercions(logger, model.id, warnings);
2394
+ const result = await adapter.generateAudio(resolved, ctx);
2283
2395
  await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
2284
2396
  return result;
2285
2397
  },
@@ -2300,7 +2412,7 @@ function createModelKit(config, adapters) {
2300
2412
  });
2301
2413
  return {
2302
2414
  model,
2303
- providerOptions: entry.providerOptions ?? {},
2415
+ providerOptions: withoutModelkit(entry.providerOptions),
2304
2416
  catalog: entry
2305
2417
  };
2306
2418
  },
@@ -2336,7 +2448,9 @@ function createModelKit(config, adapters) {
2336
2448
  ...textAbortOptions(options.abortSignal, call.signal),
2337
2449
  model: target.languageModel,
2338
2450
  providerOptions: {},
2339
- prepareStep: steps.wrap(options.prepareStep),
2451
+ prepareStep: steps.wrap(
2452
+ options.prepareStep ?? options.experimental_prepareStep
2453
+ ),
2340
2454
  onFinish: async (event) => {
2341
2455
  for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
2342
2456
  await callerOnFinish?.(event);
@@ -2393,6 +2507,7 @@ var SEEDREAM_SIZES = {
2393
2507
  "3:2": "1248x832",
2394
2508
  "2:3": "832x1248",
2395
2509
  "21:9": "1568x672",
2510
+ "9:21": "672x1568",
2396
2511
  "4:5": "864x1080",
2397
2512
  "5:4": "1080x864"
2398
2513
  },
@@ -2405,16 +2520,34 @@ var SEEDREAM_SIZES = {
2405
2520
  "3:2": "2496x1664",
2406
2521
  "2:3": "1664x2496",
2407
2522
  "21:9": "3136x1344",
2523
+ "9:21": "1344x3136",
2408
2524
  "4:5": "1728x2160",
2409
2525
  "5:4": "2160x1728"
2526
+ },
2527
+ // 4K keeps the long edge at Ark's 4096 cap (a doubled 2K entry would exceed
2528
+ // it); sides are multiples of 16.
2529
+ "4K": {
2530
+ "1:1": "4096x4096",
2531
+ "4:3": "4096x3072",
2532
+ "3:4": "3072x4096",
2533
+ "16:9": "4096x2304",
2534
+ "9:16": "2304x4096",
2535
+ "3:2": "4096x2736",
2536
+ "2:3": "2736x4096",
2537
+ "21:9": "4096x1760",
2538
+ "9:21": "1760x4096",
2539
+ "4:5": "3280x4096",
2540
+ "5:4": "4096x3280"
2410
2541
  }
2411
2542
  };
2412
2543
  var arkAdapter = {
2413
2544
  id: "ark",
2414
2545
  async generateImage(req, ctx) {
2546
+ throwIfAborted(ctx.signal);
2415
2547
  return generateSeedreamImage(req, ctx);
2416
2548
  },
2417
2549
  async generateVideo(req, ctx) {
2550
+ throwIfAborted(ctx.signal);
2418
2551
  return generateSeedanceVideo(req, ctx);
2419
2552
  }
2420
2553
  };
@@ -2434,7 +2567,7 @@ function arkKey(ctx) {
2434
2567
  function throwArkError(status, body, model) {
2435
2568
  const parsed = z5.string().safeParse(body);
2436
2569
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2437
- if (/sensitive.?content|inputimage|human.?face/i.test(text2)) {
2570
+ if (/sensitive.?content|human.?face/i.test(text2)) {
2438
2571
  const init = {
2439
2572
  code: "content_blocked",
2440
2573
  message: `ark rejected the request: ${text2.slice(0, 500)}`,
@@ -2459,7 +2592,7 @@ function throwArkError(status, body, model) {
2459
2592
  throw classifyHttpError(status, body, "ark", model);
2460
2593
  }
2461
2594
  function seedreamSize(aspect, size) {
2462
- const tier = size === "1K" ? "1K" : "2K";
2595
+ const tier = size === "4K" || size === "1K" ? size : "2K";
2463
2596
  const table = SEEDREAM_SIZES[tier];
2464
2597
  return table[aspect ?? ""] ?? table["1:1"] ?? "2048x2048";
2465
2598
  }
@@ -2470,10 +2603,6 @@ function sniffedImageMime(bytes) {
2470
2603
  return "image/webp";
2471
2604
  return "image/jpeg";
2472
2605
  }
2473
- function arkUrl(ref) {
2474
- if ("url" in ref) return ref.url;
2475
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2476
- }
2477
2606
  var SeedreamImageSchema = z5.object({
2478
2607
  url: z5.string().optional(),
2479
2608
  b64_json: z5.string().optional()
@@ -2500,7 +2629,7 @@ async function generateSeedreamImage(req, ctx) {
2500
2629
  const key = arkKey(ctx);
2501
2630
  const modelId = ctx.model.id;
2502
2631
  const size = seedreamSize(req.aspectRatio, req.size);
2503
- const refs = (req.references ?? []).map(arkUrl);
2632
+ const refs = (req.references ?? []).map(refToUrl);
2504
2633
  const body = {
2505
2634
  model: ctx.model.providerModelId,
2506
2635
  prompt: req.prompt,
@@ -2552,10 +2681,18 @@ async function generateSeedreamImage(req, ctx) {
2552
2681
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
2553
2682
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
2554
2683
  }
2684
+ var SeedanceUsageSchema = z5.object({
2685
+ total_tokens: z5.number().optional(),
2686
+ completion_tokens: z5.number().optional()
2687
+ });
2555
2688
  var SeedanceResponseSchema = z5.object({
2556
2689
  id: z5.string().optional(),
2557
2690
  status: z5.string().optional(),
2558
2691
  content: z5.object({ video_url: z5.string().optional() }).optional(),
2692
+ usage: SeedanceUsageSchema.optional(),
2693
+ duration: z5.number().optional(),
2694
+ framespersecond: z5.number().optional(),
2695
+ resolution: z5.string().optional(),
2559
2696
  error: z5.union([z5.string(), z5.object({ message: z5.string().optional() })]).optional()
2560
2697
  });
2561
2698
  var SeedanceErrorMessageSchema = z5.object({ message: z5.string().optional() });
@@ -2587,42 +2724,42 @@ async function generateSeedanceVideo(req, ctx) {
2587
2724
  if (req.firstFrame) {
2588
2725
  content.push({
2589
2726
  type: "image_url",
2590
- image_url: { url: arkUrl(req.firstFrame) },
2727
+ image_url: { url: refToUrl(req.firstFrame) },
2591
2728
  role: "first_frame"
2592
2729
  });
2593
2730
  }
2594
2731
  if (req.lastFrame) {
2595
2732
  content.push({
2596
2733
  type: "image_url",
2597
- image_url: { url: arkUrl(req.lastFrame) },
2734
+ image_url: { url: refToUrl(req.lastFrame) },
2598
2735
  role: "last_frame"
2599
2736
  });
2600
2737
  }
2601
2738
  for (const ref of req.referenceImages ?? []) {
2602
2739
  content.push({
2603
2740
  type: "image_url",
2604
- image_url: { url: arkUrl(ref) },
2741
+ image_url: { url: refToUrl(ref) },
2605
2742
  role: "reference_image"
2606
2743
  });
2607
2744
  }
2608
2745
  if (req.sourceVideo) {
2609
2746
  content.push({
2610
2747
  type: "video_url",
2611
- video_url: { url: arkUrl(req.sourceVideo) },
2748
+ video_url: { url: refToUrl(req.sourceVideo) },
2612
2749
  role: "reference_video"
2613
2750
  });
2614
2751
  }
2615
2752
  for (const ref of req.referenceVideos ?? []) {
2616
2753
  content.push({
2617
2754
  type: "video_url",
2618
- video_url: { url: arkUrl(ref) },
2755
+ video_url: { url: refToUrl(ref) },
2619
2756
  role: "reference_video"
2620
2757
  });
2621
2758
  }
2622
2759
  for (const ref of req.referenceAudios ?? []) {
2623
2760
  content.push({
2624
2761
  type: "audio_url",
2625
- audio_url: { url: arkUrl(ref) },
2762
+ audio_url: { url: refToUrl(ref) },
2626
2763
  role: "reference_audio"
2627
2764
  });
2628
2765
  }
@@ -2636,6 +2773,7 @@ async function generateSeedanceVideo(req, ctx) {
2636
2773
  if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
2637
2774
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
2638
2775
  if (req.seed !== void 0) body.seed = req.seed;
2776
+ if (req.watermark !== void 0) body.watermark = req.watermark;
2639
2777
  const submit = await withRetry(async () => {
2640
2778
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
2641
2779
  method: "POST",
@@ -2699,6 +2837,11 @@ async function generateSeedanceVideo(req, ctx) {
2699
2837
  "Seedance task succeeded but returned no video_url",
2700
2838
  modelId
2701
2839
  );
2840
+ const tokens = polled.usage;
2841
+ if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
2842
+ usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
2843
+ usage2.outputTokens = tokens.completion_tokens;
2844
+ }
2702
2845
  return {
2703
2846
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
2704
2847
  usage: usage2,
@@ -2762,24 +2905,17 @@ var defaultDeps = { createFalClient: defaultCreateFalClient };
2762
2905
  function createFalAdapter(deps = defaultDeps) {
2763
2906
  return {
2764
2907
  id: "fal",
2765
- generateImage: (req, ctx) => generateMuseImage(req, ctx, deps),
2766
- generateVideo: (req, ctx) => generateFalVideo(req, ctx, deps)
2908
+ generateImage: (req, ctx) => {
2909
+ throwIfAborted(ctx.signal);
2910
+ return generateMuseImage(req, ctx, deps);
2911
+ },
2912
+ generateVideo: (req, ctx) => {
2913
+ throwIfAborted(ctx.signal);
2914
+ return generateFalVideo(req, ctx, deps);
2915
+ }
2767
2916
  };
2768
2917
  }
2769
2918
  var falAdapter = createFalAdapter();
2770
- function refToUrl(ref) {
2771
- if ("url" in ref) return ref.url;
2772
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2773
- }
2774
- async function readBody(res) {
2775
- const text2 = await res.text().catch(() => "");
2776
- try {
2777
- const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
2778
- return decoded.success ? decoded.data : text2;
2779
- } catch {
2780
- return text2;
2781
- }
2782
- }
2783
2919
  var falDetailSchema = z6.object({ detail: JsonValueSchema });
2784
2920
  function liftDetail(body) {
2785
2921
  const parsed = falDetailSchema.safeParse(body);
@@ -3016,8 +3152,12 @@ async function generateMuseImage(req, ctx, deps) {
3016
3152
  raw: payload
3017
3153
  };
3018
3154
  }
3155
+ var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
3156
+ "minimax/h3-max",
3157
+ "minimax/h3-max/reference-to-video"
3158
+ ]);
3019
3159
  function minimaxFamily(providerModelId) {
3020
- return providerModelId.toLowerCase().includes("h3-max") ? "h3-max" : "h3";
3160
+ return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
3021
3161
  }
3022
3162
  function minimaxBase(req, family) {
3023
3163
  const resolution = (family === "h3-max" ? req.resolution ?? "768p" : req.resolution ?? "2k").toUpperCase();
@@ -3025,14 +3165,17 @@ function minimaxBase(req, family) {
3025
3165
  prompt: req.prompt.trim(),
3026
3166
  duration: req.durationSeconds ?? 5,
3027
3167
  resolution,
3028
- prompt_expansion_mode: req.promptExpansion ?? "balanced",
3029
- enable_safety_checker: true
3168
+ prompt_expansion_mode: req.promptExpansion ?? "balanced"
3030
3169
  };
3170
+ if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
3031
3171
  if (req.seed !== void 0) input.seed = req.seed;
3032
3172
  return input;
3033
3173
  }
3174
+ var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
3175
+ "fal-ai/kling-video/o1/video-to-video/reference"
3176
+ ]);
3034
3177
  function isKling(providerModelId) {
3035
- return providerModelId.toLowerCase().includes("kling");
3178
+ return KLING_MODEL_IDS.has(providerModelId.toLowerCase());
3036
3179
  }
3037
3180
  function klingO1Input(req) {
3038
3181
  const source = req.sourceVideo ? refToUrl(req.sourceVideo) : void 0;
@@ -3105,7 +3248,9 @@ async function generateFalVideo(req, ctx, deps) {
3105
3248
  if (lastFrame) base.end_image_url = lastFrame;
3106
3249
  } else {
3107
3250
  endpoint = `minimax/${family}/text-to-video`;
3108
- base.aspect_ratio = req.aspectRatio ?? "adaptive";
3251
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
3252
+ base.aspect_ratio = req.aspectRatio;
3253
+ }
3109
3254
  }
3110
3255
  if (ctx.routing.fal === "cloudflare-passthrough") {
3111
3256
  return await passthroughVideoJob(ctx, req, endpoint, base);
@@ -3593,6 +3738,14 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
3593
3738
  model: modelId
3594
3739
  });
3595
3740
  }
3741
+ if (req.lastFrame !== void 0 && req.firstFrame === void 0) {
3742
+ throw new ModelKitError({
3743
+ code: "missing_input",
3744
+ message: `${modelId} requires firstFrame when lastFrame is set`,
3745
+ provider: "google-genai",
3746
+ model: modelId
3747
+ });
3748
+ }
3596
3749
  const duration = req.durationSeconds ?? 8;
3597
3750
  const personGeneration = req.firstFrame ?? refs.length > 0 ? "allow_adult" : "allow_all";
3598
3751
  let image;
@@ -3659,7 +3812,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
3659
3812
  throwSdkError(cause, modelId);
3660
3813
  }
3661
3814
  };
3662
- const jobId = operation.name ?? "veo-operation";
3815
+ const jobId = operation.name ?? crypto.randomUUID();
3663
3816
  const usage2 = videoUsage2(ctx, req, duration);
3664
3817
  return {
3665
3818
  jobId,
@@ -3798,6 +3951,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3798
3951
  });
3799
3952
  }
3800
3953
  for (const ref of videos) {
3954
+ if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
3801
3955
  const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "video/mp4", modelId);
3802
3956
  parts.push({
3803
3957
  type: "video",
@@ -3806,6 +3960,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3806
3960
  });
3807
3961
  }
3808
3962
  if (req.firstFrame) {
3963
+ if (req.firstFrame.label !== void 0)
3964
+ parts.push({ type: "text", text: req.firstFrame.label });
3809
3965
  const media = await resolveMedia(
3810
3966
  req.firstFrame,
3811
3967
  ctx.fetch,
@@ -3824,6 +3980,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3824
3980
  }
3825
3981
  }
3826
3982
  for (const ref of images) {
3983
+ if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
3827
3984
  const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
3828
3985
  if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
3829
3986
  parts.push({
@@ -3867,7 +4024,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3867
4024
  } finally {
3868
4025
  await cleanupUploads();
3869
4026
  }
3870
- const jobId = interaction.id ?? "gemini-omni-interaction";
4027
+ const jobId = interaction.id ?? crypto.randomUUID();
3871
4028
  const usage2 = videoUsage2(ctx, req, duration);
3872
4029
  const getInteraction = async () => {
3873
4030
  try {
@@ -4093,11 +4250,11 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4093
4250
  const model = google(ctx.model.providerModelId);
4094
4251
  const content = [];
4095
4252
  for (const ref of req.references ?? []) {
4253
+ if (ref.label !== void 0) content.push({ type: "text", text: ref.label });
4096
4254
  if ("url" in ref) content.push({ type: "image", image: ref.url });
4097
4255
  else content.push({ type: "image", image: ref.bytes, mediaType: ref.mime });
4098
4256
  }
4099
4257
  content.push({ type: "text", text: req.prompt });
4100
- void ctx.call.postCropToAspect;
4101
4258
  const imageConfig = {};
4102
4259
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4103
4260
  imageConfig.aspectRatio = req.aspectRatio;
@@ -4113,7 +4270,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4113
4270
  const timeout = AbortSignal.timeout(GEMINI_IMAGE_TIMEOUT_MS);
4114
4271
  const signal = ctx.signal !== void 0 ? AbortSignal.any([ctx.signal, timeout]) : timeout;
4115
4272
  try {
4116
- return await deps.runTextGeneration({
4273
+ const genOptions = {
4117
4274
  model,
4118
4275
  messages: [{ role: "user", content }],
4119
4276
  maxRetries: 0,
@@ -4121,7 +4278,9 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4121
4278
  google: googleOptions
4122
4279
  },
4123
4280
  abortSignal: signal
4124
- });
4281
+ };
4282
+ if (req.temperature !== void 0) genOptions.temperature = req.temperature;
4283
+ return await deps.runTextGeneration(genOptions);
4125
4284
  } catch (cause) {
4126
4285
  throw toProviderError(cause, ctx);
4127
4286
  }
@@ -4325,26 +4484,14 @@ function headers(ctx) {
4325
4484
  const { key, secret } = credentials(ctx);
4326
4485
  return { "Content-Type": "application/json", "hf-api-key": key, "hf-secret": secret };
4327
4486
  }
4328
- function refToUrl2(ref) {
4329
- if ("url" in ref) return ref.url;
4330
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
4331
- }
4332
- async function readBody2(res) {
4333
- const text2 = await res.text().catch(() => "");
4334
- try {
4335
- const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
4336
- return decoded.success ? decoded.data : text2;
4337
- } catch {
4338
- return text2;
4339
- }
4340
- }
4341
4487
  function klingEndpoint(providerModelId) {
4342
4488
  if (providerModelId.startsWith("http")) return providerModelId;
4343
4489
  const path = providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId;
4344
4490
  return `${PLATFORM}/${path}`;
4345
4491
  }
4346
- function isDop(providerModelId) {
4347
- return providerModelId.toLowerCase().includes("dop");
4492
+ var DOP_MODEL_IDS = /* @__PURE__ */ new Set(["dop", "dop-preview"]);
4493
+ function higgsfieldVideoKind(providerModelId) {
4494
+ return DOP_MODEL_IDS.has(providerModelId.toLowerCase()) ? "dop" : "kling";
4348
4495
  }
4349
4496
  function videoUsage3(ctx, req, duration) {
4350
4497
  const event = {
@@ -4388,12 +4535,12 @@ async function createRequest(ctx, url, init) {
4388
4535
  throw classifyThrown("higgsfield", cause, ctx.model.id);
4389
4536
  }
4390
4537
  if (!res.ok) {
4391
- throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4538
+ throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
4392
4539
  }
4393
4540
  return res;
4394
4541
  }
4395
4542
  async function generateKlingVideo(req, ctx) {
4396
- const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4543
+ const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
4397
4544
  if (!firstFrame) {
4398
4545
  throw new ModelKitError({
4399
4546
  code: "missing_input",
@@ -4412,7 +4559,7 @@ async function generateKlingVideo(req, ctx) {
4412
4559
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
4413
4560
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4414
4561
  body.aspect_ratio = req.aspectRatio;
4415
- if (req.lastFrame) body.last_image_url = refToUrl2(req.lastFrame);
4562
+ if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
4416
4563
  const endpoint = klingEndpoint(ctx.model.providerModelId);
4417
4564
  const retryOptions = {};
4418
4565
  if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
@@ -4438,9 +4585,9 @@ async function generateKlingVideo(req, ctx) {
4438
4585
  } catch {
4439
4586
  return void 0;
4440
4587
  }
4441
- if (res.status >= 500) return void 0;
4588
+ if (res.status === 429 || res.status >= 500) return void 0;
4442
4589
  if (!res.ok) {
4443
- throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4590
+ throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
4444
4591
  }
4445
4592
  const payload = JsonValueSchema.parse(await res.json());
4446
4593
  const parsed = klingStatusSchema.safeParse(payload);
@@ -4547,7 +4694,7 @@ function dopUrl(body) {
4547
4694
  var dopCreateSchema = z10.object({ id: z10.string() });
4548
4695
  var dopStatusSchema = z10.object({ status: z10.string().optional() });
4549
4696
  async function generateDopVideo(req, ctx) {
4550
- const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4697
+ const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
4551
4698
  if (!firstFrame) {
4552
4699
  throw new ModelKitError({
4553
4700
  code: "missing_input",
@@ -4567,7 +4714,7 @@ async function generateDopVideo(req, ctx) {
4567
4714
  webhook: null
4568
4715
  };
4569
4716
  if (req.lastFrame) {
4570
- params.input_images_end = [{ type: "image_url", image_url: refToUrl2(req.lastFrame) }];
4717
+ params.input_images_end = [{ type: "image_url", image_url: refToUrl(req.lastFrame) }];
4571
4718
  }
4572
4719
  if (req.seed !== void 0) params.seed = req.seed;
4573
4720
  const retryOptions = {};
@@ -4657,7 +4804,10 @@ async function generateDopVideo(req, ctx) {
4657
4804
  }
4658
4805
  var higgsfieldAdapter = {
4659
4806
  id: "higgsfield",
4660
- generateVideo: (req, ctx) => isDop(ctx.model.providerModelId) ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx)
4807
+ generateVideo: (req, ctx) => {
4808
+ throwIfAborted(ctx.signal);
4809
+ return higgsfieldVideoKind(ctx.model.providerModelId) === "dop" ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx);
4810
+ }
4661
4811
  };
4662
4812
 
4663
4813
  // src/adapters/openai-image.ts
@@ -4752,6 +4902,7 @@ var openaiUsageSchema = z11.object({
4752
4902
  var openaiImageAdapter = {
4753
4903
  id: "openai-image",
4754
4904
  async generateImage(req, ctx) {
4905
+ throwIfAborted(ctx.signal);
4755
4906
  const apiKey = ctx.keys.openai;
4756
4907
  if (!apiKey)
4757
4908
  throw new ModelKitError({
@@ -4761,6 +4912,13 @@ var openaiImageAdapter = {
4761
4912
  model: ctx.model.id,
4762
4913
  retryable: false
4763
4914
  });
4915
+ if ((req.references ?? []).some((ref) => ref.label !== void 0)) {
4916
+ ctx.warnings.push({
4917
+ code: "option_ignored",
4918
+ field: "references.label",
4919
+ message: "openai-image cannot express reference labels; ignoring them"
4920
+ });
4921
+ }
4764
4922
  const client2 = new OpenAI({ apiKey, fetch: ctx.fetch, maxRetries: 0 });
4765
4923
  const size = req.exactSize !== void 0 ? req.exactSize : req.aspectRatio === void 0 || req.aspectRatio === "adaptive" ? void 0 : aspectRatioToSize(req.aspectRatio, req.size ?? "1K");
4766
4924
  const refs = req.references ?? [];
@@ -4774,24 +4932,34 @@ var openaiImageAdapter = {
4774
4932
  try {
4775
4933
  if (!isEdit) {
4776
4934
  if (size !== void 0) {
4777
- return await client2.images.generate({
4935
+ return await client2.images.generate(
4936
+ {
4937
+ model: ctx.model.providerModelId,
4938
+ prompt: req.prompt,
4939
+ size,
4940
+ quality: sdkQuality,
4941
+ ...count
4942
+ },
4943
+ { signal: ctx.signal }
4944
+ );
4945
+ }
4946
+ return await client2.images.generate(
4947
+ {
4778
4948
  model: ctx.model.providerModelId,
4779
4949
  prompt: req.prompt,
4780
- size,
4781
4950
  quality: sdkQuality,
4782
4951
  ...count
4783
- });
4784
- }
4785
- return await client2.images.generate({
4786
- model: ctx.model.providerModelId,
4787
- prompt: req.prompt,
4788
- quality: sdkQuality,
4789
- ...count
4790
- });
4952
+ },
4953
+ { signal: ctx.signal }
4954
+ );
4791
4955
  }
4792
4956
  const files = await Promise.all(
4793
4957
  refs.slice(0, MAX_EDIT_REFERENCES).map(async (ref, i) => {
4794
- const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch);
4958
+ const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch, {
4959
+ signal: ctx.signal,
4960
+ provider: "openai-image",
4961
+ model: ctx.model.id
4962
+ });
4795
4963
  const ext = mime.includes("jpeg") ? "jpg" : mime.includes("webp") ? "webp" : "png";
4796
4964
  return new File([bytes], `ref-${i}.${ext}`, { type: mime });
4797
4965
  })
@@ -4799,22 +4967,28 @@ var openaiImageAdapter = {
4799
4967
  const single = files.length === 1 ? files[0] : void 0;
4800
4968
  const imageInput = single ?? files;
4801
4969
  if (size !== void 0) {
4802
- return await client2.images.edit({
4970
+ return await client2.images.edit(
4971
+ {
4972
+ model: ctx.model.providerModelId,
4973
+ image: imageInput,
4974
+ prompt: req.prompt,
4975
+ size,
4976
+ quality: sdkQuality,
4977
+ ...count
4978
+ },
4979
+ { signal: ctx.signal }
4980
+ );
4981
+ }
4982
+ return await client2.images.edit(
4983
+ {
4803
4984
  model: ctx.model.providerModelId,
4804
4985
  image: imageInput,
4805
4986
  prompt: req.prompt,
4806
- size,
4807
4987
  quality: sdkQuality,
4808
4988
  ...count
4809
- });
4810
- }
4811
- return await client2.images.edit({
4812
- model: ctx.model.providerModelId,
4813
- image: imageInput,
4814
- prompt: req.prompt,
4815
- quality: sdkQuality,
4816
- ...count
4817
- });
4989
+ },
4990
+ { signal: ctx.signal }
4991
+ );
4818
4992
  } catch (cause) {
4819
4993
  throw toProviderError2(cause, ctx);
4820
4994
  }
@@ -4896,7 +5070,7 @@ async function refToBytes(ctx, ref) {
4896
5070
  if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
4897
5071
  let res;
4898
5072
  try {
4899
- res = await ctx.fetch(ref.url);
5073
+ res = await ctx.fetch(ref.url, ctx.signal ? { signal: ctx.signal } : {});
4900
5074
  } catch (cause) {
4901
5075
  throw classifyThrown("prodia", cause, ctx.model.id);
4902
5076
  }
@@ -4942,6 +5116,12 @@ function emptyImage() {
4942
5116
  retryable: false
4943
5117
  });
4944
5118
  }
5119
+ function inputExtension(mime) {
5120
+ if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
5121
+ if (mime.includes("webp")) return "webp";
5122
+ if (mime.includes("gif")) return "gif";
5123
+ return "png";
5124
+ }
4945
5125
  function isBgRemove(providerModelId) {
4946
5126
  const id = providerModelId.toLowerCase();
4947
5127
  return id.includes("remove-background") || id.includes("bg-remove");
@@ -4950,6 +5130,7 @@ function isKlein(providerModelId) {
4950
5130
  return providerModelId.toLowerCase().includes("klein");
4951
5131
  }
4952
5132
  async function generateProdiaImage(req, ctx) {
5133
+ throwIfAborted(ctx.signal);
4953
5134
  const key = ctx.keys.prodia;
4954
5135
  if (!key) {
4955
5136
  throw new ModelKitError({
@@ -5048,7 +5229,9 @@ async function generateProdiaImage(req, ctx) {
5048
5229
  "input",
5049
5230
  // Uint8Array<ArrayBufferLike> is not a valid BlobPart under the
5050
5231
  // strict lib types; copy into a fresh ArrayBuffer-backed view.
5051
- new File([new Uint8Array(input.bytes)], `input-${i}.jpg`, { type: "image/jpeg" })
5232
+ new File([new Uint8Array(input.bytes)], `input-${i}.${inputExtension(input.mime)}`, {
5233
+ type: input.mime
5234
+ })
5052
5235
  );
5053
5236
  });
5054
5237
  const retryOpts = {
@@ -5063,11 +5246,13 @@ async function generateProdiaImage(req, ctx) {
5063
5246
  res = await withRetry(async () => {
5064
5247
  let attemptRes;
5065
5248
  try {
5066
- attemptRes = await ctx.fetch(PRODIA_JOB_URL, {
5249
+ const init = {
5067
5250
  method: "POST",
5068
5251
  headers: { Authorization: `Bearer ${key}`, Accept: accept },
5069
5252
  body: form
5070
- });
5253
+ };
5254
+ if (ctx.signal !== void 0) init.signal = ctx.signal;
5255
+ attemptRes = await ctx.fetch(PRODIA_JOB_URL, init);
5071
5256
  } catch (err) {
5072
5257
  throw classifyThrown("prodia", err, ctx.model.id);
5073
5258
  }
@@ -5128,11 +5313,7 @@ function client(ctx, deps) {
5128
5313
  retryable: false
5129
5314
  });
5130
5315
  }
5131
- return deps.createReplicateClient({ auth: token });
5132
- }
5133
- function refToUrl3(ref) {
5134
- if ("url" in ref) return ref.url;
5135
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
5316
+ return deps.createReplicateClient({ auth: token, fetch: ctx.fetch });
5136
5317
  }
5137
5318
  function route(providerModelId) {
5138
5319
  if (providerModelId.includes(":")) {
@@ -5152,8 +5333,9 @@ function replicateError(cause, ctx) {
5152
5333
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5153
5334
  return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
5154
5335
  }
5155
- function isLower(id) {
5156
- return id.toLowerCase();
5336
+ function baseModelId(providerModelId) {
5337
+ const colon = providerModelId.indexOf(":");
5338
+ return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
5157
5339
  }
5158
5340
  function predictionErrorBody(cause) {
5159
5341
  const parsed = JsonValueSchema.safeParse(cause);
@@ -5201,6 +5383,7 @@ function noOutput() {
5201
5383
  });
5202
5384
  }
5203
5385
  async function runPrediction(ctx, input, deps) {
5386
+ throwIfAborted(ctx.signal);
5204
5387
  const api = client(ctx, deps);
5205
5388
  const createOptions = { ...route(ctx.model.providerModelId), input };
5206
5389
  let prediction;
@@ -5208,12 +5391,14 @@ async function runPrediction(ctx, input, deps) {
5208
5391
  prediction = await withRetry(
5209
5392
  async () => {
5210
5393
  try {
5211
- return await api.predictions.create(createOptions);
5394
+ return await api.predictions.create(
5395
+ ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
5396
+ );
5212
5397
  } catch (cause) {
5213
5398
  throw replicateError(cause, ctx);
5214
5399
  }
5215
5400
  },
5216
- ctx.signal ? { signal: ctx.signal } : {}
5401
+ { attempts: 1 }
5217
5402
  );
5218
5403
  } catch (cause) {
5219
5404
  throw replicateError(cause, ctx);
@@ -5226,7 +5411,10 @@ async function runPrediction(ctx, input, deps) {
5226
5411
  const done = await pollUntil(async () => {
5227
5412
  let current;
5228
5413
  try {
5229
- current = await api.predictions.get(prediction.id);
5414
+ current = await api.predictions.get(
5415
+ prediction.id,
5416
+ ctx.signal ? { signal: ctx.signal } : void 0
5417
+ );
5230
5418
  } catch (cause) {
5231
5419
  throw replicateError(cause, ctx);
5232
5420
  }
@@ -5293,21 +5481,32 @@ async function download(ctx, url) {
5293
5481
  const mime = res.headers.get("content-type") ?? "image/png";
5294
5482
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
5295
5483
  }
5296
- function isUpscaler(providerModelId) {
5297
- const id = isLower(providerModelId);
5298
- return id.includes("upscal") || id.includes("crystal") || id.includes("topaz");
5299
- }
5300
- function isTopazUpscaler(providerModelId) {
5301
- return isLower(providerModelId).includes("topazlabs/image-upscale");
5302
- }
5303
- function isQwen(providerModelId) {
5304
- return isLower(providerModelId).includes("qwen");
5305
- }
5306
- function isWanImage(providerModelId) {
5307
- return isLower(providerModelId).includes("wan-2.7");
5484
+ var REPLICATE_IMAGE_KINDS = {
5485
+ "topazlabs/image-upscale": "topaz",
5486
+ "philz1337x/crystal-upscaler": "upscaler",
5487
+ "wan-video/wan-2.7-image-pro": "wan",
5488
+ "qwen/qwen-image-2-pro": "qwen-image",
5489
+ "qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
5490
+ };
5491
+ function imageKind(providerModelId) {
5492
+ return REPLICATE_IMAGE_KINDS[baseModelId(providerModelId)] ?? "generic";
5493
+ }
5494
+ var REPLICATE_VIDEO_KINDS = {
5495
+ "kling-video/v2.5-turbo/pro/image-to-video": "kling",
5496
+ "kling-video/v3.0/pro/image-to-video": "kling",
5497
+ "kwaivgi/kling-v3-video": "kling",
5498
+ "kwaivgi/kling-v3-omni-video": "kling-omni",
5499
+ "minimax/hailuo-02": "hailuo"
5500
+ };
5501
+ function videoKind(providerModelId) {
5502
+ return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)] ?? "wan";
5308
5503
  }
5309
- function isQwenEditPlus(providerModelId) {
5310
- return isLower(providerModelId).includes("edit");
5504
+ var REPLICATE_AUDIO_KINDS = {
5505
+ "zsxkib/mmaudio": "mmaudio",
5506
+ "elevenlabs/music": "elevenlabs"
5507
+ };
5508
+ function audioKind(providerModelId) {
5509
+ return REPLICATE_AUDIO_KINDS[baseModelId(providerModelId)] ?? "lyria";
5311
5510
  }
5312
5511
  var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
5313
5512
  "1:1",
@@ -5350,87 +5549,113 @@ function wanImageSize(aspectRatio, size) {
5350
5549
  async function generateReplicateImage(req, ctx, deps) {
5351
5550
  const id = ctx.model.providerModelId;
5352
5551
  let input;
5353
- if (isTopazUpscaler(id)) {
5354
- const first = (req.references ?? [])[0];
5355
- if (!first) {
5356
- throw new ModelKitError({
5357
- code: "missing_input",
5358
- message: `${ctx.model.id} requires a reference image to upscale`,
5359
- provider: "replicate",
5360
- model: ctx.model.id,
5361
- retryable: false
5362
- });
5552
+ switch (imageKind(id)) {
5553
+ case "topaz": {
5554
+ const first = (req.references ?? [])[0];
5555
+ if (!first) {
5556
+ throw new ModelKitError({
5557
+ code: "missing_input",
5558
+ message: `${ctx.model.id} requires a reference image to upscale`,
5559
+ provider: "replicate",
5560
+ model: ctx.model.id,
5561
+ retryable: false
5562
+ });
5563
+ }
5564
+ let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
5565
+ if (format !== "png" && format !== "jpg") {
5566
+ ctx.warnings.push({
5567
+ code: "option_ignored",
5568
+ field: "outputFormat",
5569
+ from: format,
5570
+ message: "topazlabs/image-upscale supports only png and jpg; using png"
5571
+ });
5572
+ format = "png";
5573
+ }
5574
+ const upscale = req.upscale;
5575
+ const topaz = {
5576
+ image: refToUrl(first),
5577
+ enhance_model: upscale?.enhanceModel ?? "Standard V2",
5578
+ output_format: format,
5579
+ upscale_factor: `${req.scaleFactor ?? 2}x`,
5580
+ face_enhancement: upscale?.faceEnhancement ?? false
5581
+ };
5582
+ if (upscale?.subjectDetection !== void 0)
5583
+ topaz.subject_detection = upscale.subjectDetection;
5584
+ if (upscale?.faceEnhancementCreativity !== void 0)
5585
+ topaz.face_enhancement_creativity = upscale.faceEnhancementCreativity;
5586
+ if (upscale?.faceEnhancementStrength !== void 0)
5587
+ topaz.face_enhancement_strength = upscale.faceEnhancementStrength;
5588
+ input = topaz;
5589
+ break;
5363
5590
  }
5364
- let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
5365
- if (format !== "png" && format !== "jpg") {
5366
- ctx.warnings.push({
5367
- code: "option_ignored",
5368
- field: "outputFormat",
5369
- from: format,
5370
- message: "topazlabs/image-upscale supports only png and jpg; using png"
5371
- });
5372
- format = "png";
5591
+ case "upscaler": {
5592
+ const first = (req.references ?? [])[0];
5593
+ if (!first) {
5594
+ throw new ModelKitError({
5595
+ code: "missing_input",
5596
+ message: `${ctx.model.id} requires a reference image to upscale`,
5597
+ provider: "replicate",
5598
+ model: ctx.model.id,
5599
+ retryable: false
5600
+ });
5601
+ }
5602
+ const imageInput = { prompt: req.prompt };
5603
+ imageInput.image = refToUrl(first);
5604
+ imageInput.creativity = 0;
5605
+ imageInput.scale_factor = 2;
5606
+ imageInput.output_format = "png";
5607
+ input = imageInput;
5608
+ break;
5373
5609
  }
5374
- input = {
5375
- image: refToUrl3(first),
5376
- enhance_model: "Standard V2",
5377
- output_format: format,
5378
- upscale_factor: `${req.scaleFactor ?? 2}x`,
5379
- face_enhancement: true
5380
- };
5381
- } else if (isUpscaler(id)) {
5382
- const refs = req.references ?? [];
5383
- const first = refs[0];
5384
- if (!first) {
5385
- throw new ModelKitError({
5386
- code: "missing_input",
5387
- message: `${ctx.model.id} requires a reference image to upscale`,
5388
- provider: "replicate",
5389
- model: ctx.model.id,
5390
- retryable: false
5391
- });
5610
+ case "wan": {
5611
+ const refs = (req.references ?? []).map(refToUrl);
5612
+ const imageInput = { prompt: req.prompt };
5613
+ if (refs.length > 0) imageInput.images = refs;
5614
+ imageInput.size = wanImageSize(req.aspectRatio, req.size);
5615
+ input = imageInput;
5616
+ break;
5392
5617
  }
5393
- const imageInput = { prompt: req.prompt };
5394
- imageInput.image = refToUrl3(first);
5395
- imageInput.creativity = 0;
5396
- imageInput.scale_factor = 2;
5397
- imageInput.output_format = "png";
5398
- input = imageInput;
5399
- } else if (isWanImage(id)) {
5400
- const refs = (req.references ?? []).map(refToUrl3);
5401
- const imageInput = { prompt: req.prompt };
5402
- if (refs.length > 0) imageInput.images = refs;
5403
- imageInput.size = wanImageSize(req.aspectRatio, req.size);
5404
- input = imageInput;
5405
- } else if (isQwen(id)) {
5406
- const refs = (req.references ?? []).map(refToUrl3);
5407
- const firstUrl = refs[0];
5408
- const imageInput = { prompt: req.prompt };
5409
- if (firstUrl !== void 0) {
5410
- imageInput.image = firstUrl;
5411
- if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
5618
+ case "qwen-image": {
5619
+ const refs = (req.references ?? []).map(refToUrl);
5620
+ const firstUrl = refs[0];
5621
+ const imageInput = { prompt: req.prompt };
5622
+ if (firstUrl !== void 0) {
5623
+ imageInput.image = firstUrl;
5624
+ imageInput.match_input_image = true;
5625
+ } else if (req.aspectRatio !== void 0 && QWEN_IMAGE_RATIOS.has(req.aspectRatio)) {
5626
+ imageInput.aspect_ratio = req.aspectRatio;
5627
+ }
5628
+ input = imageInput;
5629
+ break;
5412
5630
  }
5413
- const ratios = isQwenEditPlus(id) ? QWEN_EDIT_RATIOS : QWEN_IMAGE_RATIOS;
5414
- if (req.aspectRatio !== void 0) {
5415
- if (ratios.has(req.aspectRatio)) imageInput.aspect_ratio = req.aspectRatio;
5416
- else
5417
- ctx.warnings.push({
5418
- code: "option_ignored",
5419
- field: "aspectRatio",
5420
- from: req.aspectRatio,
5421
- message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
5422
- });
5631
+ case "qwen-edit": {
5632
+ const refs = (req.references ?? []).map(refToUrl);
5633
+ const firstUrl = refs[0];
5634
+ const imageInput = { prompt: req.prompt };
5635
+ if (firstUrl !== void 0) imageInput.image = firstUrl;
5636
+ if (req.aspectRatio !== void 0) {
5637
+ if (QWEN_EDIT_RATIOS.has(req.aspectRatio))
5638
+ imageInput.aspect_ratio = req.aspectRatio;
5639
+ else
5640
+ ctx.warnings.push({
5641
+ code: "option_ignored",
5642
+ field: "aspectRatio",
5643
+ from: req.aspectRatio,
5644
+ message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
5645
+ });
5646
+ }
5647
+ if (req.outputFormat !== void 0) {
5648
+ imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5649
+ }
5650
+ input = imageInput;
5651
+ break;
5423
5652
  }
5424
- if (isQwenEditPlus(id) && req.outputFormat !== void 0) {
5425
- imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
5653
+ default: {
5654
+ const first = (req.references ?? [])[0];
5655
+ const imageInput = { prompt: req.prompt };
5656
+ if (first) imageInput.image = refToUrl(first);
5657
+ input = imageInput;
5426
5658
  }
5427
- input = imageInput;
5428
- } else {
5429
- const refs = req.references ?? [];
5430
- const first = refs[0];
5431
- const imageInput = { prompt: req.prompt };
5432
- if (first) imageInput.image = refToUrl3(first);
5433
- input = imageInput;
5434
5659
  }
5435
5660
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
5436
5661
  const file = await download(ctx, url);
@@ -5447,8 +5672,8 @@ function wanSize(aspectRatio) {
5447
5672
  return w > h ? "2048*1152" : "1536*2048";
5448
5673
  }
5449
5674
  function klingInput(req) {
5450
- const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl3);
5451
- if (req.lastFrame) images.push(refToUrl3(req.lastFrame));
5675
+ const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
5676
+ if (req.lastFrame) images.push(refToUrl(req.lastFrame));
5452
5677
  const input = {
5453
5678
  prompt: req.prompt,
5454
5679
  duration: req.durationSeconds ?? 10,
@@ -5466,13 +5691,18 @@ function klingInput(req) {
5466
5691
  if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
5467
5692
  return input;
5468
5693
  }
5694
+ function klingOmniMode(req) {
5695
+ if (req.resolution === "1080p") return "pro";
5696
+ if (req.resolution === "720p") return "standard";
5697
+ return req.mode ?? "standard";
5698
+ }
5469
5699
  function klingOmniInput(req) {
5470
- const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl3);
5471
- if (req.lastFrame) images.push(refToUrl3(req.lastFrame));
5700
+ const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
5701
+ if (req.lastFrame) images.push(refToUrl(req.lastFrame));
5472
5702
  const input = {
5473
5703
  prompt: req.prompt,
5474
5704
  duration: req.durationSeconds ?? 10,
5475
- mode: req.mode ?? "standard",
5705
+ mode: klingOmniMode(req),
5476
5706
  generate_audio: req.generateAudio ?? false
5477
5707
  };
5478
5708
  const startImage = images[0];
@@ -5483,7 +5713,7 @@ function klingOmniInput(req) {
5483
5713
  } else if (req.aspectRatio !== "adaptive") {
5484
5714
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5485
5715
  }
5486
- const refs = (req.referenceImages ?? []).map(refToUrl3);
5716
+ const refs = (req.referenceImages ?? []).map(refToUrl);
5487
5717
  if (refs.length > 0) input.reference_images = refs;
5488
5718
  return input;
5489
5719
  }
@@ -5494,8 +5724,8 @@ function hailuoInput(req) {
5494
5724
  resolution: req.resolution ?? "768p",
5495
5725
  prompt_optimizer: true
5496
5726
  };
5497
- if (req.firstFrame) input.first_frame_image = refToUrl3(req.firstFrame);
5498
- if (req.lastFrame) input.last_frame_image = refToUrl3(req.lastFrame);
5727
+ if (req.firstFrame) input.first_frame_image = refToUrl(req.firstFrame);
5728
+ if (req.lastFrame) input.last_frame_image = refToUrl(req.lastFrame);
5499
5729
  return input;
5500
5730
  }
5501
5731
  function wanInput(req) {
@@ -5504,12 +5734,13 @@ function wanInput(req) {
5504
5734
  duration: req.durationSeconds ?? 5,
5505
5735
  size: wanSize(req.aspectRatio)
5506
5736
  };
5507
- if (req.firstFrame) input.image = refToUrl3(req.firstFrame);
5737
+ if (req.firstFrame) input.image = refToUrl(req.firstFrame);
5508
5738
  return input;
5509
5739
  }
5510
5740
  async function generateReplicateVideo(req, ctx, deps) {
5511
- const id = isLower(ctx.model.providerModelId);
5512
- const input = id.includes("kling") ? id.includes("omni") ? klingOmniInput(req) : klingInput(req) : id.includes("hailuo") ? hailuoInput(req) : wanInput(req);
5741
+ throwIfAborted(ctx.signal);
5742
+ const kind = videoKind(ctx.model.providerModelId);
5743
+ const input = kind === "kling" ? klingInput(req) : kind === "kling-omni" ? klingOmniInput(req) : kind === "hailuo" ? hailuoInput(req) : wanInput(req);
5513
5744
  const api = client(ctx, deps);
5514
5745
  const createOptions = { ...route(ctx.model.providerModelId), input };
5515
5746
  let prediction;
@@ -5517,12 +5748,14 @@ async function generateReplicateVideo(req, ctx, deps) {
5517
5748
  prediction = await withRetry(
5518
5749
  async () => {
5519
5750
  try {
5520
- return await api.predictions.create(createOptions);
5751
+ return await api.predictions.create(
5752
+ ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
5753
+ );
5521
5754
  } catch (cause) {
5522
5755
  throw replicateError(cause, ctx);
5523
5756
  }
5524
5757
  },
5525
- ctx.signal ? { signal: ctx.signal } : {}
5758
+ { attempts: 1 }
5526
5759
  );
5527
5760
  } catch (cause) {
5528
5761
  throw replicateError(cause, ctx);
@@ -5531,7 +5764,10 @@ async function generateReplicateVideo(req, ctx, deps) {
5531
5764
  const check = async () => {
5532
5765
  let current;
5533
5766
  try {
5534
- current = await api.predictions.get(jobId);
5767
+ current = await api.predictions.get(
5768
+ jobId,
5769
+ ctx.signal ? { signal: ctx.signal } : void 0
5770
+ );
5535
5771
  } catch (cause) {
5536
5772
  throw replicateError(cause, ctx);
5537
5773
  }
@@ -5632,7 +5868,7 @@ function mmaudioInput(req, ctx) {
5632
5868
  });
5633
5869
  }
5634
5870
  const input = {
5635
- video: refToUrl3(video),
5871
+ video: refToUrl(video),
5636
5872
  duration: req.durationSeconds ?? 8,
5637
5873
  seed: req.seed ?? -1
5638
5874
  };
@@ -5651,8 +5887,8 @@ function predictionRaw(prediction) {
5651
5887
  return raw;
5652
5888
  }
5653
5889
  async function generateReplicateAudio(req, ctx, deps) {
5654
- const id = isLower(ctx.model.providerModelId);
5655
- const input = id.includes("mmaudio") ? mmaudioInput(req, ctx) : id.includes("elevenlabs") ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
5890
+ const kind = audioKind(ctx.model.providerModelId);
5891
+ const input = kind === "mmaudio" ? mmaudioInput(req, ctx) : kind === "elevenlabs" ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
5656
5892
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
5657
5893
  const usage2 = audioUsage(ctx, req);
5658
5894
  if (ctx.model.usage.unit === "seconds") {
@@ -5681,10 +5917,6 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
5681
5917
  };
5682
5918
  }
5683
5919
  var xaiVideoAdapter = createXaiVideoAdapter();
5684
- function refToUrl4(ref) {
5685
- if ("url" in ref) return ref.url;
5686
- return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
5687
- }
5688
5920
  var xaiResponseStatusSchema = z13.object({
5689
5921
  response: z13.object({ status: z13.number() }).partial()
5690
5922
  });
@@ -5716,13 +5948,14 @@ async function generateXaiVideo(req, ctx, deps) {
5716
5948
  retryable: false
5717
5949
  });
5718
5950
  }
5719
- const refUrls = (req.referenceImages ?? []).map(refToUrl4).slice(0, 7);
5720
- const resolution = req.resolution === "480p" ? "480p" : "720p";
5951
+ const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
5721
5952
  const xaiOptions = {
5722
- resolution,
5723
5953
  pollIntervalMs: POLL_INTERVAL_MS2,
5724
5954
  pollTimeoutMs: POLL_TIMEOUT_MS2
5725
5955
  };
5956
+ if (req.resolution === "480p" || req.resolution === "720p" || req.resolution === "1080p") {
5957
+ xaiOptions.resolution = req.resolution;
5958
+ }
5726
5959
  if (refUrls.length > 0) {
5727
5960
  xaiOptions.mode = "reference-to-video";
5728
5961
  xaiOptions.referenceImageUrls = refUrls;
@@ -5742,7 +5975,7 @@ async function generateXaiVideo(req, ctx, deps) {
5742
5975
  providerOptions: { xai: xaiOptions }
5743
5976
  };
5744
5977
  if (req.firstFrame) {
5745
- callBody.frameImages = [{ image: refToUrl4(req.firstFrame), frameType: "first_frame" }];
5978
+ callBody.frameImages = [{ image: refToUrl(req.firstFrame), frameType: "first_frame" }];
5746
5979
  }
5747
5980
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5748
5981
  callBody.aspectRatio = req.aspectRatio;
@@ -5778,7 +6011,8 @@ async function generateXaiVideo(req, ctx, deps) {
5778
6011
  return settled;
5779
6012
  };
5780
6013
  return {
5781
- jobId: `${ctx.model.id}-grok`,
6014
+ // xAI exposes no request id on the synchronous handle, so each job gets a fresh one.
6015
+ jobId: crypto.randomUUID(),
5782
6016
  async poll() {
5783
6017
  if (failed !== void 0) return { status: "failed" };
5784
6018
  return settled ? { status: "succeeded" } : { status: "pending" };
@@ -5912,6 +6146,7 @@ export {
5912
6146
  prodiaAdapter,
5913
6147
  readErrorBody,
5914
6148
  replicateAdapter,
6149
+ resolveAudioOptions,
5915
6150
  resolveImageOptions,
5916
6151
  resolveKeys,
5917
6152
  resolveVideoOptions,