@shop-os/modelkit 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -93,7 +93,8 @@ var GEMINI_RATIOS = [
93
93
  "3:4",
94
94
  "21:9",
95
95
  "4:5",
96
- "5:4"
96
+ "5:4",
97
+ "adaptive"
97
98
  ];
98
99
  function geminiImage(id, label, aliases, sizes) {
99
100
  const model = {
@@ -104,7 +105,7 @@ function geminiImage(id, label, aliases, sizes) {
104
105
  adapter: "google-image",
105
106
  providerModelId: id,
106
107
  lifecycle: "active",
107
- constraints: { aspectRatios: [...GEMINI_RATIOS], sizes },
108
+ constraints: { aspectRatios: [...GEMINI_RATIOS], sizes, supports: ["safetySettings"] },
108
109
  defaults: { size: "1K", aspectRatio: "1:1" },
109
110
  usage: { ...IMAGE_USAGE },
110
111
  pricingKind: "image_size"
@@ -201,7 +202,8 @@ var IMAGE_MODELS = [
201
202
  "9:16",
202
203
  "4:5",
203
204
  "5:4",
204
- "9:21"
205
+ "9:21",
206
+ "adaptive"
205
207
  ],
206
208
  sizes: ["1K"],
207
209
  references: { images: 10 },
@@ -262,9 +264,10 @@ var IMAGE_MODELS = [
262
264
  constraints: {
263
265
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
264
266
  sizes: ["1K"],
265
- supports: ["outputFormat"]
267
+ // flux-2-pro's job type always returns image/png; only the seed is forwarded.
268
+ supports: ["seed"]
266
269
  },
267
- defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png" },
270
+ defaults: { size: "1K", aspectRatio: "1:1" },
268
271
  usage: { ...IMAGE_USAGE },
269
272
  pricingKind: "image_size"
270
273
  },
@@ -282,7 +285,8 @@ var IMAGE_MODELS = [
282
285
  constraints: {
283
286
  aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
284
287
  sizes: ["1K", "2K", "4K"],
285
- requires: ["references"]
288
+ requires: ["references"],
289
+ supports: ["seed"]
286
290
  },
287
291
  defaults: { size: "1K", aspectRatio: "1:1" },
288
292
  usage: { ...IMAGE_USAGE },
@@ -301,7 +305,8 @@ var IMAGE_MODELS = [
301
305
  constraints: {
302
306
  aspectRatios: ["1:1", "2:3", "3:4", "4:3", "9:16", "16:9", "21:9"],
303
307
  sizes: ["1K"],
304
- requires: ["references"]
308
+ requires: ["references"],
309
+ supports: ["seed"]
305
310
  },
306
311
  defaults: { size: "1K", aspectRatio: "1:1" },
307
312
  usage: { ...IMAGE_USAGE },
@@ -321,7 +326,8 @@ var IMAGE_MODELS = [
321
326
  constraints: {
322
327
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4"],
323
328
  sizes: ["1K", "2K", "4K"],
324
- references: { images: 9 }
329
+ references: { images: 9 },
330
+ supports: []
325
331
  },
326
332
  defaults: { size: "1K", aspectRatio: "1:1" },
327
333
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -342,7 +348,8 @@ var IMAGE_MODELS = [
342
348
  aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"],
343
349
  sizes: [],
344
350
  references: { images: 1 },
345
- requires: ["references"]
351
+ requires: ["references"],
352
+ supports: []
346
353
  },
347
354
  defaults: { aspectRatio: "1:1" },
348
355
  usage: { unit: "compute_seconds", modality: "IMAGE" },
@@ -384,7 +391,8 @@ var OTHER_MODELS = [
384
391
  lifecycle: "active",
385
392
  constraints: {
386
393
  durations: [30],
387
- references: { images: 10 }
394
+ references: { images: 10 },
395
+ supports: []
388
396
  },
389
397
  defaults: {},
390
398
  usage: { unit: "images", modality: "AUDIO" },
@@ -399,7 +407,8 @@ var OTHER_MODELS = [
399
407
  providerModelId: "lyria-3-pro-preview",
400
408
  lifecycle: "active",
401
409
  constraints: {
402
- references: { images: 10 }
410
+ references: { images: 10 },
411
+ supports: []
403
412
  },
404
413
  defaults: {},
405
414
  usage: { unit: "images", modality: "AUDIO" },
@@ -482,7 +491,8 @@ var OTHER_MODELS = [
482
491
  lifecycle: "active",
483
492
  constraints: {
484
493
  references: { images: 1 },
485
- requires: ["references"]
494
+ requires: ["references"],
495
+ supports: []
486
496
  },
487
497
  defaults: {},
488
498
  usage: { unit: "images", modality: "IMAGE" },
@@ -501,7 +511,7 @@ function text(id, label, providerModelId, extra) {
501
511
  adapter: "ai-sdk-text",
502
512
  providerModelId,
503
513
  lifecycle: "active",
504
- constraints: {},
514
+ constraints: { supports: [] },
505
515
  defaults: {},
506
516
  usage: { ...TEXT_USAGE },
507
517
  pricingKind: "token",
@@ -574,7 +584,7 @@ var TEXT_MODELS = [
574
584
  // src/catalog/video.ts
575
585
  var VIDEO_USAGE = { unit: "seconds", modality: "VIDEO" };
576
586
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
577
- var KLING_RATIOS = ["16:9", "9:16", "1:1"];
587
+ var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
578
588
  var OMNI_RATIOS = ["16:9", "9:16"];
579
589
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
580
590
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
@@ -666,12 +676,15 @@ var VIDEO_MODELS = [
666
676
  providerModelId: "gemini-omni-flash-preview",
667
677
  lifecycle: "active",
668
678
  constraints: {
679
+ // 1.0 rejects `resolution`; it renders 720p. No defaults: the adapter
680
+ // sends ratio and duration only when the caller set them, so a
681
+ // reference clip keeps its own framing.
669
682
  aspectRatios: [...OMNI_RATIOS],
670
- resolutions: ["720p"],
671
683
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
672
- references: { images: 6, videos: 1 }
684
+ references: { images: 6, videos: 1 },
685
+ supports: []
673
686
  },
674
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
687
+ defaults: {},
675
688
  usage: { ...VIDEO_USAGE },
676
689
  pricingKind: "video_per_second"
677
690
  },
@@ -687,9 +700,10 @@ var VIDEO_MODELS = [
687
700
  aspectRatios: [...OMNI_RATIOS],
688
701
  resolutions: ["360p", "720p", "1080p", "4k"],
689
702
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
690
- references: { images: 6, videos: 1 }
703
+ references: { images: 6, videos: 1 },
704
+ supports: []
691
705
  },
692
- defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
706
+ defaults: {},
693
707
  usage: { ...VIDEO_USAGE },
694
708
  pricingKind: "video_per_second"
695
709
  },
@@ -783,7 +797,8 @@ var VIDEO_MODELS = [
783
797
  aspectRatios: [...GROK_RATIOS],
784
798
  resolutions: ["480p", "720p"],
785
799
  durations: { min: 1, max: 15 },
786
- references: { images: 7 }
800
+ references: { images: 7 },
801
+ supports: []
787
802
  },
788
803
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
789
804
  usage: { unit: "reported_cost_usd", modality: "VIDEO" },
@@ -973,7 +988,8 @@ var VIDEO_MODELS = [
973
988
  constraints: {
974
989
  aspectRatios: [...KLING_RATIOS],
975
990
  durations: { min: 3, max: 10 },
976
- requires: ["sourceVideo"]
991
+ requires: ["sourceVideo"],
992
+ supports: []
977
993
  },
978
994
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
979
995
  usage: { ...VIDEO_USAGE },
@@ -1006,7 +1022,7 @@ var VIDEO_MODELS = [
1006
1022
  lifecycle: "active",
1007
1023
  constraints: {
1008
1024
  requires: ["firstFrame"],
1009
- supports: ["seed"]
1025
+ supports: ["seed", "lastFrame"]
1010
1026
  },
1011
1027
  defaults: {},
1012
1028
  usage: { ...VIDEO_USAGE },
@@ -1117,7 +1133,7 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1117
1133
  const warnings = [];
1118
1134
  const c = model.constraints;
1119
1135
  const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1120
- if (merged.aspectRatio && c.aspectRatios && !c.aspectRatios.includes(merged.aspectRatio)) {
1136
+ if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1121
1137
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1122
1138
  warnings.push({
1123
1139
  code: "ratio_coerced",
@@ -1160,7 +1176,8 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
1160
1176
  "quality",
1161
1177
  "count",
1162
1178
  "outputFormat",
1163
- "scaleFactor"
1179
+ "scaleFactor",
1180
+ "safetySettings"
1164
1181
  ]);
1165
1182
  return { request: merged, warnings };
1166
1183
  }
@@ -1190,7 +1207,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1190
1207
  delete merged.aspectRatio;
1191
1208
  }
1192
1209
  }
1193
- if (merged.aspectRatio && c.aspectRatios && !c.aspectRatios.includes(merged.aspectRatio)) {
1210
+ if (merged.aspectRatio !== void 0 && merged.aspectRatio !== "adaptive" && c.aspectRatios !== void 0 && !c.aspectRatios.includes(merged.aspectRatio)) {
1194
1211
  const to = nearestAspectRatio(merged.aspectRatio, c.aspectRatios);
1195
1212
  warnings.push({
1196
1213
  code: "ratio_coerced",
@@ -1272,8 +1289,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
1272
1289
  return { request: merged, warnings };
1273
1290
  }
1274
1291
  function dropUnsupported(req, model, warnings, fields) {
1275
- const supports = model.constraints.supports;
1276
- if (!supports) return;
1292
+ const supports = model.constraints.supports ?? [];
1277
1293
  for (const field of fields) {
1278
1294
  if (req[field] !== void 0 && !supports.includes(field)) {
1279
1295
  warnings.push({
@@ -1351,8 +1367,45 @@ function keysFromEnv(env, prefix = "") {
1351
1367
  }
1352
1368
 
1353
1369
  // src/retry.ts
1370
+ import { z as z2 } from "zod";
1371
+
1372
+ // src/json.ts
1354
1373
  import { z } from "zod";
1355
- var textBody = z.string();
1374
+ var JsonValueSchema = z.lazy(
1375
+ () => z.union([
1376
+ z.string(),
1377
+ z.number(),
1378
+ z.boolean(),
1379
+ z.null(),
1380
+ z.array(JsonValueSchema),
1381
+ z.record(z.string(), JsonValueSchema)
1382
+ ])
1383
+ );
1384
+ var JsonObjectSchema = z.record(z.string(), JsonValueSchema);
1385
+ async function readErrorBody(res) {
1386
+ const text2 = await res.text().catch(() => "");
1387
+ try {
1388
+ return JsonValueSchema.parse(JSON.parse(text2));
1389
+ } catch {
1390
+ return text2;
1391
+ }
1392
+ }
1393
+ var thrownErrorSchema = z.object({
1394
+ message: z.string().optional(),
1395
+ status: z.number().optional(),
1396
+ statusCode: z.number().optional(),
1397
+ responseBody: z.string().optional()
1398
+ });
1399
+ function describeThrown(cause) {
1400
+ const parsed = thrownErrorSchema.safeParse(cause);
1401
+ if (!parsed.success) return { message: String(cause), status: void 0, body: String(cause) };
1402
+ const { message, status, statusCode, responseBody } = parsed.data;
1403
+ const body = responseBody ?? message ?? String(cause);
1404
+ return { message: message ?? String(cause), status: status ?? statusCode, body };
1405
+ }
1406
+
1407
+ // src/retry.ts
1408
+ var textBody = z2.string();
1356
1409
  function classifyHttpError(status, body, provider, model) {
1357
1410
  const asText = textBody.safeParse(body);
1358
1411
  const text2 = asText.success ? asText.data : JSON.stringify(body);
@@ -1435,6 +1488,13 @@ function transportError(provider, cause, model) {
1435
1488
  if (model !== void 0) init.model = model;
1436
1489
  return new ModelKitError(init);
1437
1490
  }
1491
+ function classifyThrown(provider, cause, model, override = {}) {
1492
+ if (cause instanceof ModelKitError) return cause;
1493
+ const info = describeThrown(cause);
1494
+ const status = override.status ?? info.status;
1495
+ if (status === void 0) return transportError(provider, cause, model);
1496
+ return classifyHttpError(status, override.body ?? info.body, provider, model);
1497
+ }
1438
1498
  async function pollUntil(check, opts) {
1439
1499
  const start = Date.now();
1440
1500
  let interval = opts.intervalMs;
@@ -1557,7 +1617,7 @@ import {
1557
1617
  streamObject as aiStreamObject2,
1558
1618
  streamText as aiStreamText2
1559
1619
  } from "ai";
1560
- import { z as z3 } from "zod";
1620
+ import { z as z4 } from "zod";
1561
1621
 
1562
1622
  // src/adapters/media-ref.ts
1563
1623
  function isUrlRef(ref) {
@@ -1612,7 +1672,7 @@ import { createPerplexity } from "@ai-sdk/perplexity";
1612
1672
  import { createXai } from "@ai-sdk/xai";
1613
1673
  import { createDeepSeek } from "@ai-sdk/deepseek";
1614
1674
  import { createMoonshotAI } from "@ai-sdk/moonshotai";
1615
- import { z as z2 } from "zod";
1675
+ import { z as z3 } from "zod";
1616
1676
  var TEXT_PROVIDERS = [
1617
1677
  "openai",
1618
1678
  "anthropic",
@@ -1623,7 +1683,7 @@ var TEXT_PROVIDERS = [
1623
1683
  "moonshot",
1624
1684
  "minimax"
1625
1685
  ];
1626
- var textProviderSchema = z2.enum(TEXT_PROVIDERS);
1686
+ var textProviderSchema = z3.enum(TEXT_PROVIDERS);
1627
1687
  function isTextProvider(value) {
1628
1688
  return textProviderSchema.safeParse(value).success;
1629
1689
  }
@@ -1632,9 +1692,9 @@ var OPENAI_COMPATIBLE_BASE_URLS = {
1632
1692
  };
1633
1693
  var GATEWAY_SLUGS = {
1634
1694
  openai: "openai",
1635
- anthropic: "anthropic",
1695
+ anthropic: "anthropic/v1",
1636
1696
  google: "google-ai-studio/v1beta",
1637
- xai: "grok",
1697
+ xai: "grok/v1",
1638
1698
  perplexity: "perplexity-ai",
1639
1699
  deepseek: "deepseek"
1640
1700
  };
@@ -1809,10 +1869,10 @@ function textAbortOptions(sdk, context) {
1809
1869
  if (abortSignal) return { abortSignal };
1810
1870
  return {};
1811
1871
  }
1812
- var catalogId = z3.string();
1813
- var exactSize = z3.templateLiteral([z3.number(), "x", z3.number()]);
1814
- var sdkRatio = z3.templateLiteral([z3.number(), ":", z3.number()]);
1815
- var sizeTier = z3.enum(["1K", "2K", "4K"]);
1872
+ var catalogId = z4.string();
1873
+ var exactSize = z4.templateLiteral([z4.number(), "x", z4.number()]);
1874
+ var sdkRatio = z4.templateLiteral([z4.number(), ":", z4.number()]);
1875
+ var sizeTier = z4.enum(["512", "1K", "2K", "4K"]);
1816
1876
  function isCatalogId(model) {
1817
1877
  return catalogId.safeParse(model).success;
1818
1878
  }
@@ -1869,6 +1929,10 @@ function pushIgnored(warnings, field, from, modelId) {
1869
1929
  message: `${modelId} provider instance does not support ${field}; ignored`
1870
1930
  });
1871
1931
  }
1932
+ function logCoercions(logger, modelId, warnings) {
1933
+ if (warnings.length === 0) return;
1934
+ logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
1935
+ }
1872
1936
  function createModelKit(config, adapters) {
1873
1937
  const catalog = new Catalog(MODELS).withOverrides(config.catalogOverride ?? []);
1874
1938
  const logger = config.logger ?? console;
@@ -1902,6 +1966,10 @@ function createModelKit(config, adapters) {
1902
1966
  logger.warn("[modelkit] usage emit failed", err);
1903
1967
  }
1904
1968
  }
1969
+ function withRowUnit(event) {
1970
+ const row = catalog.get(event.model);
1971
+ return row ? { ...event, unit: row.usage.unit } : event;
1972
+ }
1905
1973
  function textTarget(model, call) {
1906
1974
  if (!isCatalogId(model)) {
1907
1975
  return {
@@ -1970,6 +2038,7 @@ function createModelKit(config, adapters) {
1970
2038
  pushIgnored(warnings, "outputFormat", _outputFormat, model.modelId);
1971
2039
  if (scaleFactor !== void 0)
1972
2040
  pushIgnored(warnings, "scaleFactor", scaleFactor, model.modelId);
2041
+ logCoercions(logger, model.modelId, warnings);
1973
2042
  const abortSignal = combineSignals(req.abortSignal, call.signal);
1974
2043
  if (abortSignal) options.abortSignal = abortSignal;
1975
2044
  const result = await aiGenerateImage(options);
@@ -2053,6 +2122,7 @@ function createModelKit(config, adapters) {
2053
2122
  if (_mode !== void 0) pushIgnored(warnings, "mode", _mode, model.modelId);
2054
2123
  if (providerOptions) options.providerOptions = providerOptions;
2055
2124
  if (abortSignal) options.abortSignal = abortSignal;
2125
+ logCoercions(logger, model.modelId, warnings);
2056
2126
  const pending = aiGenerateVideo(options);
2057
2127
  let settled;
2058
2128
  let failed = false;
@@ -2111,6 +2181,7 @@ function createModelKit(config, adapters) {
2111
2181
  call.onUnsupported ?? "error"
2112
2182
  );
2113
2183
  warnings.push(...inputWarnings);
2184
+ logCoercions(logger, model.id, warnings);
2114
2185
  const signal = combineSignals(req.abortSignal, call.signal);
2115
2186
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2116
2187
  if (!adapter.generateImage)
@@ -2120,7 +2191,7 @@ function createModelKit(config, adapters) {
2120
2191
  model: model.id
2121
2192
  });
2122
2193
  const result = await adapter.generateImage(request, ctx);
2123
- const usage2 = { ...result.usage, model: model.id };
2194
+ const usage2 = { ...result.usage, model: model.id, unit: model.usage.unit };
2124
2195
  await emit(usage2);
2125
2196
  const images = result.images.map(toGeneratedImage);
2126
2197
  const first = images[0];
@@ -2153,6 +2224,7 @@ function createModelKit(config, adapters) {
2153
2224
  call.onUnsupported ?? "error"
2154
2225
  );
2155
2226
  warnings.push(...inputWarnings);
2227
+ logCoercions(logger, model.id, warnings);
2156
2228
  const signal = combineSignals(req.abortSignal, call.signal);
2157
2229
  const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
2158
2230
  if (!adapter.generateVideo)
@@ -2170,7 +2242,11 @@ function createModelKit(config, adapters) {
2170
2242
  result(opts) {
2171
2243
  if (settled) return settled;
2172
2244
  const pending = result(opts).then(
2173
- (out) => emit({ ...out.usage, model: model.id }).then(() => out),
2245
+ (out) => emit({
2246
+ ...out.usage,
2247
+ model: model.id,
2248
+ unit: model.usage.unit
2249
+ }).then(() => out),
2174
2250
  (cause) => {
2175
2251
  settled = void 0;
2176
2252
  throw cause;
@@ -2190,7 +2266,8 @@ function createModelKit(config, adapters) {
2190
2266
  model: model.id
2191
2267
  });
2192
2268
  }
2193
- const { adapter, ctx } = context(model, call, []);
2269
+ const warnings = [];
2270
+ const { adapter, ctx } = context(model, call, warnings);
2194
2271
  if (!adapter.generateAudio) {
2195
2272
  throw new ModelKitError({
2196
2273
  code: "unsupported_option",
@@ -2202,7 +2279,8 @@ function createModelKit(config, adapters) {
2202
2279
  { ...model.defaults, ...req, model: model.id },
2203
2280
  ctx
2204
2281
  );
2205
- await emit({ ...result.usage, model: model.id });
2282
+ logCoercions(logger, model.id, warnings);
2283
+ await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
2206
2284
  return result;
2207
2285
  },
2208
2286
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
@@ -2242,7 +2320,7 @@ function createModelKit(config, adapters) {
2242
2320
  options.prepareStep ?? options.experimental_prepareStep
2243
2321
  )
2244
2322
  });
2245
- for (const event of steps.usage(result.steps)) await emit(event);
2323
+ for (const event of steps.usage(result.steps)) await emit(withRowUnit(event));
2246
2324
  return result;
2247
2325
  },
2248
2326
  streamText(options, call = {}) {
@@ -2260,7 +2338,7 @@ function createModelKit(config, adapters) {
2260
2338
  providerOptions: {},
2261
2339
  prepareStep: steps.wrap(options.prepareStep),
2262
2340
  onFinish: async (event) => {
2263
- for (const usage2 of steps.usage(event.steps)) await emit(usage2);
2341
+ for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
2264
2342
  await callerOnFinish?.(event);
2265
2343
  }
2266
2344
  });
@@ -2274,7 +2352,7 @@ function createModelKit(config, adapters) {
2274
2352
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions)
2275
2353
  };
2276
2354
  const result = await aiGenerateObject2(sdkOptions);
2277
- await emit(textUsageEvent(entry, provider, result.usage));
2355
+ await emit(withRowUnit(textUsageEvent(entry, provider, result.usage)));
2278
2356
  return result;
2279
2357
  },
2280
2358
  streamObject(options, call = {}) {
@@ -2286,7 +2364,7 @@ function createModelKit(config, adapters) {
2286
2364
  model: languageModel2,
2287
2365
  providerOptions: mergeTextProviderOptions(entry, options.providerOptions),
2288
2366
  onFinish: async (event) => {
2289
- await emit(textUsageEvent(entry, provider, event.usage));
2367
+ await emit(withRowUnit(textUsageEvent(entry, provider, event.usage)));
2290
2368
  await callerOnFinish?.(event);
2291
2369
  }
2292
2370
  };
@@ -2296,7 +2374,7 @@ function createModelKit(config, adapters) {
2296
2374
  }
2297
2375
 
2298
2376
  // src/adapters/ark.ts
2299
- import { z as z4 } from "zod";
2377
+ import { z as z5 } from "zod";
2300
2378
  var ARK_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
2301
2379
  var SUBMIT_PATH = "/contents/generations/tasks";
2302
2380
  var SEEDANCE_POLL_INTERVAL_MS = 15e3;
@@ -2354,7 +2432,7 @@ function arkKey(ctx) {
2354
2432
  return key;
2355
2433
  }
2356
2434
  function throwArkError(status, body, model) {
2357
- const parsed = z4.string().safeParse(body);
2435
+ const parsed = z5.string().safeParse(body);
2358
2436
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2359
2437
  if (/sensitive.?content|inputimage|human.?face/i.test(text2)) {
2360
2438
  const init = {
@@ -2368,6 +2446,16 @@ function throwArkError(status, body, model) {
2368
2446
  if (status !== void 0) init.status = status;
2369
2447
  throw new ModelKitError(init);
2370
2448
  }
2449
+ if (status === void 0) {
2450
+ throw new ModelKitError({
2451
+ code: "provider_rejected",
2452
+ message: `ark rejected the request: ${text2.slice(0, 500)}`,
2453
+ provider: "ark",
2454
+ model,
2455
+ body,
2456
+ retryable: false
2457
+ });
2458
+ }
2371
2459
  throw classifyHttpError(status, body, "ark", model);
2372
2460
  }
2373
2461
  function seedreamSize(aspect, size) {
@@ -2386,13 +2474,13 @@ function arkUrl(ref) {
2386
2474
  if ("url" in ref) return ref.url;
2387
2475
  return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
2388
2476
  }
2389
- var SeedreamImageSchema = z4.object({
2390
- url: z4.string().optional(),
2391
- b64_json: z4.string().optional()
2477
+ var SeedreamImageSchema = z5.object({
2478
+ url: z5.string().optional(),
2479
+ b64_json: z5.string().optional()
2392
2480
  });
2393
- var SeedreamResponseSchema = z4.object({
2394
- data: z4.array(SeedreamImageSchema).optional(),
2395
- error: z4.object({ message: z4.string().optional(), code: z4.string().optional() }).optional()
2481
+ var SeedreamResponseSchema = z5.object({
2482
+ data: z5.array(SeedreamImageSchema).optional(),
2483
+ error: z5.object({ message: z5.string().optional(), code: z5.string().optional() }).optional()
2396
2484
  });
2397
2485
  function retryOptsFor(ctx, attempts = 3) {
2398
2486
  const opts = { attempts };
@@ -2403,6 +2491,11 @@ function fetchInitFor(ctx, init) {
2403
2491
  if (ctx.signal !== void 0) init.signal = ctx.signal;
2404
2492
  return init;
2405
2493
  }
2494
+ function arkFetch(ctx, url, init) {
2495
+ return ctx.fetch(url, fetchInitFor(ctx, init)).catch((cause) => {
2496
+ throw classifyThrown("ark", cause, ctx.model.id);
2497
+ });
2498
+ }
2406
2499
  async function generateSeedreamImage(req, ctx) {
2407
2500
  const key = arkKey(ctx);
2408
2501
  const modelId = ctx.model.id;
@@ -2420,14 +2513,11 @@ async function generateSeedreamImage(req, ctx) {
2420
2513
  if (refs.length === 1 && firstRef !== void 0) body.image = firstRef;
2421
2514
  else if (refs.length > 1) body.image = refs;
2422
2515
  const data = await withRetry(async () => {
2423
- const res = await ctx.fetch(
2424
- `${arkBaseUrl(ctx)}/images/generations`,
2425
- fetchInitFor(ctx, {
2426
- method: "POST",
2427
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2428
- body: JSON.stringify(body)
2429
- })
2430
- );
2516
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}/images/generations`, {
2517
+ method: "POST",
2518
+ headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2519
+ body: JSON.stringify(body)
2520
+ });
2431
2521
  if (!res.ok) {
2432
2522
  const text2 = await res.text().catch(() => "");
2433
2523
  throwArkError(res.status, text2, modelId);
@@ -2442,7 +2532,7 @@ async function generateSeedreamImage(req, ctx) {
2442
2532
  bytes = Buffer.from(first.b64_json, "base64");
2443
2533
  } else if (first?.url) {
2444
2534
  const imageUrl = first.url;
2445
- const res = await ctx.fetch(imageUrl, fetchInitFor(ctx, {}));
2535
+ const res = await arkFetch(ctx, imageUrl, {});
2446
2536
  if (!res.ok) {
2447
2537
  const text2 = await res.text().catch(() => "");
2448
2538
  throwArkError(res.status, text2, modelId);
@@ -2462,13 +2552,13 @@ async function generateSeedreamImage(req, ctx) {
2462
2552
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
2463
2553
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
2464
2554
  }
2465
- var SeedanceResponseSchema = z4.object({
2466
- id: z4.string().optional(),
2467
- status: z4.string().optional(),
2468
- content: z4.object({ video_url: z4.string().optional() }).optional(),
2469
- error: z4.union([z4.string(), z4.object({ message: z4.string().optional() })]).optional()
2555
+ var SeedanceResponseSchema = z5.object({
2556
+ id: z5.string().optional(),
2557
+ status: z5.string().optional(),
2558
+ content: z5.object({ video_url: z5.string().optional() }).optional(),
2559
+ error: z5.union([z5.string(), z5.object({ message: z5.string().optional() })]).optional()
2470
2560
  });
2471
- var SeedanceErrorMessageSchema = z4.object({ message: z4.string().optional() });
2561
+ var SeedanceErrorMessageSchema = z5.object({ message: z5.string().optional() });
2472
2562
  function seedanceUsage(ctx, req, duration) {
2473
2563
  const usage2 = {
2474
2564
  model: ctx.model.id,
@@ -2482,7 +2572,7 @@ function seedanceUsage(ctx, req, duration) {
2482
2572
  return usage2;
2483
2573
  }
2484
2574
  function seedanceErrorMessage(error, status) {
2485
- const asString = z4.string().safeParse(error);
2575
+ const asString = z5.string().safeParse(error);
2486
2576
  if (asString.success) return asString.data;
2487
2577
  const asObject = SeedanceErrorMessageSchema.safeParse(error);
2488
2578
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
@@ -2547,14 +2637,11 @@ async function generateSeedanceVideo(req, ctx) {
2547
2637
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
2548
2638
  if (req.seed !== void 0) body.seed = req.seed;
2549
2639
  const submit = await withRetry(async () => {
2550
- const res = await ctx.fetch(
2551
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}`,
2552
- fetchInitFor(ctx, {
2553
- method: "POST",
2554
- headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2555
- body: JSON.stringify(body)
2556
- })
2557
- );
2640
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
2641
+ method: "POST",
2642
+ headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
2643
+ body: JSON.stringify(body)
2644
+ });
2558
2645
  if (!res.ok) {
2559
2646
  const text2 = await res.text().catch(() => "");
2560
2647
  throwArkError(res.status, text2, modelId);
@@ -2567,12 +2654,9 @@ async function generateSeedanceVideo(req, ctx) {
2567
2654
  const jobId = submit.id;
2568
2655
  const usage2 = seedanceUsage(ctx, req, duration);
2569
2656
  const fetchStatus = async () => {
2570
- const res = await ctx.fetch(
2571
- `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`,
2572
- fetchInitFor(ctx, {
2573
- headers: { Authorization: `Bearer ${key}` }
2574
- })
2575
- );
2657
+ const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
2658
+ headers: { Authorization: `Bearer ${key}` }
2659
+ });
2576
2660
  if (!res.ok) {
2577
2661
  if (res.status === 429 || res.status >= 500) return void 0;
2578
2662
  const text2 = await res.text().catch(() => "");
@@ -2633,43 +2717,6 @@ async function generateSeedanceVideo(req, ctx) {
2633
2717
  // src/adapters/fal.ts
2634
2718
  import { z as z6 } from "zod";
2635
2719
  import { createFalClient } from "@fal-ai/client";
2636
-
2637
- // src/json.ts
2638
- import { z as z5 } from "zod";
2639
- var JsonValueSchema = z5.lazy(
2640
- () => z5.union([
2641
- z5.string(),
2642
- z5.number(),
2643
- z5.boolean(),
2644
- z5.null(),
2645
- z5.array(JsonValueSchema),
2646
- z5.record(z5.string(), JsonValueSchema)
2647
- ])
2648
- );
2649
- var JsonObjectSchema = z5.record(z5.string(), JsonValueSchema);
2650
- async function readErrorBody(res) {
2651
- const text2 = await res.text().catch(() => "");
2652
- try {
2653
- return JsonValueSchema.parse(JSON.parse(text2));
2654
- } catch {
2655
- return text2;
2656
- }
2657
- }
2658
- var thrownErrorSchema = z5.object({
2659
- message: z5.string().optional(),
2660
- status: z5.number().optional(),
2661
- statusCode: z5.number().optional(),
2662
- responseBody: z5.string().optional()
2663
- });
2664
- function describeThrown(cause) {
2665
- const parsed = thrownErrorSchema.safeParse(cause);
2666
- if (!parsed.success) return { message: String(cause), status: void 0, body: String(cause) };
2667
- const { message, status, statusCode, responseBody } = parsed.data;
2668
- const body = responseBody ?? message ?? String(cause);
2669
- return { message: message ?? String(cause), status: status ?? statusCode, body };
2670
- }
2671
-
2672
- // src/adapters/fal.ts
2673
2720
  var MUSE_T2I_ENDPOINT = "meta/muse-image/text-to-image";
2674
2721
  var MUSE_EDIT_ENDPOINT = "meta/muse-image/edit";
2675
2722
  var KLING_O1_ENDPOINT = "fal-ai/kling-video/o1/video-to-video/reference";
@@ -2681,10 +2728,33 @@ function defaultCreateFalClient(opts) {
2681
2728
  const client2 = createFalClient(opts);
2682
2729
  return {
2683
2730
  async subscribe(endpoint, options) {
2684
- const outcome = await client2.subscribe(endpoint, { input: options.input });
2731
+ const outcome = await client2.subscribe(endpoint, options);
2685
2732
  const unwrapped = falSubscribePayloadSchema.safeParse(outcome);
2686
2733
  if (unwrapped.success) return unwrapped.data.data;
2687
2734
  return JsonValueSchema.parse(outcome);
2735
+ },
2736
+ queue: {
2737
+ async submit(endpoint, options) {
2738
+ const submitted = await client2.queue.submit(endpoint, {
2739
+ input: options.input,
2740
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2741
+ });
2742
+ return { requestId: submitted.request_id };
2743
+ },
2744
+ async status(endpoint, options) {
2745
+ const current = await client2.queue.status(endpoint, {
2746
+ requestId: options.requestId,
2747
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2748
+ });
2749
+ return { status: current.status };
2750
+ },
2751
+ async result(endpoint, options) {
2752
+ const outcome = await client2.queue.result(endpoint, {
2753
+ requestId: options.requestId,
2754
+ ...options.abortSignal !== void 0 ? { abortSignal: options.abortSignal } : {}
2755
+ });
2756
+ return JsonValueSchema.parse(outcome.data);
2757
+ }
2688
2758
  }
2689
2759
  };
2690
2760
  }
@@ -2726,15 +2796,17 @@ var falSdkThrownSchema = z6.object({
2726
2796
  message: z6.string().optional()
2727
2797
  });
2728
2798
  function falSdkError(cause, model) {
2729
- if (isModelKitError(cause)) return cause;
2730
2799
  const parsed = falSdkThrownSchema.safeParse(cause);
2731
2800
  if (parsed.success) {
2732
2801
  const status = parsed.data.status ?? parsed.data.statusCode;
2733
2802
  const body = parsed.data.body ?? parsed.data.message ?? String(cause);
2734
- return falError(status, body, model);
2803
+ return classifyThrown("fal", cause, model, { status, body: liftDetail(body) });
2735
2804
  }
2736
2805
  const info = describeThrown(cause);
2737
- return falError(info.status, info.body, model);
2806
+ return classifyThrown("fal", cause, model, {
2807
+ status: info.status,
2808
+ body: liftDetail(info.body)
2809
+ });
2738
2810
  }
2739
2811
  function gatewayConfig(ctx) {
2740
2812
  const cf = ctx.routing.cloudflare;
@@ -2816,7 +2888,7 @@ async function passthroughRequest(ctx, endpoint, input) {
2816
2888
  }
2817
2889
  return JsonValueSchema.parse(await resultRes.json());
2818
2890
  }
2819
- async function subscribe(ctx, deps, endpoint, input) {
2891
+ function falClientOf(ctx, deps) {
2820
2892
  const falKey = ctx.keys.fal;
2821
2893
  if (!falKey) {
2822
2894
  throw new ModelKitError({
@@ -2827,12 +2899,19 @@ async function subscribe(ctx, deps, endpoint, input) {
2827
2899
  retryable: false
2828
2900
  });
2829
2901
  }
2830
- const client2 = deps.createFalClient({ credentials: falKey });
2902
+ return deps.createFalClient({ credentials: falKey, fetch: ctx.fetch });
2903
+ }
2904
+ async function subscribe(ctx, deps, endpoint, input) {
2905
+ const client2 = falClientOf(ctx, deps);
2906
+ const options = {
2907
+ input,
2908
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
2909
+ };
2831
2910
  try {
2832
2911
  return await withRetry(
2833
2912
  async () => {
2834
2913
  try {
2835
- return await client2.subscribe(endpoint, { input });
2914
+ return await client2.subscribe(endpoint, options);
2836
2915
  } catch (cause) {
2837
2916
  throw falSdkError(cause, ctx.model.id);
2838
2917
  }
@@ -2966,13 +3045,14 @@ function klingO1Input(req) {
2966
3045
  });
2967
3046
  }
2968
3047
  const duration = Math.min(10, Math.max(3, Math.round(req.durationSeconds ?? 5)));
2969
- const ratio = req.aspectRatio === "16:9" || req.aspectRatio === "9:16" || req.aspectRatio === "1:1" ? req.aspectRatio : "auto";
2970
3048
  const input = {
2971
3049
  prompt: req.prompt,
2972
3050
  video_url: source,
2973
- duration: String(duration),
2974
- aspect_ratio: ratio
3051
+ duration: String(duration)
2975
3052
  };
3053
+ if (req.aspectRatio !== "adaptive") {
3054
+ input.aspect_ratio = req.aspectRatio === "16:9" || req.aspectRatio === "9:16" || req.aspectRatio === "1:1" ? req.aspectRatio : "auto";
3055
+ }
2976
3056
  const refs = (req.referenceImages ?? []).map(refToUrl);
2977
3057
  if (refs.length > 0) input.image_urls = refs;
2978
3058
  return input;
@@ -3001,13 +3081,7 @@ async function generateFalVideo(req, ctx, deps) {
3001
3081
  if (ctx.routing.fal === "cloudflare-passthrough") {
3002
3082
  return await passthroughVideoJob(ctx, req, KLING_O1_ENDPOINT, input);
3003
3083
  }
3004
- const result2 = await runJob(ctx, deps, KLING_O1_ENDPOINT, input);
3005
- return completedVideoJob(
3006
- ctx,
3007
- req,
3008
- extractVideoUrl(result2, KLING_O1_ENDPOINT, ctx.model.id),
3009
- result2
3010
- );
3084
+ return await submitQueueJob(ctx, req, deps, KLING_O1_ENDPOINT, input);
3011
3085
  }
3012
3086
  const family = minimaxFamily(providerModelId);
3013
3087
  const refs = {
@@ -3036,19 +3110,81 @@ async function generateFalVideo(req, ctx, deps) {
3036
3110
  if (ctx.routing.fal === "cloudflare-passthrough") {
3037
3111
  return await passthroughVideoJob(ctx, req, endpoint, base);
3038
3112
  }
3039
- const result = await runJob(ctx, deps, endpoint, base);
3040
- return completedVideoJob(ctx, req, extractVideoUrl(result, endpoint, ctx.model.id), result);
3113
+ return await submitQueueJob(ctx, req, deps, endpoint, base);
3041
3114
  }
3042
- function completedVideoJob(ctx, req, url, raw) {
3115
+ async function submitQueueJob(ctx, req, deps, endpoint, input) {
3116
+ const client2 = falClientOf(ctx, deps);
3117
+ let submitted;
3118
+ try {
3119
+ submitted = await withRetry(
3120
+ async () => {
3121
+ try {
3122
+ return await client2.queue.submit(endpoint, {
3123
+ input,
3124
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
3125
+ });
3126
+ } catch (cause) {
3127
+ throw falSdkError(cause, ctx.model.id);
3128
+ }
3129
+ },
3130
+ ctx.signal !== void 0 ? { signal: ctx.signal } : {}
3131
+ );
3132
+ } catch (cause) {
3133
+ throw falSdkError(cause, ctx.model.id);
3134
+ }
3135
+ return queuedVideoJob(ctx, req, client2, endpoint, submitted.requestId);
3136
+ }
3137
+ function queuedVideoJob(ctx, req, client2, endpoint, requestId) {
3138
+ const readStatus = async () => {
3139
+ try {
3140
+ const options = {
3141
+ requestId,
3142
+ ...ctx.signal !== void 0 ? { abortSignal: ctx.signal } : {}
3143
+ };
3144
+ return (await client2.queue.status(endpoint, options)).status;
3145
+ } catch (cause) {
3146
+ throw falSdkError(cause, ctx.model.id);
3147
+ }
3148
+ };
3043
3149
  const duration = req.durationSeconds ?? 5;
3044
- const result = { video: { url }, usage: videoUsage(ctx, req, duration), raw };
3045
3150
  return {
3046
- jobId: url,
3151
+ jobId: requestId,
3047
3152
  async poll() {
3048
- return { status: "succeeded", raw };
3153
+ try {
3154
+ const status = await readStatus();
3155
+ if (status === "COMPLETED") return { status: "succeeded" };
3156
+ if (status === "IN_QUEUE") return { status: "pending" };
3157
+ return { status: "running" };
3158
+ } catch (cause) {
3159
+ if (isModelKitError(cause) && !cause.retryable)
3160
+ return { status: "failed" };
3161
+ return { status: "pending" };
3162
+ }
3049
3163
  },
3050
- async result() {
3051
- return result;
3164
+ async result(opts) {
3165
+ const signal = opts?.signal ?? ctx.signal;
3166
+ const pollOptions = {
3167
+ intervalMs: opts?.pollIntervalMs ?? PASSTHROUGH_POLL_MS,
3168
+ timeoutMs: opts?.timeoutMs ?? 15 * 6e4
3169
+ };
3170
+ if (signal !== void 0) pollOptions.signal = signal;
3171
+ const queueOptions = {
3172
+ requestId,
3173
+ ...signal !== void 0 ? { abortSignal: signal } : {}
3174
+ };
3175
+ const payload = await pollUntil(async () => {
3176
+ try {
3177
+ const current = await client2.queue.status(endpoint, queueOptions);
3178
+ if (current.status !== "COMPLETED") return void 0;
3179
+ return await client2.queue.result(endpoint, queueOptions);
3180
+ } catch (cause) {
3181
+ const err = falSdkError(cause, ctx.model.id);
3182
+ if (err.retryable) return void 0;
3183
+ throw err;
3184
+ }
3185
+ }, pollOptions);
3186
+ const url = extractVideoUrl(payload, endpoint, ctx.model.id);
3187
+ return { video: { url }, usage: videoUsage(ctx, req, duration), raw: payload };
3052
3188
  }
3053
3189
  };
3054
3190
  }
@@ -3401,9 +3537,7 @@ function sdkStatus(cause) {
3401
3537
  return describeThrown(cause).status;
3402
3538
  }
3403
3539
  function throwSdkError(cause, model) {
3404
- if (cause instanceof ModelKitError) throw cause;
3405
- const info = describeThrown(cause);
3406
- throw classifyHttpError(info.status, info.body, "google-genai", model);
3540
+ throw classifyThrown("google-genai", cause, model);
3407
3541
  }
3408
3542
  function toBase64(bytes) {
3409
3543
  return Buffer.from(bytes).toString("base64");
@@ -3607,12 +3741,17 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3607
3741
  const duration = req.durationSeconds ?? 8;
3608
3742
  const images = req.referenceImages ?? [];
3609
3743
  const videos = req.referenceVideos ?? [];
3610
- const task = req.sourceVideo ? "edit" : videos.length > 0 || images.length > 1 ? "reference_to_video" : req.firstFrame || images.length === 1 ? "image_to_video" : "text_to_video";
3611
- const responseFormat = { type: "video" };
3612
- if (req.sourceVideo === void 0) responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
3613
- const omniResolution = toOmniResolution(req.resolution);
3614
- if (omniResolution !== void 0) responseFormat.resolution = omniResolution;
3615
- responseFormat.duration = `${duration}s`;
3744
+ const task = req.sourceVideo ? "edit" : req.firstFrame ? "image_to_video" : images.length > 0 || videos.length > 0 ? "reference_to_video" : "text_to_video";
3745
+ const isOmniV1 = providerModelId === "gemini-omni-flash-preview";
3746
+ const responseFormat = { type: "video", delivery: "uri" };
3747
+ if (req.sourceVideo === void 0 && req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
3748
+ responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
3749
+ }
3750
+ if (!isOmniV1) {
3751
+ const omniResolution = toOmniResolution(req.resolution);
3752
+ if (omniResolution !== void 0) responseFormat.resolution = omniResolution;
3753
+ }
3754
+ if (req.durationSeconds !== void 0) responseFormat.duration = `${req.durationSeconds}s`;
3616
3755
  const client2 = createGenAIClient({ apiKey });
3617
3756
  const uploadedByUri = /* @__PURE__ */ new Map();
3618
3757
  const uploadedNames = [];
@@ -3636,7 +3775,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3636
3775
  model: providerModelId,
3637
3776
  input,
3638
3777
  response_format: responseFormat,
3639
- generation_config: { video_config: { task } }
3778
+ generation_config: { video_config: { task } },
3779
+ store: true
3640
3780
  });
3641
3781
  const createRetryOptions = { attempts: 3 };
3642
3782
  if (ctx.signal !== void 0) createRetryOptions.signal = ctx.signal;
@@ -3718,23 +3858,14 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3718
3858
  };
3719
3859
  return inline;
3720
3860
  });
3721
- const inlineRetryOptions = { attempts: 3 };
3722
- if (ctx.signal !== void 0) inlineRetryOptions.signal = ctx.signal;
3723
3861
  try {
3724
- interaction = await withRetry(async () => {
3725
- try {
3726
- return await callCreate(inlineParts);
3727
- } catch (inlineCause) {
3728
- throwSdkError(inlineCause, modelId);
3729
- }
3730
- }, inlineRetryOptions);
3862
+ interaction = await callCreate(inlineParts);
3731
3863
  } catch (inlineCause) {
3732
3864
  throwSdkError(inlineCause, modelId);
3733
3865
  }
3734
3866
  }
3735
- } catch (cause) {
3867
+ } finally {
3736
3868
  await cleanupUploads();
3737
- throw cause;
3738
3869
  }
3739
3870
  const jobId = interaction.id ?? "gemini-omni-interaction";
3740
3871
  const usage2 = videoUsage2(ctx, req, duration);
@@ -3763,47 +3894,43 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
3763
3894
  timeoutMs: opts?.timeoutMs ?? RESULT_TIMEOUT_MS2
3764
3895
  };
3765
3896
  if (signal !== void 0) pollOptions.signal = signal;
3766
- try {
3767
- const done = await pollUntil(async () => {
3768
- const current = await getInteraction();
3769
- const status = (current.status ?? "").toUpperCase();
3770
- if (status === "COMPLETED") return current;
3771
- if (status === "FAILED") {
3772
- throw classifyHttpError(
3773
- void 0,
3774
- `Gemini Omni interaction failed: ${JSON.stringify(current).slice(0, 500)}`,
3775
- "google-genai",
3776
- modelId
3777
- );
3778
- }
3779
- return void 0;
3780
- }, pollOptions);
3781
- const video = extractOmniVideo(done, modelId);
3782
- if (video.data) {
3783
- return {
3784
- video: {
3785
- bytes: Buffer.from(video.data, "base64"),
3786
- mime: video.mime_type ?? "video/mp4"
3787
- },
3788
- usage: usage2,
3789
- raw: done
3790
- };
3897
+ const done = await pollUntil(async () => {
3898
+ const current = await getInteraction();
3899
+ const status = (current.status ?? "").toUpperCase();
3900
+ if (status === "COMPLETED") return current;
3901
+ if (status === "FAILED") {
3902
+ throw classifyHttpError(
3903
+ void 0,
3904
+ `Gemini Omni interaction failed: ${JSON.stringify(current).slice(0, 500)}`,
3905
+ "google-genai",
3906
+ modelId
3907
+ );
3791
3908
  }
3792
- if (video.uri)
3793
- return {
3794
- video: await downloadVideo(ctx, video.uri, apiKey, signal),
3795
- usage: usage2,
3796
- raw: done
3797
- };
3798
- throw classifyHttpError(
3799
- void 0,
3800
- "No video content in Gemini Omni response",
3801
- "google-genai",
3802
- modelId
3803
- );
3804
- } finally {
3805
- await cleanupUploads();
3909
+ return void 0;
3910
+ }, pollOptions);
3911
+ const video = extractOmniVideo(done, modelId);
3912
+ if (video.data) {
3913
+ return {
3914
+ video: {
3915
+ bytes: Buffer.from(video.data, "base64"),
3916
+ mime: video.mime_type ?? "video/mp4"
3917
+ },
3918
+ usage: usage2,
3919
+ raw: done
3920
+ };
3806
3921
  }
3922
+ if (video.uri)
3923
+ return {
3924
+ video: await downloadVideo(ctx, video.uri, apiKey, signal),
3925
+ usage: usage2,
3926
+ raw: done
3927
+ };
3928
+ throw classifyHttpError(
3929
+ void 0,
3930
+ "No video content in Gemini Omni response",
3931
+ "google-genai",
3932
+ modelId
3933
+ );
3807
3934
  }
3808
3935
  };
3809
3936
  }
@@ -3972,8 +4099,14 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
3972
4099
  content.push({ type: "text", text: req.prompt });
3973
4100
  void ctx.call.postCropToAspect;
3974
4101
  const imageConfig = {};
3975
- if (req.aspectRatio !== void 0) imageConfig.aspectRatio = req.aspectRatio;
4102
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4103
+ imageConfig.aspectRatio = req.aspectRatio;
3976
4104
  if (req.size !== void 0) imageConfig.imageSize = req.size;
4105
+ const googleOptions = {
4106
+ imageConfig,
4107
+ responseModalities: ["IMAGE"]
4108
+ };
4109
+ if (req.safetySettings !== void 0) googleOptions.safetySettings = req.safetySettings;
3977
4110
  const retryOptions = {};
3978
4111
  if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
3979
4112
  const result = await withRetry(async () => {
@@ -3985,22 +4118,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
3985
4118
  messages: [{ role: "user", content }],
3986
4119
  maxRetries: 0,
3987
4120
  providerOptions: {
3988
- google: {
3989
- imageConfig,
3990
- responseModalities: ["IMAGE"],
3991
- safetySettings: [
3992
- {
3993
- category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
3994
- threshold: "OFF"
3995
- },
3996
- { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "OFF" },
3997
- {
3998
- category: "HARM_CATEGORY_DANGEROUS_CONTENT",
3999
- threshold: "OFF"
4000
- },
4001
- { category: "HARM_CATEGORY_HARASSMENT", threshold: "OFF" }
4002
- ]
4003
- }
4121
+ google: googleOptions
4004
4122
  },
4005
4123
  abortSignal: signal
4006
4124
  });
@@ -4187,6 +4305,7 @@ var KLING_MAX_INTERVAL_MS = 1e4;
4187
4305
  var KLING_TIMEOUT_MS = 15 * 6e4;
4188
4306
  var DOP_INTERVAL_MS = 5e3;
4189
4307
  var DOP_TIMEOUT_MS = 5 * 6e4;
4308
+ var DOP_FALLBACK_DURATION_SECONDS = 5;
4190
4309
  var DEFAULT_NEGATIVE_PROMPT = "text, watermark, copyright, blur, low quality, distortion, abstract, weird, deformed";
4191
4310
  function credentials(ctx) {
4192
4311
  const key = ctx.keys.higgsfield;
@@ -4261,6 +4380,18 @@ function requestInit(ctx, init) {
4261
4380
  if (ctx.signal !== void 0) request.signal = ctx.signal;
4262
4381
  return request;
4263
4382
  }
4383
+ async function createRequest(ctx, url, init) {
4384
+ let res;
4385
+ try {
4386
+ res = await ctx.fetch(url, requestInit(ctx, init));
4387
+ } catch (cause) {
4388
+ throw classifyThrown("higgsfield", cause, ctx.model.id);
4389
+ }
4390
+ if (!res.ok) {
4391
+ throw classifyHttpError(res.status, await readBody2(res), "higgsfield", ctx.model.id);
4392
+ }
4393
+ return res;
4394
+ }
4264
4395
  async function generateKlingVideo(req, ctx) {
4265
4396
  const firstFrame = req.firstFrame ? refToUrl2(req.firstFrame) : void 0;
4266
4397
  if (!firstFrame) {
@@ -4279,26 +4410,16 @@ async function generateKlingVideo(req, ctx) {
4279
4410
  negative_prompt: req.negativePrompt ?? DEFAULT_NEGATIVE_PROMPT
4280
4411
  };
4281
4412
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
4282
- if (req.aspectRatio !== void 0) body.aspect_ratio = req.aspectRatio;
4413
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
4414
+ body.aspect_ratio = req.aspectRatio;
4283
4415
  if (req.lastFrame) body.last_image_url = refToUrl2(req.lastFrame);
4284
4416
  const endpoint = klingEndpoint(ctx.model.providerModelId);
4285
- let createRes;
4286
- try {
4287
- createRes = await ctx.fetch(
4288
- endpoint,
4289
- requestInit(ctx, { method: "POST", body: JSON.stringify(body) })
4290
- );
4291
- } catch (cause) {
4292
- throw networkError(cause, ctx);
4293
- }
4294
- if (!createRes.ok) {
4295
- throw classifyHttpError(
4296
- createRes.status,
4297
- await readBody2(createRes),
4298
- "higgsfield",
4299
- ctx.model.id
4300
- );
4301
- }
4417
+ const retryOptions = {};
4418
+ if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4419
+ const createRes = await withRetry(
4420
+ () => createRequest(ctx, endpoint, { method: "POST", body: JSON.stringify(body) }),
4421
+ retryOptions
4422
+ );
4302
4423
  const created = klingCreateSchema.safeParse(await createRes.json());
4303
4424
  if (!created.success) {
4304
4425
  throw new ModelKitError({
@@ -4378,11 +4499,6 @@ async function generateKlingVideo(req, ctx) {
4378
4499
  }
4379
4500
  };
4380
4501
  }
4381
- function networkError(cause, ctx) {
4382
- if (isModelKitError(cause)) return cause;
4383
- const info = describeThrown(cause);
4384
- return classifyHttpError(info.status, info.body, "higgsfield", ctx.model.id);
4385
- }
4386
4502
  var dopMotionOptionsSchema = z10.object({
4387
4503
  modelkit: z10.object({ motion: z10.string().optional() }).optional()
4388
4504
  });
@@ -4454,26 +4570,15 @@ async function generateDopVideo(req, ctx) {
4454
4570
  params.input_images_end = [{ type: "image_url", image_url: refToUrl2(req.lastFrame) }];
4455
4571
  }
4456
4572
  if (req.seed !== void 0) params.seed = req.seed;
4457
- let createRes;
4458
- try {
4459
- createRes = await ctx.fetch(
4460
- DOP_ENDPOINT,
4461
- requestInit(ctx, {
4462
- method: "POST",
4463
- body: JSON.stringify({ params, webhook: null })
4464
- })
4465
- );
4466
- } catch (cause) {
4467
- throw networkError(cause, ctx);
4468
- }
4469
- if (!createRes.ok) {
4470
- throw classifyHttpError(
4471
- createRes.status,
4472
- await readBody2(createRes),
4473
- "higgsfield",
4474
- ctx.model.id
4475
- );
4476
- }
4573
+ const retryOptions = {};
4574
+ if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
4575
+ const createRes = await withRetry(
4576
+ () => createRequest(ctx, DOP_ENDPOINT, {
4577
+ method: "POST",
4578
+ body: JSON.stringify({ params, webhook: null })
4579
+ }),
4580
+ retryOptions
4581
+ );
4477
4582
  const created = dopCreateSchema.safeParse(await createRes.json());
4478
4583
  if (!created.success) {
4479
4584
  throw new ModelKitError({
@@ -4542,7 +4647,10 @@ async function generateDopVideo(req, ctx) {
4542
4647
  };
4543
4648
  if (dopSignal !== void 0) pollSettings.signal = dopSignal;
4544
4649
  const url = await pollUntil(check, pollSettings);
4545
- const result = { video: { url }, usage: videoUsage3(ctx, req) };
4650
+ const result = {
4651
+ video: { url },
4652
+ usage: videoUsage3(ctx, req, req.durationSeconds ?? DOP_FALLBACK_DURATION_SECONDS)
4653
+ };
4546
4654
  return result;
4547
4655
  }
4548
4656
  };
@@ -4724,28 +4832,16 @@ var openaiImageAdapter = {
4724
4832
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
4725
4833
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
4726
4834
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
4727
- let usage2;
4728
- if (inputTokens !== void 0 || outputTokens !== void 0) {
4729
- usage2 = {
4730
- model: ctx.model.id,
4731
- provider: "openai-image",
4732
- modality: "IMAGE",
4733
- unit: "tokens",
4734
- quantity: (inputTokens ?? 0) + (outputTokens ?? 0),
4735
- imageQuality: quality
4736
- };
4737
- if (inputTokens !== void 0) usage2.inputTokens = inputTokens;
4738
- if (outputTokens !== void 0) usage2.outputTokens = outputTokens;
4739
- } else {
4740
- usage2 = {
4741
- model: ctx.model.id,
4742
- provider: "openai-image",
4743
- modality: "IMAGE",
4744
- unit: "images",
4745
- quantity: images.length,
4746
- imageQuality: quality
4747
- };
4748
- }
4835
+ const usage2 = {
4836
+ model: ctx.model.id,
4837
+ provider: "openai-image",
4838
+ modality: "IMAGE",
4839
+ unit: "images",
4840
+ quantity: images.length,
4841
+ imageQuality: quality
4842
+ };
4843
+ if (inputTokens !== void 0) usage2.inputTokens = inputTokens;
4844
+ if (outputTokens !== void 0) usage2.outputTokens = outputTokens;
4749
4845
  if (req.size !== void 0) usage2.imageSize = req.size;
4750
4846
  return { images, usage: usage2, raw: response };
4751
4847
  }
@@ -4798,7 +4894,12 @@ var NANO_BANANA_RATIOS = /* @__PURE__ */ new Set([
4798
4894
  ]);
4799
4895
  async function refToBytes(ctx, ref) {
4800
4896
  if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
4801
- const res = await ctx.fetch(ref.url);
4897
+ let res;
4898
+ try {
4899
+ res = await ctx.fetch(ref.url);
4900
+ } catch (cause) {
4901
+ throw classifyThrown("prodia", cause, ctx.model.id);
4902
+ }
4802
4903
  if (!res.ok) {
4803
4904
  const text2 = await res.text().catch(() => "");
4804
4905
  throw classifyHttpError(res.status, text2, "prodia", ctx.model.id);
@@ -4968,8 +5069,7 @@ async function generateProdiaImage(req, ctx) {
4968
5069
  body: form
4969
5070
  });
4970
5071
  } catch (err) {
4971
- if (isModelKitError(err)) throw err;
4972
- throw transportError("prodia", err, ctx.model.id);
5072
+ throw classifyThrown("prodia", err, ctx.model.id);
4973
5073
  }
4974
5074
  if (!attemptRes.ok) {
4975
5075
  const text2 = await attemptRes.text().catch(() => "");
@@ -4978,8 +5078,7 @@ async function generateProdiaImage(req, ctx) {
4978
5078
  return attemptRes;
4979
5079
  }, retryOpts);
4980
5080
  } catch (err) {
4981
- if (isModelKitError(err)) throw err;
4982
- throw transportError("prodia", err, ctx.model.id);
5081
+ throw classifyThrown("prodia", err, ctx.model.id);
4983
5082
  }
4984
5083
  const bytes = parseImageResponse(
4985
5084
  new Uint8Array(await res.arrayBuffer()),
@@ -5051,7 +5150,7 @@ function replicateError(cause, ctx) {
5051
5150
  const info = describeThrown(cause);
5052
5151
  const nested = replicateResponseStatusSchema.safeParse(cause);
5053
5152
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5054
- return classifyHttpError(status, info.body, "replicate", ctx.model.id);
5153
+ return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
5055
5154
  }
5056
5155
  function isLower(id) {
5057
5156
  return id.toLowerCase();
@@ -5361,7 +5460,7 @@ function klingInput(req) {
5361
5460
  input.start_image = startImage;
5362
5461
  const endImage = images[1];
5363
5462
  if (endImage !== void 0) input.end_image = endImage;
5364
- } else {
5463
+ } else if (req.aspectRatio !== "adaptive") {
5365
5464
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5366
5465
  }
5367
5466
  if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
@@ -5381,7 +5480,7 @@ function klingOmniInput(req) {
5381
5480
  input.start_image = startImage;
5382
5481
  const endImage = images[1];
5383
5482
  if (endImage !== void 0) input.end_image = endImage;
5384
- } else {
5483
+ } else if (req.aspectRatio !== "adaptive") {
5385
5484
  input.aspect_ratio = req.aspectRatio ?? "16:9";
5386
5485
  }
5387
5486
  const refs = (req.referenceImages ?? []).map(refToUrl3);
@@ -5590,11 +5689,10 @@ var xaiResponseStatusSchema = z13.object({
5590
5689
  response: z13.object({ status: z13.number() }).partial()
5591
5690
  });
5592
5691
  function xaiError(cause, ctx) {
5593
- if (isModelKitError(cause)) return cause;
5594
5692
  const info = describeThrown(cause);
5595
5693
  const nested = xaiResponseStatusSchema.safeParse(cause);
5596
5694
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
5597
- return classifyHttpError(status, info.body, "xai-video", ctx.model.id);
5695
+ return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
5598
5696
  }
5599
5697
  var xaiMetaSchema = z13.object({
5600
5698
  videoUrl: JsonValueSchema.optional(),
@@ -5618,10 +5716,7 @@ async function generateXaiVideo(req, ctx, deps) {
5618
5716
  retryable: false
5619
5717
  });
5620
5718
  }
5621
- const frames = [req.firstFrame, req.lastFrame, ...req.referenceImages ?? []].filter(
5622
- (r) => r !== void 0
5623
- );
5624
- const refUrls = frames.map(refToUrl4).slice(0, 5);
5719
+ const refUrls = (req.referenceImages ?? []).map(refToUrl4).slice(0, 7);
5625
5720
  const resolution = req.resolution === "480p" ? "480p" : "720p";
5626
5721
  const xaiOptions = {
5627
5722
  resolution,
@@ -5632,13 +5727,23 @@ async function generateXaiVideo(req, ctx, deps) {
5632
5727
  xaiOptions.mode = "reference-to-video";
5633
5728
  xaiOptions.referenceImageUrls = refUrls;
5634
5729
  }
5730
+ if (req.lastFrame !== void 0) {
5731
+ ctx.warnings.push({
5732
+ code: "option_ignored",
5733
+ field: "lastFrame",
5734
+ message: "xai-video does not support lastFrame; ignored"
5735
+ });
5736
+ }
5635
5737
  const client2 = deps.createXaiClient({ apiKey });
5636
- const model = createXai2({ apiKey }).video(ctx.model.providerModelId);
5738
+ const model = createXai2({ apiKey, fetch: ctx.fetch }).video(ctx.model.providerModelId);
5637
5739
  const callBody = {
5638
5740
  model,
5639
5741
  prompt: req.prompt,
5640
5742
  providerOptions: { xai: xaiOptions }
5641
5743
  };
5744
+ if (req.firstFrame) {
5745
+ callBody.frameImages = [{ image: refToUrl4(req.firstFrame), frameType: "first_frame" }];
5746
+ }
5642
5747
  if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5643
5748
  callBody.aspectRatio = req.aspectRatio;
5644
5749
  }
@@ -5724,26 +5829,14 @@ async function mapResult(ctx, req, result) {
5724
5829
  function usage(ctx, req, meta) {
5725
5830
  const costTicks = z13.number().safeParse(meta.costInUsdTicks);
5726
5831
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
5727
- if (cost !== void 0) {
5728
- const event2 = {
5729
- model: ctx.model.id,
5730
- provider: "xai-video",
5731
- modality: "VIDEO",
5732
- unit: "reported_cost_usd",
5733
- quantity: cost,
5734
- reportedCostUsd: cost
5735
- };
5736
- if (req.durationSeconds !== void 0) event2.durationSeconds = req.durationSeconds;
5737
- if (req.resolution !== void 0) event2.resolution = req.resolution;
5738
- return event2;
5739
- }
5740
5832
  const event = {
5741
5833
  model: ctx.model.id,
5742
5834
  provider: "xai-video",
5743
5835
  modality: "VIDEO",
5744
- unit: "seconds",
5745
- quantity: req.durationSeconds ?? 0
5836
+ unit: "reported_cost_usd",
5837
+ quantity: cost ?? 0
5746
5838
  };
5839
+ if (cost !== void 0) event.reportedCostUsd = cost;
5747
5840
  if (req.durationSeconds !== void 0) event.durationSeconds = req.durationSeconds;
5748
5841
  if (req.resolution !== void 0) event.resolution = req.resolution;
5749
5842
  return event;