@shop-os/modelkit 0.1.5 → 0.1.7
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/README.md +12 -11
- package/dist/index.cjs +1156 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -9
- package/dist/index.d.ts +69 -9
- package/dist/index.js +1155 -380
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -68,6 +68,7 @@ __export(index_exports, {
|
|
|
68
68
|
prodiaAdapter: () => prodiaAdapter,
|
|
69
69
|
readErrorBody: () => readErrorBody,
|
|
70
70
|
replicateAdapter: () => replicateAdapter,
|
|
71
|
+
resolveAudioOptions: () => resolveAudioOptions,
|
|
71
72
|
resolveImageOptions: () => resolveImageOptions,
|
|
72
73
|
resolveKeys: () => resolveKeys,
|
|
73
74
|
resolveVideoOptions: () => resolveVideoOptions,
|
|
@@ -165,6 +166,7 @@ var Catalog = class _Catalog {
|
|
|
165
166
|
|
|
166
167
|
// src/catalog/image.ts
|
|
167
168
|
var IMAGE_USAGE = { unit: "images", modality: "IMAGE" };
|
|
169
|
+
var IMAGE_GENERATE_EDIT = { imageGenerate: true, imageEdit: true };
|
|
168
170
|
var GEMINI_RATIOS = [
|
|
169
171
|
"1:1",
|
|
170
172
|
"2:3",
|
|
@@ -178,7 +180,7 @@ var GEMINI_RATIOS = [
|
|
|
178
180
|
"5:4",
|
|
179
181
|
"adaptive"
|
|
180
182
|
];
|
|
181
|
-
function geminiImage(id, label, aliases, sizes) {
|
|
183
|
+
function geminiImage(id, label, aliases, sizes, display) {
|
|
182
184
|
const model = {
|
|
183
185
|
id,
|
|
184
186
|
aliases,
|
|
@@ -187,25 +189,47 @@ function geminiImage(id, label, aliases, sizes) {
|
|
|
187
189
|
adapter: "google-image",
|
|
188
190
|
providerModelId: id,
|
|
189
191
|
lifecycle: "active",
|
|
190
|
-
constraints: {
|
|
192
|
+
constraints: {
|
|
193
|
+
aspectRatios: [...GEMINI_RATIOS],
|
|
194
|
+
sizes,
|
|
195
|
+
supports: ["safetySettings", "temperature"]
|
|
196
|
+
},
|
|
191
197
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
192
198
|
usage: { ...IMAGE_USAGE },
|
|
193
|
-
pricingKind: "image_size"
|
|
199
|
+
pricingKind: "image_size",
|
|
200
|
+
display,
|
|
201
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
194
202
|
};
|
|
195
203
|
return model;
|
|
196
204
|
}
|
|
197
205
|
var IMAGE_MODELS = [
|
|
198
|
-
geminiImage("gemini-3-pro-image-preview", "Nano Banana Pro", ["nb-pro"], ["1K", "2K", "4K"]
|
|
206
|
+
geminiImage("gemini-3-pro-image-preview", "Nano Banana Pro", ["nb-pro"], ["1K", "2K", "4K"], {
|
|
207
|
+
provider: "google",
|
|
208
|
+
description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
|
|
209
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
210
|
+
}),
|
|
199
211
|
geminiImage(
|
|
200
212
|
"gemini-3.1-flash-image-preview",
|
|
201
213
|
"Nano Banana Flash",
|
|
202
214
|
["nb-2"],
|
|
203
215
|
// Flash 3.1 is the only Gemini image model with the 512 tier.
|
|
204
|
-
["512", "1K", "2K", "4K"]
|
|
216
|
+
["512", "1K", "2K", "4K"],
|
|
217
|
+
{
|
|
218
|
+
provider: "google",
|
|
219
|
+
description: "Generate high-quality images at speed. Perfect for brainstorming, moodboards, concept testing, creative exploration, and large batch workflows.",
|
|
220
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
221
|
+
}
|
|
205
222
|
),
|
|
206
|
-
geminiImage("gemini-3.1-flash-lite-image", "Nano Banana Lite", ["nb-lite"], ["1K"]
|
|
223
|
+
geminiImage("gemini-3.1-flash-lite-image", "Nano Banana Lite", ["nb-lite"], ["1K"], {
|
|
224
|
+
provider: "google",
|
|
225
|
+
description: "The fastest and most affordable image model. Ideal for rapid drafts, bulk exploration, and iterative concept testing at 1K resolution.",
|
|
226
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
227
|
+
}),
|
|
207
228
|
// trigger-workflows validates 1K only; pricing seeds 2K/4K rows so allow all three.
|
|
208
|
-
geminiImage("gemini-2.5-flash-image", "Gemini 2.5 Flash Image", [], ["1K", "2K", "4K"]
|
|
229
|
+
geminiImage("gemini-2.5-flash-image", "Gemini 2.5 Flash Image", [], ["1K", "2K", "4K"], {
|
|
230
|
+
provider: "google",
|
|
231
|
+
description: "Nano Banana (legacy Gemini 2.5 Flash Image) native image generation and editing model for high-volume, low-latency creative workflows."
|
|
232
|
+
}),
|
|
209
233
|
{
|
|
210
234
|
// Cowork "auto" lets OpenAI pick the size; the canonical equivalent is adaptive.
|
|
211
235
|
id: "gpt-image-2",
|
|
@@ -223,7 +247,13 @@ var IMAGE_MODELS = [
|
|
|
223
247
|
},
|
|
224
248
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
225
249
|
usage: { ...IMAGE_USAGE },
|
|
226
|
-
pricingKind: "image_size"
|
|
250
|
+
pricingKind: "image_size",
|
|
251
|
+
display: {
|
|
252
|
+
provider: "openai",
|
|
253
|
+
description: "The most capable model for image editing and complex creative instructions. Excels at text rendering, visual consistency, design generation, and iterative refinement.",
|
|
254
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/1204b494-8962-4f7f-af5e-699a8bdc98e3_compressed.png"
|
|
255
|
+
},
|
|
256
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
227
257
|
},
|
|
228
258
|
{
|
|
229
259
|
// Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
|
|
@@ -242,7 +272,12 @@ var IMAGE_MODELS = [
|
|
|
242
272
|
},
|
|
243
273
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
244
274
|
usage: { ...IMAGE_USAGE },
|
|
245
|
-
pricingKind: "image_size"
|
|
275
|
+
pricingKind: "image_size",
|
|
276
|
+
display: {
|
|
277
|
+
provider: "openai",
|
|
278
|
+
description: "OpenAI's most capable GPT Image 2.5 tier, built for editing precision; takes text and image input and outputs images in low, medium, high, xhigh, or max quality."
|
|
279
|
+
},
|
|
280
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
246
281
|
},
|
|
247
282
|
{
|
|
248
283
|
// Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
|
|
@@ -261,7 +296,12 @@ var IMAGE_MODELS = [
|
|
|
261
296
|
},
|
|
262
297
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
263
298
|
usage: { ...IMAGE_USAGE },
|
|
264
|
-
pricingKind: "image_size"
|
|
299
|
+
pricingKind: "image_size",
|
|
300
|
+
display: {
|
|
301
|
+
provider: "openai",
|
|
302
|
+
description: "OpenAI's fastest GPT Image 2.5 tier for high-quality everyday image generation and editing; takes text and image input and outputs images."
|
|
303
|
+
},
|
|
304
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
265
305
|
},
|
|
266
306
|
{
|
|
267
307
|
// Cowork allows 7 ratios; trigger-workflows allows 9 (adds 3:2, 9:21, drops 4:5/5:4).
|
|
@@ -293,7 +333,13 @@ var IMAGE_MODELS = [
|
|
|
293
333
|
},
|
|
294
334
|
defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png", count: 1 },
|
|
295
335
|
usage: { ...IMAGE_USAGE },
|
|
296
|
-
pricingKind: "image_size"
|
|
336
|
+
pricingKind: "image_size",
|
|
337
|
+
display: {
|
|
338
|
+
provider: "meta",
|
|
339
|
+
description: "Meta's image model with built-in world knowledge and strong prompt adherence. Great for concept-rich scenes, realistic compositions, and reference-guided edits.",
|
|
340
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/characters/1787909065794-k9a7zz.png"
|
|
341
|
+
},
|
|
342
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
297
343
|
},
|
|
298
344
|
{
|
|
299
345
|
id: "seedream-5-0-pro",
|
|
@@ -313,7 +359,12 @@ var IMAGE_MODELS = [
|
|
|
313
359
|
},
|
|
314
360
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
315
361
|
usage: { ...IMAGE_USAGE },
|
|
316
|
-
pricingKind: "image_size"
|
|
362
|
+
pricingKind: "image_size",
|
|
363
|
+
display: {
|
|
364
|
+
provider: "bytedance",
|
|
365
|
+
description: "ByteDance Seedream 5.0 Pro text-to-image and multi-reference image-to-image (up to 10 inputs) with region editing; outputs 1K, 1.5K, or 2K."
|
|
366
|
+
},
|
|
367
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
317
368
|
},
|
|
318
369
|
{
|
|
319
370
|
id: "seedream-4.5",
|
|
@@ -326,14 +377,31 @@ var IMAGE_MODELS = [
|
|
|
326
377
|
constraints: {
|
|
327
378
|
// 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
|
|
328
379
|
// omits the ratio instead. Advertise only sizes the adapter can send.
|
|
329
|
-
aspectRatios: [
|
|
330
|
-
|
|
380
|
+
aspectRatios: [
|
|
381
|
+
"1:1",
|
|
382
|
+
"2:3",
|
|
383
|
+
"3:2",
|
|
384
|
+
"4:3",
|
|
385
|
+
"3:4",
|
|
386
|
+
"4:5",
|
|
387
|
+
"5:4",
|
|
388
|
+
"9:16",
|
|
389
|
+
"16:9",
|
|
390
|
+
"21:9",
|
|
391
|
+
"9:21"
|
|
392
|
+
],
|
|
393
|
+
sizes: ["1K", "2K", "4K"],
|
|
331
394
|
references: { images: 10 },
|
|
332
395
|
supports: ["seed"]
|
|
333
396
|
},
|
|
334
397
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
335
398
|
usage: { ...IMAGE_USAGE },
|
|
336
|
-
pricingKind: "image_size"
|
|
399
|
+
pricingKind: "image_size",
|
|
400
|
+
display: {
|
|
401
|
+
provider: "bytedance",
|
|
402
|
+
description: "ByteDance Seedream 4.5 text-to-image and image-to-image with up to 14 reference images and batch image-set generation; outputs 2K or 4K."
|
|
403
|
+
},
|
|
404
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
337
405
|
},
|
|
338
406
|
{
|
|
339
407
|
id: "flux-2-pro",
|
|
@@ -351,7 +419,12 @@ var IMAGE_MODELS = [
|
|
|
351
419
|
},
|
|
352
420
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
353
421
|
usage: { ...IMAGE_USAGE },
|
|
354
|
-
pricingKind: "image_size"
|
|
422
|
+
pricingKind: "image_size",
|
|
423
|
+
display: {
|
|
424
|
+
provider: "black-forest-labs",
|
|
425
|
+
description: "Black Forest Labs FLUX.2 [pro] text-to-image and multi-reference editing model served via Prodia; takes a prompt and up to 8 input images and outputs up to 4096x4096."
|
|
426
|
+
},
|
|
427
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
355
428
|
},
|
|
356
429
|
{
|
|
357
430
|
// Prodia's gemini-3-pro jobs take aspect_ratio + resolution (1K/2K/4K), not
|
|
@@ -372,7 +445,12 @@ var IMAGE_MODELS = [
|
|
|
372
445
|
},
|
|
373
446
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
374
447
|
usage: { ...IMAGE_USAGE },
|
|
375
|
-
pricingKind: "image_size"
|
|
448
|
+
pricingKind: "image_size",
|
|
449
|
+
display: {
|
|
450
|
+
provider: "google",
|
|
451
|
+
description: "Google Gemini 3 Pro image generation and editing served via Prodia; takes a prompt plus up to 3 reference images and outputs 1K, 2K, or 4K."
|
|
452
|
+
},
|
|
453
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
376
454
|
},
|
|
377
455
|
{
|
|
378
456
|
// Nano Banana (img2img.v2) is flat-rate with aspect_ratio only; 3:2, 4:5,
|
|
@@ -392,7 +470,12 @@ var IMAGE_MODELS = [
|
|
|
392
470
|
},
|
|
393
471
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
394
472
|
usage: { ...IMAGE_USAGE },
|
|
395
|
-
pricingKind: "image_size"
|
|
473
|
+
pricingKind: "image_size",
|
|
474
|
+
display: {
|
|
475
|
+
provider: "google",
|
|
476
|
+
description: "Google Nano Banana image generation and editing served via Prodia; takes a prompt plus 1-3 input images and matches the first input's aspect ratio in roughly 8 seconds."
|
|
477
|
+
},
|
|
478
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
396
479
|
},
|
|
397
480
|
{
|
|
398
481
|
// WAN 2.7 takes `images` (up to 9) and a `size` enum whose exact values
|
|
@@ -413,7 +496,12 @@ var IMAGE_MODELS = [
|
|
|
413
496
|
},
|
|
414
497
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
415
498
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
416
|
-
pricingKind: "image_size"
|
|
499
|
+
pricingKind: "image_size",
|
|
500
|
+
display: {
|
|
501
|
+
provider: "alibaba",
|
|
502
|
+
description: "Alibaba Wan 2.7 Image Pro text-to-image and image-editing model; takes a prompt plus up to 9 reference images and generates up to 4K (4096x4096)."
|
|
503
|
+
},
|
|
504
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
417
505
|
},
|
|
418
506
|
{
|
|
419
507
|
// Qwen Image 2 Pro has aspect_ratio but no size input; resolution follows
|
|
@@ -435,7 +523,12 @@ var IMAGE_MODELS = [
|
|
|
435
523
|
},
|
|
436
524
|
defaults: { aspectRatio: "1:1" },
|
|
437
525
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
438
|
-
pricingKind: "image_size"
|
|
526
|
+
pricingKind: "image_size",
|
|
527
|
+
display: {
|
|
528
|
+
provider: "alibaba",
|
|
529
|
+
description: "Alibaba Qwen Image 2 Pro unified text-to-image and editing model; takes a prompt plus an optional single reference image and generates native 2K output."
|
|
530
|
+
},
|
|
531
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
439
532
|
},
|
|
440
533
|
{
|
|
441
534
|
// Qwen Image Edit Plus takes aspect_ratio (or match_input_image) and
|
|
@@ -457,7 +550,12 @@ var IMAGE_MODELS = [
|
|
|
457
550
|
},
|
|
458
551
|
defaults: { outputFormat: "png" },
|
|
459
552
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
460
|
-
pricingKind: "image_size"
|
|
553
|
+
pricingKind: "image_size",
|
|
554
|
+
display: {
|
|
555
|
+
provider: "alibaba",
|
|
556
|
+
description: "Alibaba Qwen Image Edit Plus with Lightning and a skin-retouching LoRA; takes one or more reference images plus an edit prompt and outputs webp, jpg, or png."
|
|
557
|
+
},
|
|
558
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
461
559
|
}
|
|
462
560
|
];
|
|
463
561
|
|
|
@@ -478,7 +576,11 @@ var OTHER_MODELS = [
|
|
|
478
576
|
},
|
|
479
577
|
defaults: {},
|
|
480
578
|
usage: { unit: "images", modality: "AUDIO" },
|
|
481
|
-
pricingKind: "flat"
|
|
579
|
+
pricingKind: "flat",
|
|
580
|
+
display: {
|
|
581
|
+
provider: "google",
|
|
582
|
+
description: "Google Lyria 3 Clip short music clips, loops, and previews; takes text and up to 10 image prompts and returns a fixed 30-second MP3 plus lyrics."
|
|
583
|
+
}
|
|
482
584
|
},
|
|
483
585
|
{
|
|
484
586
|
id: "lyria-3-pro-preview",
|
|
@@ -494,7 +596,11 @@ var OTHER_MODELS = [
|
|
|
494
596
|
},
|
|
495
597
|
defaults: {},
|
|
496
598
|
usage: { unit: "images", modality: "AUDIO" },
|
|
497
|
-
pricingKind: "flat"
|
|
599
|
+
pricingKind: "flat",
|
|
600
|
+
display: {
|
|
601
|
+
provider: "google",
|
|
602
|
+
description: "Google Lyria 3 Pro flagship music model for full-length songs with verses, choruses, and bridges; takes text and up to 10 image prompts and returns MP3 plus lyrics."
|
|
603
|
+
}
|
|
498
604
|
},
|
|
499
605
|
{
|
|
500
606
|
id: "google/lyria-2",
|
|
@@ -510,7 +616,11 @@ var OTHER_MODELS = [
|
|
|
510
616
|
},
|
|
511
617
|
defaults: {},
|
|
512
618
|
usage: { unit: "compute_seconds", modality: "AUDIO" },
|
|
513
|
-
pricingKind: "flat"
|
|
619
|
+
pricingKind: "flat",
|
|
620
|
+
display: {
|
|
621
|
+
provider: "google",
|
|
622
|
+
description: "Lyria 2 music generation on Replicate; produces 30 seconds of 48 kHz stereo audio from a text prompt."
|
|
623
|
+
}
|
|
514
624
|
},
|
|
515
625
|
{
|
|
516
626
|
id: "mmaudio",
|
|
@@ -527,7 +637,11 @@ var OTHER_MODELS = [
|
|
|
527
637
|
},
|
|
528
638
|
defaults: { durationSeconds: 8 },
|
|
529
639
|
usage: { unit: "compute_seconds", modality: "AUDIO" },
|
|
530
|
-
pricingKind: "flat"
|
|
640
|
+
pricingKind: "flat",
|
|
641
|
+
display: {
|
|
642
|
+
provider: "mmaudio",
|
|
643
|
+
description: "MMAudio V2 video-to-audio model on Replicate; takes a source video and prompt and synthesizes synchronized environmental, action, and speech-like audio."
|
|
644
|
+
}
|
|
531
645
|
},
|
|
532
646
|
{
|
|
533
647
|
id: "elevenlabs-music",
|
|
@@ -544,7 +658,11 @@ var OTHER_MODELS = [
|
|
|
544
658
|
defaults: { durationSeconds: 15, instrumental: true },
|
|
545
659
|
// Replicate's run() does not report predict_time; billed by generated length.
|
|
546
660
|
usage: { unit: "seconds", modality: "AUDIO" },
|
|
547
|
-
pricingKind: "flat"
|
|
661
|
+
pricingKind: "flat",
|
|
662
|
+
display: {
|
|
663
|
+
provider: "elevenlabs",
|
|
664
|
+
description: "ElevenLabs Music text-to-music on Replicate; generates full songs, instrumental or with vocals, up to 5 minutes long at up to 44.1 kHz."
|
|
665
|
+
}
|
|
548
666
|
},
|
|
549
667
|
{
|
|
550
668
|
id: "topaz",
|
|
@@ -557,11 +675,16 @@ var OTHER_MODELS = [
|
|
|
557
675
|
constraints: {
|
|
558
676
|
references: { images: 1 },
|
|
559
677
|
requires: ["references"],
|
|
560
|
-
supports: ["scaleFactor", "outputFormat"]
|
|
678
|
+
supports: ["scaleFactor", "outputFormat", "upscale"]
|
|
561
679
|
},
|
|
562
680
|
defaults: { scaleFactor: 2, outputFormat: "png" },
|
|
563
681
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
564
|
-
pricingKind: "flat"
|
|
682
|
+
pricingKind: "flat",
|
|
683
|
+
display: {
|
|
684
|
+
provider: "topaz",
|
|
685
|
+
description: "Topaz Labs AI image upscaling on Replicate; takes one input image and upscales up to 6x with selectable enhancement models and optional face enhancement."
|
|
686
|
+
},
|
|
687
|
+
capabilities: { imageEdit: true }
|
|
565
688
|
},
|
|
566
689
|
{
|
|
567
690
|
id: "bg-remove",
|
|
@@ -578,7 +701,12 @@ var OTHER_MODELS = [
|
|
|
578
701
|
},
|
|
579
702
|
defaults: {},
|
|
580
703
|
usage: { unit: "images", modality: "IMAGE" },
|
|
581
|
-
pricingKind: "flat"
|
|
704
|
+
pricingKind: "flat",
|
|
705
|
+
display: {
|
|
706
|
+
provider: "prodia",
|
|
707
|
+
description: "Prodia background removal; takes one input image and returns a PNG cut-out of the subject plus an optional black-and-white mask."
|
|
708
|
+
},
|
|
709
|
+
capabilities: { imageEdit: true }
|
|
582
710
|
}
|
|
583
711
|
];
|
|
584
712
|
|
|
@@ -601,22 +729,112 @@ function text(id, label, providerModelId, extra) {
|
|
|
601
729
|
};
|
|
602
730
|
}
|
|
603
731
|
var TEXT_MODELS = [
|
|
604
|
-
text("gpt-4o", "GPT-4o", "gpt-4o"
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
732
|
+
text("gpt-4o", "GPT-4o", "gpt-4o", {
|
|
733
|
+
display: {
|
|
734
|
+
provider: "openai",
|
|
735
|
+
description: "OpenAI GPT-4o flagship multimodal model; text and image input, 128K-token context."
|
|
736
|
+
},
|
|
737
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
|
|
738
|
+
}),
|
|
739
|
+
text("gpt-4o-mini", "GPT-4o mini", "gpt-4o-mini", {
|
|
740
|
+
display: {
|
|
741
|
+
provider: "openai",
|
|
742
|
+
description: "OpenAI GPT-4o mini fast, low-cost multimodal model; text and image input, 128K-token context."
|
|
743
|
+
},
|
|
744
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
|
|
745
|
+
}),
|
|
746
|
+
text("gpt-5.1", "GPT-5.1", "gpt-5.1", {
|
|
747
|
+
display: {
|
|
748
|
+
provider: "openai",
|
|
749
|
+
description: "OpenAI GPT-5.1 reasoning model for coding and agentic tasks; text and image input, 400K-token context."
|
|
750
|
+
},
|
|
751
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
752
|
+
}),
|
|
753
|
+
text("gpt-5.2", "GPT-5.2", "gpt-5.2", {
|
|
754
|
+
display: {
|
|
755
|
+
provider: "openai",
|
|
756
|
+
description: "OpenAI GPT-5.2 reasoning model for complex professional work; text and image input, 400K-token context."
|
|
757
|
+
},
|
|
758
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
759
|
+
}),
|
|
760
|
+
// 1.05M-token context: https://platform.openai.com/docs/models/gpt-5.4
|
|
761
|
+
text("gpt-5.4", "GPT-5.4", "gpt-5.4", {
|
|
762
|
+
display: {
|
|
763
|
+
provider: "openai",
|
|
764
|
+
description: "OpenAI GPT-5.4 flagship reasoning model; text and image input, 1.05M-token context."
|
|
765
|
+
},
|
|
766
|
+
capabilities: {
|
|
767
|
+
vision: true,
|
|
768
|
+
tools: true,
|
|
769
|
+
structuredOutput: true,
|
|
770
|
+
contextWindow: 105e4
|
|
771
|
+
}
|
|
772
|
+
}),
|
|
609
773
|
// OpenAI never shipped gpt-5.1-mini or gpt-5.2-mini; callers that still send them get 5.4 mini.
|
|
610
774
|
text("gpt-5.4-mini", "GPT-5.4 mini", "gpt-5.4-mini", {
|
|
611
|
-
aliases: ["gpt-5.1-mini", "gpt-5.2-mini"]
|
|
775
|
+
aliases: ["gpt-5.1-mini", "gpt-5.2-mini"],
|
|
776
|
+
display: {
|
|
777
|
+
provider: "openai",
|
|
778
|
+
description: "OpenAI GPT-5.4 mini efficient reasoning model for high-volume workloads; text and image input, 400K-token context."
|
|
779
|
+
},
|
|
780
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
781
|
+
}),
|
|
782
|
+
text("gpt-5.5", "GPT-5.5", "gpt-5.5", {
|
|
783
|
+
display: {
|
|
784
|
+
provider: "openai",
|
|
785
|
+
description: "OpenAI GPT-5.5 flagship reasoning model for the most complex professional and coding work; text and image input, 1.05M-token context."
|
|
786
|
+
},
|
|
787
|
+
capabilities: {
|
|
788
|
+
vision: true,
|
|
789
|
+
tools: true,
|
|
790
|
+
structuredOutput: true,
|
|
791
|
+
contextWindow: 105e4
|
|
792
|
+
}
|
|
793
|
+
}),
|
|
794
|
+
text("gpt-5.6-luna", "GPT-5.6 Luna", "gpt-5.6-luna", {
|
|
795
|
+
display: {
|
|
796
|
+
provider: "openai",
|
|
797
|
+
description: "OpenAI GPT-5.6 Luna cost-optimized tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
798
|
+
},
|
|
799
|
+
capabilities: {
|
|
800
|
+
vision: true,
|
|
801
|
+
tools: true,
|
|
802
|
+
structuredOutput: true,
|
|
803
|
+
contextWindow: 105e4
|
|
804
|
+
}
|
|
805
|
+
}),
|
|
806
|
+
text("gpt-5.6-terra", "GPT-5.6 Terra", "gpt-5.6-terra", {
|
|
807
|
+
display: {
|
|
808
|
+
provider: "openai",
|
|
809
|
+
description: "OpenAI GPT-5.6 Terra balanced tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
810
|
+
},
|
|
811
|
+
capabilities: {
|
|
812
|
+
vision: true,
|
|
813
|
+
tools: true,
|
|
814
|
+
structuredOutput: true,
|
|
815
|
+
contextWindow: 105e4
|
|
816
|
+
}
|
|
817
|
+
}),
|
|
818
|
+
text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol", {
|
|
819
|
+
display: {
|
|
820
|
+
provider: "openai",
|
|
821
|
+
description: "OpenAI GPT-5.6 Sol flagship tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
822
|
+
},
|
|
823
|
+
capabilities: {
|
|
824
|
+
vision: true,
|
|
825
|
+
tools: true,
|
|
826
|
+
structuredOutput: true,
|
|
827
|
+
contextWindow: 105e4
|
|
828
|
+
}
|
|
612
829
|
}),
|
|
613
|
-
text("gpt-5.5", "GPT-5.5", "gpt-5.5"),
|
|
614
|
-
text("gpt-5.6-luna", "GPT-5.6 Luna", "gpt-5.6-luna"),
|
|
615
|
-
text("gpt-5.6-terra", "GPT-5.6 Terra", "gpt-5.6-terra"),
|
|
616
|
-
text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol"),
|
|
617
830
|
// Library key "claude-sonnet-4.5" maps to the SDK id "claude-sonnet-4-5".
|
|
618
831
|
text("claude-sonnet-4-5", "Claude Sonnet 4.5", "claude-sonnet-4-5", {
|
|
619
|
-
aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"]
|
|
832
|
+
aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"],
|
|
833
|
+
display: {
|
|
834
|
+
provider: "anthropic",
|
|
835
|
+
description: "Anthropic Claude Sonnet 4.5 (legacy) balanced model; text and image input, 200K-token context."
|
|
836
|
+
},
|
|
837
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
|
|
620
838
|
}),
|
|
621
839
|
// Anthropic retired the dated 4.0 ids; callers that still send them get 4.6.
|
|
622
840
|
text("claude-sonnet-4-6", "Claude Sonnet 4.6", "claude-sonnet-4-6", {
|
|
@@ -625,42 +843,280 @@ var TEXT_MODELS = [
|
|
|
625
843
|
"claude-sonnet-4",
|
|
626
844
|
"claude-sonnet-4.0",
|
|
627
845
|
"claude-sonnet-4-20250514"
|
|
628
|
-
]
|
|
846
|
+
],
|
|
847
|
+
display: {
|
|
848
|
+
provider: "anthropic",
|
|
849
|
+
description: "Anthropic Claude Sonnet 4.6 (legacy) balanced model; text and image input, 1M-token context."
|
|
850
|
+
},
|
|
851
|
+
capabilities: {
|
|
852
|
+
vision: true,
|
|
853
|
+
tools: true,
|
|
854
|
+
structuredOutput: true,
|
|
855
|
+
contextWindow: 1e6
|
|
856
|
+
}
|
|
857
|
+
}),
|
|
858
|
+
text("claude-sonnet-5", "Claude Sonnet 5", "claude-sonnet-5", {
|
|
859
|
+
display: {
|
|
860
|
+
provider: "anthropic",
|
|
861
|
+
description: "Anthropic Claude Sonnet 5 current balanced model; text and image input, 1M-token context."
|
|
862
|
+
},
|
|
863
|
+
capabilities: {
|
|
864
|
+
vision: true,
|
|
865
|
+
tools: true,
|
|
866
|
+
structuredOutput: true,
|
|
867
|
+
contextWindow: 1e6
|
|
868
|
+
}
|
|
629
869
|
}),
|
|
630
|
-
text("claude-sonnet-5", "Claude Sonnet 5", "claude-sonnet-5"),
|
|
631
870
|
text("claude-opus-4-8", "Claude Opus 4.8", "claude-opus-4-8", {
|
|
632
|
-
aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"]
|
|
871
|
+
aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"],
|
|
872
|
+
display: {
|
|
873
|
+
provider: "anthropic",
|
|
874
|
+
description: "Anthropic Claude Opus 4.8 (legacy) frontier model; text and image input, 1M-token context."
|
|
875
|
+
},
|
|
876
|
+
capabilities: {
|
|
877
|
+
vision: true,
|
|
878
|
+
tools: true,
|
|
879
|
+
structuredOutput: true,
|
|
880
|
+
contextWindow: 1e6
|
|
881
|
+
}
|
|
633
882
|
}),
|
|
634
883
|
text("claude-haiku-4-5", "Claude Haiku 4.5", "claude-haiku-4-5", {
|
|
635
|
-
aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"]
|
|
884
|
+
aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"],
|
|
885
|
+
display: {
|
|
886
|
+
provider: "anthropic",
|
|
887
|
+
description: "Anthropic Claude Haiku 4.5 fast model with near-frontier intelligence; text and image input, 200K-token context."
|
|
888
|
+
},
|
|
889
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
|
|
636
890
|
}),
|
|
637
891
|
text("claude-opus-5", "Claude Opus 5", "claude-opus-5", {
|
|
638
|
-
aliases: ["claude-opus-5.0"]
|
|
892
|
+
aliases: ["claude-opus-5.0"],
|
|
893
|
+
display: {
|
|
894
|
+
provider: "anthropic",
|
|
895
|
+
description: "Anthropic Claude Opus 5 current frontier model for agentic coding and enterprise work; text and image input, 1M-token context."
|
|
896
|
+
},
|
|
897
|
+
capabilities: {
|
|
898
|
+
vision: true,
|
|
899
|
+
tools: true,
|
|
900
|
+
structuredOutput: true,
|
|
901
|
+
contextWindow: 1e6
|
|
902
|
+
}
|
|
903
|
+
}),
|
|
904
|
+
text("claude-fable-5", "Claude Fable 5", "claude-fable-5", {
|
|
905
|
+
display: {
|
|
906
|
+
provider: "anthropic",
|
|
907
|
+
description: "Anthropic Claude Fable 5 (legacy) model for demanding reasoning and long-horizon agentic work; text and image input, 1M-token context."
|
|
908
|
+
},
|
|
909
|
+
capabilities: {
|
|
910
|
+
vision: true,
|
|
911
|
+
tools: true,
|
|
912
|
+
structuredOutput: true,
|
|
913
|
+
contextWindow: 1e6
|
|
914
|
+
}
|
|
915
|
+
}),
|
|
916
|
+
text("gemini-2.5-flash", "Gemini 2.5 Flash", "gemini-2.5-flash", {
|
|
917
|
+
display: {
|
|
918
|
+
provider: "google",
|
|
919
|
+
description: "Google Gemini 2.5 Flash low-latency multimodal model for high-volume reasoning over text, images, video, and audio; 1M-token context."
|
|
920
|
+
},
|
|
921
|
+
capabilities: {
|
|
922
|
+
vision: true,
|
|
923
|
+
tools: true,
|
|
924
|
+
structuredOutput: true,
|
|
925
|
+
contextWindow: 1048576
|
|
926
|
+
}
|
|
927
|
+
}),
|
|
928
|
+
text("gemini-2.5-pro", "Gemini 2.5 Pro", "gemini-2.5-pro", {
|
|
929
|
+
display: {
|
|
930
|
+
provider: "google",
|
|
931
|
+
description: "Google Gemini 2.5 Pro thinking model for complex reasoning over code, math, and documents; text, image, video, audio, and PDF input, 1M-token context."
|
|
932
|
+
},
|
|
933
|
+
capabilities: {
|
|
934
|
+
vision: true,
|
|
935
|
+
tools: true,
|
|
936
|
+
structuredOutput: true,
|
|
937
|
+
contextWindow: 1048576
|
|
938
|
+
}
|
|
939
|
+
}),
|
|
940
|
+
text("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)", "gemini-3.1-pro-preview", {
|
|
941
|
+
display: {
|
|
942
|
+
provider: "google",
|
|
943
|
+
description: "Google Gemini 3.1 Pro preview reasoning model for software engineering, tool use, and reliable agentic workflows; 1M-token context."
|
|
944
|
+
},
|
|
945
|
+
capabilities: {
|
|
946
|
+
vision: true,
|
|
947
|
+
tools: true,
|
|
948
|
+
structuredOutput: true,
|
|
949
|
+
contextWindow: 1048576
|
|
950
|
+
}
|
|
951
|
+
}),
|
|
952
|
+
text("gemini-3.5-flash", "Gemini 3.5 Flash", "gemini-3.5-flash", {
|
|
953
|
+
display: {
|
|
954
|
+
provider: "google",
|
|
955
|
+
description: "Google Gemini 3.5 Flash high-throughput model for frontier-level agentic tasks; text, image, video, audio, and PDF input, 1M-token context."
|
|
956
|
+
},
|
|
957
|
+
capabilities: {
|
|
958
|
+
vision: true,
|
|
959
|
+
tools: true,
|
|
960
|
+
structuredOutput: true,
|
|
961
|
+
contextWindow: 1048576
|
|
962
|
+
}
|
|
963
|
+
}),
|
|
964
|
+
text("gemini-3.6-flash", "Gemini 3.6 Flash", "gemini-3.6-flash", {
|
|
965
|
+
display: {
|
|
966
|
+
provider: "google",
|
|
967
|
+
description: "Google Gemini 3.6 Flash general-purpose multimodal agentic model balancing speed and capability; 1M-token context."
|
|
968
|
+
},
|
|
969
|
+
capabilities: {
|
|
970
|
+
vision: true,
|
|
971
|
+
tools: true,
|
|
972
|
+
structuredOutput: true,
|
|
973
|
+
contextWindow: 1048576
|
|
974
|
+
}
|
|
975
|
+
}),
|
|
976
|
+
text("gemini-3.7-flash", "Gemini 3.7 Flash", "gemini-3.7-flash", {
|
|
977
|
+
display: {
|
|
978
|
+
provider: "google",
|
|
979
|
+
description: "Google Gemini 3.7 Flash natively multimodal reasoning model for coding, agentic workflows, and multi-step execution; 1M-token context."
|
|
980
|
+
},
|
|
981
|
+
capabilities: {
|
|
982
|
+
vision: true,
|
|
983
|
+
tools: true,
|
|
984
|
+
structuredOutput: true,
|
|
985
|
+
contextWindow: 1048576
|
|
986
|
+
}
|
|
987
|
+
}),
|
|
988
|
+
text("gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash", {
|
|
989
|
+
display: {
|
|
990
|
+
provider: "google",
|
|
991
|
+
description: "Google Gemini 3.8 Flash frontier model for long-horizon software engineering, autonomous agents, and enterprise workflows; 1M-token context."
|
|
992
|
+
},
|
|
993
|
+
capabilities: {
|
|
994
|
+
vision: true,
|
|
995
|
+
tools: true,
|
|
996
|
+
structuredOutput: true,
|
|
997
|
+
contextWindow: 1048576
|
|
998
|
+
}
|
|
639
999
|
}),
|
|
640
|
-
text("claude-fable-5", "Claude Fable 5", "claude-fable-5"),
|
|
641
|
-
text("gemini-2.5-flash", "Gemini 2.5 Flash", "gemini-2.5-flash"),
|
|
642
|
-
text("gemini-2.5-pro", "Gemini 2.5 Pro", "gemini-2.5-pro"),
|
|
643
|
-
text("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)", "gemini-3.1-pro-preview"),
|
|
644
|
-
text("gemini-3.5-flash", "Gemini 3.5 Flash", "gemini-3.5-flash"),
|
|
645
|
-
text("gemini-3.6-flash", "Gemini 3.6 Flash", "gemini-3.6-flash"),
|
|
646
|
-
text("gemini-3.7-flash", "Gemini 3.7 Flash", "gemini-3.7-flash"),
|
|
647
|
-
text("gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash"),
|
|
648
1000
|
// Renamed to gemini-3.6-flash in vibe-shared model-migration.ts.
|
|
649
1001
|
text("gemini-3-flash-preview", "Gemini 3 Flash (preview)", "gemini-3-flash-preview", {
|
|
650
1002
|
lifecycle: "deprecated",
|
|
651
1003
|
replacedBy: "gemini-3.6-flash"
|
|
652
1004
|
}),
|
|
653
|
-
text("gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite", "gemini-3.1-flash-lite"
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1005
|
+
text("gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite", "gemini-3.1-flash-lite", {
|
|
1006
|
+
display: {
|
|
1007
|
+
provider: "google",
|
|
1008
|
+
description: "Google Gemini 3.1 Flash-Lite low-latency multimodal model for high-volume agentic, translation, and data-extraction tasks; 1M-token context."
|
|
1009
|
+
},
|
|
1010
|
+
capabilities: {
|
|
1011
|
+
vision: true,
|
|
1012
|
+
tools: true,
|
|
1013
|
+
structuredOutput: true,
|
|
1014
|
+
contextWindow: 1048576
|
|
1015
|
+
}
|
|
1016
|
+
}),
|
|
1017
|
+
text("sonar", "Sonar", "sonar", {
|
|
1018
|
+
display: {
|
|
1019
|
+
provider: "perplexity",
|
|
1020
|
+
description: "Perplexity Sonar lightweight web-grounded search model returning cited answers; 128K-token context."
|
|
1021
|
+
},
|
|
1022
|
+
capabilities: {
|
|
1023
|
+
vision: true,
|
|
1024
|
+
tools: false,
|
|
1025
|
+
structuredOutput: true,
|
|
1026
|
+
contextWindow: 128e3
|
|
1027
|
+
}
|
|
1028
|
+
}),
|
|
1029
|
+
text("sonar-pro", "Sonar Pro", "sonar-pro", {
|
|
1030
|
+
display: {
|
|
1031
|
+
provider: "perplexity",
|
|
1032
|
+
description: "Perplexity Sonar Pro advanced web-grounded search model for complex multi-step queries; 200K-token context."
|
|
1033
|
+
},
|
|
1034
|
+
capabilities: {
|
|
1035
|
+
vision: true,
|
|
1036
|
+
tools: false,
|
|
1037
|
+
structuredOutput: true,
|
|
1038
|
+
contextWindow: 2e5
|
|
1039
|
+
}
|
|
1040
|
+
}),
|
|
1041
|
+
text("sonar-reasoning-pro", "Sonar Reasoning Pro", "sonar-reasoning-pro", {
|
|
1042
|
+
display: {
|
|
1043
|
+
provider: "perplexity",
|
|
1044
|
+
description: "Perplexity Sonar Reasoning Pro chain-of-thought web-grounded search model for complex problem-solving; 128K-token context."
|
|
1045
|
+
},
|
|
1046
|
+
capabilities: {
|
|
1047
|
+
vision: true,
|
|
1048
|
+
tools: false,
|
|
1049
|
+
structuredOutput: true,
|
|
1050
|
+
contextWindow: 128e3
|
|
1051
|
+
}
|
|
1052
|
+
}),
|
|
1053
|
+
text("deepseek-v4-flash", "DeepSeek V4 Flash", "deepseek-v4-flash", {
|
|
1054
|
+
display: {
|
|
1055
|
+
provider: "deepseek",
|
|
1056
|
+
description: "DeepSeek V4 Flash thinking/non-thinking model with vision, tool calls, and JSON output; 1M-token context and up to 384K output tokens."
|
|
1057
|
+
},
|
|
1058
|
+
capabilities: {
|
|
1059
|
+
vision: true,
|
|
1060
|
+
tools: true,
|
|
1061
|
+
structuredOutput: true,
|
|
1062
|
+
contextWindow: 1e6
|
|
1063
|
+
}
|
|
1064
|
+
}),
|
|
1065
|
+
text("deepseek-v4-pro", "DeepSeek V4 Pro", "deepseek-v4-pro", {
|
|
1066
|
+
display: {
|
|
1067
|
+
provider: "deepseek",
|
|
1068
|
+
description: "DeepSeek V4 Pro thinking/non-thinking text model with tool calls and JSON output (no vision); 1M-token context and up to 384K output tokens."
|
|
1069
|
+
},
|
|
1070
|
+
capabilities: {
|
|
1071
|
+
vision: false,
|
|
1072
|
+
tools: true,
|
|
1073
|
+
structuredOutput: true,
|
|
1074
|
+
contextWindow: 1e6
|
|
1075
|
+
}
|
|
1076
|
+
}),
|
|
1077
|
+
// 1M-token context: https://docs.x.ai/docs/models/grok-4.3
|
|
1078
|
+
text("grok-4.3", "Grok 4.3", "grok-4.3", {
|
|
1079
|
+
display: {
|
|
1080
|
+
provider: "xai",
|
|
1081
|
+
description: "xAI Grok 4.3 reasoning model with tool calling and structured outputs; text and image input, 1M-token context."
|
|
1082
|
+
},
|
|
1083
|
+
capabilities: {
|
|
1084
|
+
vision: true,
|
|
1085
|
+
tools: true,
|
|
1086
|
+
structuredOutput: true,
|
|
1087
|
+
contextWindow: 1e6
|
|
1088
|
+
}
|
|
1089
|
+
}),
|
|
1090
|
+
// Moonshot retired kimi-k2.5 on 2026-08-31 and no longer publishes its specs.
|
|
1091
|
+
text("kimi-k2.5", "Kimi K2.5", "kimi-k2.5", {
|
|
1092
|
+
display: {
|
|
1093
|
+
provider: "moonshot",
|
|
1094
|
+
description: "Moonshot Kimi K2.5; the provider retired the model on 2026-08-31 and calls now return a model-not-found error."
|
|
1095
|
+
},
|
|
1096
|
+
capabilities: {}
|
|
1097
|
+
}),
|
|
1098
|
+
text("kimi-k3", "Kimi K3", "kimi-k3", {
|
|
1099
|
+
display: {
|
|
1100
|
+
provider: "moonshot",
|
|
1101
|
+
description: "Moonshot Kimi K3 flagship model with native visual understanding and always-on thinking; text, image, and video input, 1M-token context."
|
|
1102
|
+
},
|
|
1103
|
+
capabilities: {
|
|
1104
|
+
vision: true,
|
|
1105
|
+
tools: true,
|
|
1106
|
+
structuredOutput: true,
|
|
1107
|
+
contextWindow: 1e6
|
|
1108
|
+
}
|
|
1109
|
+
}),
|
|
662
1110
|
// Cowork calls the provider "MiniMax-M3"; the pricing key is lowercase.
|
|
663
|
-
|
|
1111
|
+
// 1M-token context: https://platform.minimax.io/docs/api-reference/text-openai-api
|
|
1112
|
+
text("minimax-m3", "MiniMax M3", "MiniMax-M3", {
|
|
1113
|
+
aliases: ["MiniMax-M3"],
|
|
1114
|
+
display: {
|
|
1115
|
+
provider: "minimax",
|
|
1116
|
+
description: "MiniMax M3 frontier multimodal model for agentic reasoning, tool use, and coding; text, image, and video input, 1M-token context."
|
|
1117
|
+
},
|
|
1118
|
+
capabilities: { vision: true, tools: true, contextWindow: 1e6 }
|
|
1119
|
+
})
|
|
664
1120
|
];
|
|
665
1121
|
|
|
666
1122
|
// src/catalog/video.ts
|
|
@@ -672,6 +1128,8 @@ var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
|
|
|
672
1128
|
var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
|
|
673
1129
|
var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
|
|
674
1130
|
var NEGATIVE_PROMPT = "blur, distort, and low quality";
|
|
1131
|
+
var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
|
|
1132
|
+
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
675
1133
|
var VIDEO_MODELS = [
|
|
676
1134
|
{
|
|
677
1135
|
id: "veo-3.1",
|
|
@@ -695,7 +1153,13 @@ var VIDEO_MODELS = [
|
|
|
695
1153
|
},
|
|
696
1154
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
697
1155
|
usage: { ...VIDEO_USAGE },
|
|
698
|
-
pricingKind: "video_per_second"
|
|
1156
|
+
pricingKind: "video_per_second",
|
|
1157
|
+
display: {
|
|
1158
|
+
provider: "google",
|
|
1159
|
+
description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
|
|
1160
|
+
logo: GOOGLE_LOGO
|
|
1161
|
+
},
|
|
1162
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
699
1163
|
},
|
|
700
1164
|
{
|
|
701
1165
|
id: "veo-3.1-fast",
|
|
@@ -718,7 +1182,12 @@ var VIDEO_MODELS = [
|
|
|
718
1182
|
},
|
|
719
1183
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
720
1184
|
usage: { ...VIDEO_USAGE },
|
|
721
|
-
pricingKind: "video_per_second"
|
|
1185
|
+
pricingKind: "video_per_second",
|
|
1186
|
+
display: {
|
|
1187
|
+
provider: "google",
|
|
1188
|
+
description: "Faster variant of Google Veo 3.1; text- and image-to-video with natively generated audio at 4 or 8 seconds."
|
|
1189
|
+
},
|
|
1190
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
722
1191
|
},
|
|
723
1192
|
{
|
|
724
1193
|
id: "veo-3.1-lite",
|
|
@@ -741,7 +1210,12 @@ var VIDEO_MODELS = [
|
|
|
741
1210
|
},
|
|
742
1211
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
743
1212
|
usage: { ...VIDEO_USAGE },
|
|
744
|
-
pricingKind: "video_per_second"
|
|
1213
|
+
pricingKind: "video_per_second",
|
|
1214
|
+
display: {
|
|
1215
|
+
provider: "google",
|
|
1216
|
+
description: "Efficiency-focused Google Veo 3.1 Lite for high-volume video generation and editing; text and image input, with no 4K output or video extension."
|
|
1217
|
+
},
|
|
1218
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
745
1219
|
},
|
|
746
1220
|
{
|
|
747
1221
|
id: "gemini-omni-flash",
|
|
@@ -768,7 +1242,13 @@ var VIDEO_MODELS = [
|
|
|
768
1242
|
},
|
|
769
1243
|
defaults: {},
|
|
770
1244
|
usage: { ...VIDEO_USAGE },
|
|
771
|
-
pricingKind: "video_per_second"
|
|
1245
|
+
pricingKind: "video_per_second",
|
|
1246
|
+
display: {
|
|
1247
|
+
provider: "google",
|
|
1248
|
+
description: "Google's conversational video model with native audio, human support, and natural language editing. Aspect ratio only \u2014 resolution and duration are model-determined.",
|
|
1249
|
+
logo: GOOGLE_LOGO
|
|
1250
|
+
},
|
|
1251
|
+
capabilities: { acceptsSourceVideo: true }
|
|
772
1252
|
},
|
|
773
1253
|
{
|
|
774
1254
|
id: "gemini-omni-1.1-flash",
|
|
@@ -787,7 +1267,12 @@ var VIDEO_MODELS = [
|
|
|
787
1267
|
},
|
|
788
1268
|
defaults: {},
|
|
789
1269
|
usage: { ...VIDEO_USAGE },
|
|
790
|
-
pricingKind: "video_per_second"
|
|
1270
|
+
pricingKind: "video_per_second",
|
|
1271
|
+
display: {
|
|
1272
|
+
provider: "google",
|
|
1273
|
+
description: "Google Gemini Omni Flash 1.1 conversational video generation and editing; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS."
|
|
1274
|
+
},
|
|
1275
|
+
capabilities: { acceptsSourceVideo: true }
|
|
791
1276
|
},
|
|
792
1277
|
{
|
|
793
1278
|
// vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
|
|
@@ -804,7 +1289,7 @@ var VIDEO_MODELS = [
|
|
|
804
1289
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
805
1290
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
806
1291
|
ratioIgnoredWith: ["firstFrame"],
|
|
807
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1292
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
808
1293
|
},
|
|
809
1294
|
defaults: {
|
|
810
1295
|
durationSeconds: 5,
|
|
@@ -813,7 +1298,13 @@ var VIDEO_MODELS = [
|
|
|
813
1298
|
generateAudio: true
|
|
814
1299
|
},
|
|
815
1300
|
usage: { ...VIDEO_USAGE },
|
|
816
|
-
pricingKind: "video_per_second"
|
|
1301
|
+
pricingKind: "video_per_second",
|
|
1302
|
+
display: {
|
|
1303
|
+
provider: "bytedance",
|
|
1304
|
+
description: "High-quality AI video generation with reference image conditioning. Supports 4-15 second clips with human preprocessing.",
|
|
1305
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png"
|
|
1306
|
+
},
|
|
1307
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
817
1308
|
},
|
|
818
1309
|
{
|
|
819
1310
|
id: "seedance-2.0-fast",
|
|
@@ -829,7 +1320,7 @@ var VIDEO_MODELS = [
|
|
|
829
1320
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
830
1321
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
831
1322
|
ratioIgnoredWith: ["firstFrame"],
|
|
832
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1323
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
833
1324
|
},
|
|
834
1325
|
defaults: {
|
|
835
1326
|
durationSeconds: 5,
|
|
@@ -838,7 +1329,12 @@ var VIDEO_MODELS = [
|
|
|
838
1329
|
generateAudio: true
|
|
839
1330
|
},
|
|
840
1331
|
usage: { ...VIDEO_USAGE },
|
|
841
|
-
pricingKind: "video_per_second"
|
|
1332
|
+
pricingKind: "video_per_second",
|
|
1333
|
+
display: {
|
|
1334
|
+
provider: "bytedance",
|
|
1335
|
+
description: "Speed- and cost-optimized ByteDance Seedance 2.0 Fast; text plus image, video, and audio references to generate or edit 4-15 second clips."
|
|
1336
|
+
},
|
|
1337
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
842
1338
|
},
|
|
843
1339
|
{
|
|
844
1340
|
// generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
|
|
@@ -855,7 +1351,7 @@ var VIDEO_MODELS = [
|
|
|
855
1351
|
durations: { min: 4, max: 30 },
|
|
856
1352
|
references: { images: 30, videos: 10, audios: 10 },
|
|
857
1353
|
ratioIgnoredWith: ["firstFrame"],
|
|
858
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1354
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
859
1355
|
},
|
|
860
1356
|
defaults: {
|
|
861
1357
|
durationSeconds: 5,
|
|
@@ -864,7 +1360,12 @@ var VIDEO_MODELS = [
|
|
|
864
1360
|
generateAudio: false
|
|
865
1361
|
},
|
|
866
1362
|
usage: { ...VIDEO_USAGE },
|
|
867
|
-
pricingKind: "video_per_second"
|
|
1363
|
+
pricingKind: "video_per_second",
|
|
1364
|
+
display: {
|
|
1365
|
+
provider: "bytedance",
|
|
1366
|
+
description: "ByteDance Seedance 2.5 for long-form storytelling and omni-reference generation/editing; up to 50 reference assets and 4-30 second clips at up to 1080p."
|
|
1367
|
+
},
|
|
1368
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
868
1369
|
},
|
|
869
1370
|
{
|
|
870
1371
|
// Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
|
|
@@ -882,9 +1383,16 @@ var VIDEO_MODELS = [
|
|
|
882
1383
|
references: { images: 7 },
|
|
883
1384
|
supports: []
|
|
884
1385
|
},
|
|
885
|
-
|
|
1386
|
+
// No resolution default: xAI picks its own unless the caller asks.
|
|
1387
|
+
defaults: { durationSeconds: 8, aspectRatio: "16:9" },
|
|
886
1388
|
usage: { unit: "reported_cost_usd", modality: "VIDEO" },
|
|
887
|
-
pricingKind: "video_per_second"
|
|
1389
|
+
pricingKind: "video_per_second",
|
|
1390
|
+
display: {
|
|
1391
|
+
provider: "xai",
|
|
1392
|
+
description: "xAI's reference-to-video model. Generates short clips conditioned on up to 7 reference images with flexible aspect ratios.",
|
|
1393
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/858b7fcc-9bd5-411d-aea1-a7b35ecfffab_compressed.png"
|
|
1394
|
+
},
|
|
1395
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
888
1396
|
},
|
|
889
1397
|
{
|
|
890
1398
|
id: "kling-2.5",
|
|
@@ -907,7 +1415,12 @@ var VIDEO_MODELS = [
|
|
|
907
1415
|
negativePrompt: NEGATIVE_PROMPT
|
|
908
1416
|
},
|
|
909
1417
|
usage: { ...VIDEO_USAGE },
|
|
910
|
-
pricingKind: "video_per_second"
|
|
1418
|
+
pricingKind: "video_per_second",
|
|
1419
|
+
display: {
|
|
1420
|
+
provider: "kuaishou",
|
|
1421
|
+
description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt with an optional end image, 5- or 10-second clips."
|
|
1422
|
+
},
|
|
1423
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
911
1424
|
},
|
|
912
1425
|
{
|
|
913
1426
|
// trigger-workflows validates 5/10 only; Space Builder allows 3-15s (Kling30Input).
|
|
@@ -931,7 +1444,12 @@ var VIDEO_MODELS = [
|
|
|
931
1444
|
negativePrompt: NEGATIVE_PROMPT
|
|
932
1445
|
},
|
|
933
1446
|
usage: { ...VIDEO_USAGE },
|
|
934
|
-
pricingKind: "video_per_second"
|
|
1447
|
+
pricingKind: "video_per_second",
|
|
1448
|
+
display: {
|
|
1449
|
+
provider: "kuaishou",
|
|
1450
|
+
description: "Kuaishou Kling 3.0 Pro image-to-video; a required start image plus a text prompt (or multi-shot prompts) with optional end image and native audio, 3-15 second clips."
|
|
1451
|
+
},
|
|
1452
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
935
1453
|
},
|
|
936
1454
|
{
|
|
937
1455
|
// mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
|
|
@@ -962,7 +1480,12 @@ var VIDEO_MODELS = [
|
|
|
962
1480
|
},
|
|
963
1481
|
defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
|
|
964
1482
|
usage: { unit: "compute_seconds", modality: "VIDEO" },
|
|
965
|
-
pricingKind: "video_per_second"
|
|
1483
|
+
pricingKind: "video_per_second",
|
|
1484
|
+
display: {
|
|
1485
|
+
provider: "kuaishou",
|
|
1486
|
+
description: "Kuaishou Kling Video 3.0 Omni unified generation and editing from text, start/end images, up to 7 reference images, and reference video; up to 15 seconds at up to 1080p."
|
|
1487
|
+
},
|
|
1488
|
+
capabilities: {}
|
|
966
1489
|
},
|
|
967
1490
|
{
|
|
968
1491
|
id: "minimax-h3",
|
|
@@ -976,7 +1499,7 @@ var VIDEO_MODELS = [
|
|
|
976
1499
|
aspectRatios: [...H3_RATIOS],
|
|
977
1500
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
978
1501
|
durations: { min: 5, max: 15 },
|
|
979
|
-
supports: ["seed", "promptExpansion"]
|
|
1502
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
980
1503
|
},
|
|
981
1504
|
defaults: {
|
|
982
1505
|
durationSeconds: 5,
|
|
@@ -985,7 +1508,12 @@ var VIDEO_MODELS = [
|
|
|
985
1508
|
promptExpansion: "balanced"
|
|
986
1509
|
},
|
|
987
1510
|
usage: { ...VIDEO_USAGE },
|
|
988
|
-
pricingKind: "video_per_second"
|
|
1511
|
+
pricingKind: "video_per_second",
|
|
1512
|
+
display: {
|
|
1513
|
+
provider: "minimax",
|
|
1514
|
+
description: "MiniMax H3 multimodal video model for text-to-video, image-to-video (first/last frame), and reference-to-video with native audio, up to 2K."
|
|
1515
|
+
},
|
|
1516
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
989
1517
|
},
|
|
990
1518
|
{
|
|
991
1519
|
id: "minimax-h3-max",
|
|
@@ -999,7 +1527,7 @@ var VIDEO_MODELS = [
|
|
|
999
1527
|
aspectRatios: [...H3_RATIOS],
|
|
1000
1528
|
resolutions: ["480p", "768p"],
|
|
1001
1529
|
durations: { min: 5, max: 15 },
|
|
1002
|
-
supports: ["seed", "promptExpansion"]
|
|
1530
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
1003
1531
|
},
|
|
1004
1532
|
defaults: {
|
|
1005
1533
|
durationSeconds: 5,
|
|
@@ -1008,7 +1536,12 @@ var VIDEO_MODELS = [
|
|
|
1008
1536
|
promptExpansion: "balanced"
|
|
1009
1537
|
},
|
|
1010
1538
|
usage: { ...VIDEO_USAGE },
|
|
1011
|
-
pricingKind: "video_per_second"
|
|
1539
|
+
pricingKind: "video_per_second",
|
|
1540
|
+
display: {
|
|
1541
|
+
provider: "minimax",
|
|
1542
|
+
description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
|
|
1543
|
+
},
|
|
1544
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
1012
1545
|
},
|
|
1013
1546
|
{
|
|
1014
1547
|
id: "minimax-h3-reference",
|
|
@@ -1023,7 +1556,7 @@ var VIDEO_MODELS = [
|
|
|
1023
1556
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
1024
1557
|
durations: { min: 5, max: 15 },
|
|
1025
1558
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
1026
|
-
supports: ["seed", "promptExpansion"]
|
|
1559
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
1027
1560
|
},
|
|
1028
1561
|
defaults: {
|
|
1029
1562
|
durationSeconds: 5,
|
|
@@ -1032,7 +1565,12 @@ var VIDEO_MODELS = [
|
|
|
1032
1565
|
promptExpansion: "balanced"
|
|
1033
1566
|
},
|
|
1034
1567
|
usage: { ...VIDEO_USAGE },
|
|
1035
|
-
pricingKind: "video_per_second"
|
|
1568
|
+
pricingKind: "video_per_second",
|
|
1569
|
+
display: {
|
|
1570
|
+
provider: "minimax",
|
|
1571
|
+
description: "MiniMax H3 reference-to-video mode guided by up to 9 reference images, 3 reference videos, and 3 audio clips; reference and image-to-video inputs cannot be mixed."
|
|
1572
|
+
},
|
|
1573
|
+
capabilities: {}
|
|
1036
1574
|
},
|
|
1037
1575
|
{
|
|
1038
1576
|
id: "minimax-h3-max-reference",
|
|
@@ -1047,7 +1585,7 @@ var VIDEO_MODELS = [
|
|
|
1047
1585
|
resolutions: ["480p", "768p"],
|
|
1048
1586
|
durations: { min: 5, max: 15 },
|
|
1049
1587
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
1050
|
-
supports: ["seed", "promptExpansion"]
|
|
1588
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
1051
1589
|
},
|
|
1052
1590
|
defaults: {
|
|
1053
1591
|
durationSeconds: 5,
|
|
@@ -1056,7 +1594,12 @@ var VIDEO_MODELS = [
|
|
|
1056
1594
|
promptExpansion: "balanced"
|
|
1057
1595
|
},
|
|
1058
1596
|
usage: { ...VIDEO_USAGE },
|
|
1059
|
-
pricingKind: "video_per_second"
|
|
1597
|
+
pricingKind: "video_per_second",
|
|
1598
|
+
display: {
|
|
1599
|
+
provider: "minimax",
|
|
1600
|
+
description: "MiniMax H3 Max reference-to-video on fal; conditions on reference images, videos, and audio. MiniMax's own docs do not list a reference mode for H3 Max."
|
|
1601
|
+
},
|
|
1602
|
+
capabilities: {}
|
|
1060
1603
|
},
|
|
1061
1604
|
{
|
|
1062
1605
|
// Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
|
|
@@ -1075,7 +1618,12 @@ var VIDEO_MODELS = [
|
|
|
1075
1618
|
},
|
|
1076
1619
|
defaults: { durationSeconds: 5, aspectRatio: "16:9" },
|
|
1077
1620
|
usage: { ...VIDEO_USAGE },
|
|
1078
|
-
pricingKind: "video_per_second"
|
|
1621
|
+
pricingKind: "video_per_second",
|
|
1622
|
+
display: {
|
|
1623
|
+
provider: "kuaishou",
|
|
1624
|
+
description: "Kuaishou Kling O1 Reference Video-to-Video; a prompt plus a 3-10 second reference video (optional reference images) generates 3-10 second clips preserving motion and camera language."
|
|
1625
|
+
},
|
|
1626
|
+
capabilities: { acceptsSourceVideo: true }
|
|
1079
1627
|
},
|
|
1080
1628
|
{
|
|
1081
1629
|
id: "hailuo-02",
|
|
@@ -1092,7 +1640,12 @@ var VIDEO_MODELS = [
|
|
|
1092
1640
|
},
|
|
1093
1641
|
defaults: { durationSeconds: 6, resolution: "768p" },
|
|
1094
1642
|
usage: { unit: "compute_seconds", modality: "VIDEO" },
|
|
1095
|
-
pricingKind: "video_per_second"
|
|
1643
|
+
pricingKind: "video_per_second",
|
|
1644
|
+
display: {
|
|
1645
|
+
provider: "minimax",
|
|
1646
|
+
description: "MiniMax Hailuo 02 text-to-video and image-to-video model with realistic physics and strong prompt following; outputs 768p at 6 or 10 seconds."
|
|
1647
|
+
},
|
|
1648
|
+
capabilities: {}
|
|
1096
1649
|
},
|
|
1097
1650
|
{
|
|
1098
1651
|
id: "higgsfield-dop-preview",
|
|
@@ -1108,7 +1661,12 @@ var VIDEO_MODELS = [
|
|
|
1108
1661
|
},
|
|
1109
1662
|
defaults: {},
|
|
1110
1663
|
usage: { ...VIDEO_USAGE },
|
|
1111
|
-
pricingKind: "video_per_second"
|
|
1664
|
+
pricingKind: "video_per_second",
|
|
1665
|
+
display: {
|
|
1666
|
+
provider: "higgsfield",
|
|
1667
|
+
description: "Higgsfield DOP image-to-video model; animates a required first-frame image from a text prompt with an optional last-frame image and motion controls."
|
|
1668
|
+
},
|
|
1669
|
+
capabilities: {}
|
|
1112
1670
|
}
|
|
1113
1671
|
];
|
|
1114
1672
|
|
|
@@ -1175,19 +1733,22 @@ function resolveTier(field, code, requested, supported, order, model, onUnsuppor
|
|
|
1175
1733
|
});
|
|
1176
1734
|
return to;
|
|
1177
1735
|
}
|
|
1178
|
-
function resolveDuration(requested, durations, model, warnings) {
|
|
1736
|
+
function resolveDuration(requested, durations, model, onUnsupported, warnings) {
|
|
1179
1737
|
if (requested === void 0 || !durations) return requested;
|
|
1180
|
-
|
|
1181
|
-
if (
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
if (to === requested) return requested;
|
|
1738
|
+
const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
|
|
1739
|
+
if (inSet) return requested;
|
|
1740
|
+
if (onUnsupported === "error") {
|
|
1741
|
+
const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
|
|
1742
|
+
throw new ModelKitError({
|
|
1743
|
+
code: "unsupported_option",
|
|
1744
|
+
message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
|
|
1745
|
+
model: model.id
|
|
1746
|
+
});
|
|
1190
1747
|
}
|
|
1748
|
+
const to = Array.isArray(durations) ? durations.reduce(
|
|
1749
|
+
(best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
|
|
1750
|
+
durations[0] ?? requested
|
|
1751
|
+
) : Math.min(Math.max(requested, durations.min), durations.max);
|
|
1191
1752
|
warnings.push({
|
|
1192
1753
|
code: "duration_coerced",
|
|
1193
1754
|
field: "durationSeconds",
|
|
@@ -1197,6 +1758,26 @@ function resolveDuration(requested, durations, model, warnings) {
|
|
|
1197
1758
|
});
|
|
1198
1759
|
return to;
|
|
1199
1760
|
}
|
|
1761
|
+
function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
|
|
1762
|
+
if (requested === void 0 || requested === "adaptive" || !supported) return requested;
|
|
1763
|
+
if (supported.includes(requested)) return requested;
|
|
1764
|
+
if (onUnsupported === "error") {
|
|
1765
|
+
throw new ModelKitError({
|
|
1766
|
+
code: "unsupported_option",
|
|
1767
|
+
message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
|
|
1768
|
+
model: model.id
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
const to = nearestAspectRatio(requested, supported);
|
|
1772
|
+
warnings.push({
|
|
1773
|
+
code: "ratio_coerced",
|
|
1774
|
+
field: "aspectRatio",
|
|
1775
|
+
from: requested,
|
|
1776
|
+
to,
|
|
1777
|
+
message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
|
|
1778
|
+
});
|
|
1779
|
+
return to;
|
|
1780
|
+
}
|
|
1200
1781
|
function compact(refs) {
|
|
1201
1782
|
return (refs ?? []).filter((r) => Boolean(r));
|
|
1202
1783
|
}
|
|
@@ -1215,17 +1796,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1215
1796
|
const warnings = [];
|
|
1216
1797
|
const c = model.constraints;
|
|
1217
1798
|
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
});
|
|
1227
|
-
merged.aspectRatio = to;
|
|
1228
|
-
}
|
|
1799
|
+
const aspectRatio = resolveAspectRatio(
|
|
1800
|
+
merged.aspectRatio,
|
|
1801
|
+
c.aspectRatios,
|
|
1802
|
+
model,
|
|
1803
|
+
onUnsupported,
|
|
1804
|
+
warnings
|
|
1805
|
+
);
|
|
1806
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1229
1807
|
const size = resolveTier(
|
|
1230
1808
|
"size",
|
|
1231
1809
|
"size_coerced",
|
|
@@ -1259,7 +1837,9 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1259
1837
|
"count",
|
|
1260
1838
|
"outputFormat",
|
|
1261
1839
|
"scaleFactor",
|
|
1262
|
-
"safetySettings"
|
|
1840
|
+
"safetySettings",
|
|
1841
|
+
"temperature",
|
|
1842
|
+
"upscale"
|
|
1263
1843
|
]);
|
|
1264
1844
|
return { request: merged, warnings };
|
|
1265
1845
|
}
|
|
@@ -1289,17 +1869,14 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1289
1869
|
delete merged.aspectRatio;
|
|
1290
1870
|
}
|
|
1291
1871
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
});
|
|
1301
|
-
merged.aspectRatio = to;
|
|
1302
|
-
}
|
|
1872
|
+
const aspectRatio = resolveAspectRatio(
|
|
1873
|
+
merged.aspectRatio,
|
|
1874
|
+
c.aspectRatios,
|
|
1875
|
+
model,
|
|
1876
|
+
onUnsupported,
|
|
1877
|
+
warnings
|
|
1878
|
+
);
|
|
1879
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1303
1880
|
const resolution = resolveTier(
|
|
1304
1881
|
"resolution",
|
|
1305
1882
|
"resolution_coerced",
|
|
@@ -1311,7 +1888,13 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1311
1888
|
warnings
|
|
1312
1889
|
);
|
|
1313
1890
|
if (resolution !== void 0) merged.resolution = resolution;
|
|
1314
|
-
const duration = resolveDuration(
|
|
1891
|
+
const duration = resolveDuration(
|
|
1892
|
+
merged.durationSeconds,
|
|
1893
|
+
c.durations,
|
|
1894
|
+
model,
|
|
1895
|
+
onUnsupported,
|
|
1896
|
+
warnings
|
|
1897
|
+
);
|
|
1315
1898
|
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1316
1899
|
const limits = c.references ?? {};
|
|
1317
1900
|
let images = trim(
|
|
@@ -1366,10 +1949,45 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1366
1949
|
"cfgScale",
|
|
1367
1950
|
"generateAudio",
|
|
1368
1951
|
"promptExpansion",
|
|
1369
|
-
"lastFrame"
|
|
1952
|
+
"lastFrame",
|
|
1953
|
+
"watermark",
|
|
1954
|
+
"safetyChecker"
|
|
1370
1955
|
]);
|
|
1371
1956
|
return { request: merged, warnings };
|
|
1372
1957
|
}
|
|
1958
|
+
function resolveAudioOptions(model, request, onUnsupported = "error") {
|
|
1959
|
+
const warnings = [];
|
|
1960
|
+
const c = model.constraints;
|
|
1961
|
+
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1962
|
+
for (const input of c.requires ?? []) {
|
|
1963
|
+
const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
|
|
1964
|
+
if (!present)
|
|
1965
|
+
throw new ModelKitError({
|
|
1966
|
+
code: "missing_input",
|
|
1967
|
+
message: `${model.id} requires ${input}`,
|
|
1968
|
+
model: model.id
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
const duration = resolveDuration(
|
|
1972
|
+
merged.durationSeconds,
|
|
1973
|
+
c.durations,
|
|
1974
|
+
model,
|
|
1975
|
+
onUnsupported,
|
|
1976
|
+
warnings
|
|
1977
|
+
);
|
|
1978
|
+
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1979
|
+
const references = trim(
|
|
1980
|
+
"references",
|
|
1981
|
+
compact(merged.references),
|
|
1982
|
+
c.references?.images ?? c.references?.total,
|
|
1983
|
+
model,
|
|
1984
|
+
warnings
|
|
1985
|
+
);
|
|
1986
|
+
if (references.length > 0) merged.references = references;
|
|
1987
|
+
else delete merged.references;
|
|
1988
|
+
dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
|
|
1989
|
+
return { request: merged, warnings };
|
|
1990
|
+
}
|
|
1373
1991
|
function dropUnsupported(req, model, warnings, fields) {
|
|
1374
1992
|
const supports = model.constraints.supports ?? [];
|
|
1375
1993
|
for (const field of fields) {
|
|
@@ -1411,6 +2029,9 @@ function hasAll(keys, names) {
|
|
|
1411
2029
|
(n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
|
|
1412
2030
|
);
|
|
1413
2031
|
}
|
|
2032
|
+
function missingEnterpriseKeys(config, names) {
|
|
2033
|
+
return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
|
|
2034
|
+
}
|
|
1414
2035
|
function resolveKeys(config, names, tier = "pro") {
|
|
1415
2036
|
if (tier === "enterprise" && hasAll(config.keys.enterprise, names))
|
|
1416
2037
|
return config.keys.enterprise;
|
|
@@ -1443,7 +2064,6 @@ function keysFromEnv(env, prefix = "") {
|
|
|
1443
2064
|
set("prodia", pick("PRODIA_API_KEY", "PRODIA_TOKEN"));
|
|
1444
2065
|
set("higgsfield", pick("HIGGSFIELD_API_KEY"));
|
|
1445
2066
|
set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
|
|
1446
|
-
set("openrouter", pick("OPENROUTER_API_KEY"));
|
|
1447
2067
|
set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
1448
2068
|
return keys;
|
|
1449
2069
|
}
|
|
@@ -1491,7 +2111,9 @@ var textBody = import_zod2.z.string();
|
|
|
1491
2111
|
function classifyHttpError(status, body, provider, model) {
|
|
1492
2112
|
const asText = textBody.safeParse(body);
|
|
1493
2113
|
const text2 = asText.success ? asText.data : JSON.stringify(body);
|
|
1494
|
-
const blocked = /
|
|
2114
|
+
const blocked = /content_policy_violation|blockReason|PROHIBITED_CONTENT|moderation_blocked|safety(?![_A-Za-z])/i.test(
|
|
2115
|
+
text2
|
|
2116
|
+
);
|
|
1495
2117
|
let code = "provider_rejected";
|
|
1496
2118
|
if (blocked) code = "content_blocked";
|
|
1497
2119
|
else if (status === 401 || status === 403) code = "auth";
|
|
@@ -1512,8 +2134,8 @@ function classifyHttpError(status, body, provider, model) {
|
|
|
1512
2134
|
}
|
|
1513
2135
|
function shouldRetry(err) {
|
|
1514
2136
|
if (err instanceof ModelKitError) return err.retryable;
|
|
1515
|
-
if (err.name === "AbortError"
|
|
1516
|
-
|
|
2137
|
+
if (err.name === "AbortError") return false;
|
|
2138
|
+
if (/ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message)) return true;
|
|
1517
2139
|
return false;
|
|
1518
2140
|
}
|
|
1519
2141
|
async function withRetry(fn, opts = {}) {
|
|
@@ -1698,6 +2320,12 @@ var import_zod4 = require("zod");
|
|
|
1698
2320
|
function isUrlRef(ref) {
|
|
1699
2321
|
return "url" in ref;
|
|
1700
2322
|
}
|
|
2323
|
+
function abortedError() {
|
|
2324
|
+
return new ModelKitError({ code: "timeout", message: "aborted", retryable: false });
|
|
2325
|
+
}
|
|
2326
|
+
function throwIfAborted(signal) {
|
|
2327
|
+
if (signal?.aborted) throw abortedError();
|
|
2328
|
+
}
|
|
1701
2329
|
function mediaRefToBase64(bytes) {
|
|
1702
2330
|
let binary = "";
|
|
1703
2331
|
const CHUNK = 32768;
|
|
@@ -1712,10 +2340,34 @@ function base64ToBytes(b64) {
|
|
|
1712
2340
|
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
1713
2341
|
return out;
|
|
1714
2342
|
}
|
|
1715
|
-
|
|
2343
|
+
function mediaRefToDataUrl(ref) {
|
|
2344
|
+
if (isUrlRef(ref)) return ref.url;
|
|
2345
|
+
return `data:${ref.mime};base64,${mediaRefToBase64(ref.bytes)}`;
|
|
2346
|
+
}
|
|
2347
|
+
var refToUrl = mediaRefToDataUrl;
|
|
2348
|
+
async function readBody(res) {
|
|
2349
|
+
const text2 = await res.text().catch(() => "");
|
|
2350
|
+
try {
|
|
2351
|
+
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
2352
|
+
return decoded.success ? decoded.data : text2;
|
|
2353
|
+
} catch {
|
|
2354
|
+
return text2;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
async function mediaRefToBytes(ref, fetch, options = {}) {
|
|
1716
2358
|
if (!isUrlRef(ref)) return { bytes: ref.bytes, mime: ref.mime };
|
|
1717
|
-
const
|
|
1718
|
-
if (
|
|
2359
|
+
const init = {};
|
|
2360
|
+
if (options.signal !== void 0) init.signal = options.signal;
|
|
2361
|
+
const res = await fetch(ref.url, init);
|
|
2362
|
+
if (!res.ok) {
|
|
2363
|
+
const text2 = await res.text().catch(() => "");
|
|
2364
|
+
throw classifyHttpError(
|
|
2365
|
+
res.status,
|
|
2366
|
+
text2,
|
|
2367
|
+
options.provider ?? "media-reference",
|
|
2368
|
+
options.model
|
|
2369
|
+
);
|
|
2370
|
+
}
|
|
1719
2371
|
const mime = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() || "image/png";
|
|
1720
2372
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
1721
2373
|
}
|
|
@@ -1773,16 +2425,6 @@ var GATEWAY_SLUGS = {
|
|
|
1773
2425
|
perplexity: "perplexity-ai",
|
|
1774
2426
|
deepseek: "deepseek"
|
|
1775
2427
|
};
|
|
1776
|
-
var OPENROUTER_VENDORS = {
|
|
1777
|
-
openai: "openai",
|
|
1778
|
-
anthropic: "anthropic",
|
|
1779
|
-
google: "google",
|
|
1780
|
-
xai: "x-ai",
|
|
1781
|
-
perplexity: "perplexity",
|
|
1782
|
-
deepseek: "deepseek",
|
|
1783
|
-
moonshot: "moonshotai",
|
|
1784
|
-
minimax: "minimax"
|
|
1785
|
-
};
|
|
1786
2428
|
function detectTextProvider(modelId) {
|
|
1787
2429
|
const id = modelId.toLowerCase();
|
|
1788
2430
|
if (id.startsWith("claude") || id.includes("anthropic.")) return "anthropic";
|
|
@@ -1799,14 +2441,17 @@ function detectTextProvider(modelId) {
|
|
|
1799
2441
|
message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
|
|
1800
2442
|
});
|
|
1801
2443
|
}
|
|
1802
|
-
function textKeyName(model,
|
|
1803
|
-
if (routing.text === "openrouter") return "openrouter";
|
|
2444
|
+
function textKeyName(model, _routing) {
|
|
1804
2445
|
return textProviderOf(model);
|
|
1805
2446
|
}
|
|
1806
2447
|
function textProviderOf(model) {
|
|
1807
2448
|
const explicit = model.providerOptions?.["modelkit"]?.["provider"];
|
|
1808
2449
|
return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
|
|
1809
2450
|
}
|
|
2451
|
+
function textUsesCloudflareGateway(model, routing) {
|
|
2452
|
+
if (routing.text !== "cloudflare") return false;
|
|
2453
|
+
return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
|
|
2454
|
+
}
|
|
1810
2455
|
function nativeClientFor(provider) {
|
|
1811
2456
|
switch (provider) {
|
|
1812
2457
|
case "openai":
|
|
@@ -1839,16 +2484,6 @@ function resolveTextRoute(ctx) {
|
|
|
1839
2484
|
retryable: false
|
|
1840
2485
|
});
|
|
1841
2486
|
}
|
|
1842
|
-
if (mode === "openrouter") {
|
|
1843
|
-
const modelId = ctx.model.providerModelId.includes("/") ? ctx.model.providerModelId : `${OPENROUTER_VENDORS[provider]}/${ctx.model.providerModelId}`;
|
|
1844
|
-
return {
|
|
1845
|
-
provider,
|
|
1846
|
-
client: "openai-compatible",
|
|
1847
|
-
modelId,
|
|
1848
|
-
keyName: "openrouter",
|
|
1849
|
-
baseURL: "https://openrouter.ai/api/v1"
|
|
1850
|
-
};
|
|
1851
|
-
}
|
|
1852
2487
|
const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
|
|
1853
2488
|
const route2 = {
|
|
1854
2489
|
provider,
|
|
@@ -1916,7 +2551,7 @@ var aiSdkTextAdapter = {
|
|
|
1916
2551
|
case "openai-compatible":
|
|
1917
2552
|
return (0, import_openai.createOpenAI)({
|
|
1918
2553
|
...settings,
|
|
1919
|
-
name: route2.provider
|
|
2554
|
+
name: route2.provider
|
|
1920
2555
|
}).chat(route2.modelId);
|
|
1921
2556
|
case "openai":
|
|
1922
2557
|
return (0, import_openai.createOpenAI)(settings)(route2.modelId);
|
|
@@ -1929,8 +2564,9 @@ function requiredKeys(model, config) {
|
|
|
1929
2564
|
if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
|
|
1930
2565
|
return ["cloudflare"];
|
|
1931
2566
|
if (model.adapter === "ai-sdk-text") {
|
|
1932
|
-
const
|
|
1933
|
-
|
|
2567
|
+
const routing = config.routing ?? {};
|
|
2568
|
+
const names = [textKeyName(model, routing)];
|
|
2569
|
+
if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
|
|
1934
2570
|
return names;
|
|
1935
2571
|
}
|
|
1936
2572
|
return ADAPTER_KEYS[model.adapter];
|
|
@@ -2004,6 +2640,11 @@ function pushIgnored(warnings, field, from, modelId) {
|
|
|
2004
2640
|
message: `${modelId} provider instance does not support ${field}; ignored`
|
|
2005
2641
|
});
|
|
2006
2642
|
}
|
|
2643
|
+
function withoutModelkit(options) {
|
|
2644
|
+
if (!options) return {};
|
|
2645
|
+
const { modelkit: _modelkit, ...rest } = options;
|
|
2646
|
+
return rest;
|
|
2647
|
+
}
|
|
2007
2648
|
function logCoercions(logger, modelId, warnings) {
|
|
2008
2649
|
if (warnings.length === 0) return;
|
|
2009
2650
|
logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
|
|
@@ -2020,7 +2661,16 @@ function createModelKit(config, adapters) {
|
|
|
2020
2661
|
message: `No adapter registered for ${model.adapter}`,
|
|
2021
2662
|
model: model.id
|
|
2022
2663
|
});
|
|
2023
|
-
const
|
|
2664
|
+
const names = requiredKeys(model, config);
|
|
2665
|
+
if (call.tier === "enterprise") {
|
|
2666
|
+
const missing = missingEnterpriseKeys(config, names);
|
|
2667
|
+
if (missing.length > 0)
|
|
2668
|
+
logger.warn(
|
|
2669
|
+
`[modelkit] enterprise keys incomplete for ${model.adapter}; using pro`,
|
|
2670
|
+
{ missing }
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
const keys = resolveKeys(config, names, call.tier);
|
|
2024
2674
|
const ctx = {
|
|
2025
2675
|
model,
|
|
2026
2676
|
keys,
|
|
@@ -2341,8 +2991,15 @@ function createModelKit(config, adapters) {
|
|
|
2341
2991
|
model: model.id
|
|
2342
2992
|
});
|
|
2343
2993
|
}
|
|
2344
|
-
const
|
|
2345
|
-
const {
|
|
2994
|
+
const { abortSignal: _signal, ...request } = req;
|
|
2995
|
+
const { request: resolved, warnings } = resolveAudioOptions(
|
|
2996
|
+
model,
|
|
2997
|
+
request,
|
|
2998
|
+
call.onUnsupported ?? "error"
|
|
2999
|
+
);
|
|
3000
|
+
logCoercions(logger, model.id, warnings);
|
|
3001
|
+
const signal = combineSignals(req.abortSignal, call.signal);
|
|
3002
|
+
const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
|
|
2346
3003
|
if (!adapter.generateAudio) {
|
|
2347
3004
|
throw new ModelKitError({
|
|
2348
3005
|
code: "unsupported_option",
|
|
@@ -2350,11 +3007,7 @@ function createModelKit(config, adapters) {
|
|
|
2350
3007
|
model: model.id
|
|
2351
3008
|
});
|
|
2352
3009
|
}
|
|
2353
|
-
const result = await adapter.generateAudio(
|
|
2354
|
-
{ ...model.defaults, ...req, model: model.id },
|
|
2355
|
-
ctx
|
|
2356
|
-
);
|
|
2357
|
-
logCoercions(logger, model.id, warnings);
|
|
3010
|
+
const result = await adapter.generateAudio(resolved, ctx);
|
|
2358
3011
|
await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
|
|
2359
3012
|
return result;
|
|
2360
3013
|
},
|
|
@@ -2375,7 +3028,7 @@ function createModelKit(config, adapters) {
|
|
|
2375
3028
|
});
|
|
2376
3029
|
return {
|
|
2377
3030
|
model,
|
|
2378
|
-
providerOptions: entry.providerOptions
|
|
3031
|
+
providerOptions: withoutModelkit(entry.providerOptions),
|
|
2379
3032
|
catalog: entry
|
|
2380
3033
|
};
|
|
2381
3034
|
},
|
|
@@ -2411,7 +3064,9 @@ function createModelKit(config, adapters) {
|
|
|
2411
3064
|
...textAbortOptions(options.abortSignal, call.signal),
|
|
2412
3065
|
model: target.languageModel,
|
|
2413
3066
|
providerOptions: {},
|
|
2414
|
-
prepareStep: steps.wrap(
|
|
3067
|
+
prepareStep: steps.wrap(
|
|
3068
|
+
options.prepareStep ?? options.experimental_prepareStep
|
|
3069
|
+
),
|
|
2415
3070
|
onFinish: async (event) => {
|
|
2416
3071
|
for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
|
|
2417
3072
|
await callerOnFinish?.(event);
|
|
@@ -2468,6 +3123,7 @@ var SEEDREAM_SIZES = {
|
|
|
2468
3123
|
"3:2": "1248x832",
|
|
2469
3124
|
"2:3": "832x1248",
|
|
2470
3125
|
"21:9": "1568x672",
|
|
3126
|
+
"9:21": "672x1568",
|
|
2471
3127
|
"4:5": "864x1080",
|
|
2472
3128
|
"5:4": "1080x864"
|
|
2473
3129
|
},
|
|
@@ -2480,16 +3136,34 @@ var SEEDREAM_SIZES = {
|
|
|
2480
3136
|
"3:2": "2496x1664",
|
|
2481
3137
|
"2:3": "1664x2496",
|
|
2482
3138
|
"21:9": "3136x1344",
|
|
3139
|
+
"9:21": "1344x3136",
|
|
2483
3140
|
"4:5": "1728x2160",
|
|
2484
3141
|
"5:4": "2160x1728"
|
|
3142
|
+
},
|
|
3143
|
+
// 4K keeps the long edge at Ark's 4096 cap (a doubled 2K entry would exceed
|
|
3144
|
+
// it); sides are multiples of 16.
|
|
3145
|
+
"4K": {
|
|
3146
|
+
"1:1": "4096x4096",
|
|
3147
|
+
"4:3": "4096x3072",
|
|
3148
|
+
"3:4": "3072x4096",
|
|
3149
|
+
"16:9": "4096x2304",
|
|
3150
|
+
"9:16": "2304x4096",
|
|
3151
|
+
"3:2": "4096x2736",
|
|
3152
|
+
"2:3": "2736x4096",
|
|
3153
|
+
"21:9": "4096x1760",
|
|
3154
|
+
"9:21": "1760x4096",
|
|
3155
|
+
"4:5": "3280x4096",
|
|
3156
|
+
"5:4": "4096x3280"
|
|
2485
3157
|
}
|
|
2486
3158
|
};
|
|
2487
3159
|
var arkAdapter = {
|
|
2488
3160
|
id: "ark",
|
|
2489
3161
|
async generateImage(req, ctx) {
|
|
3162
|
+
throwIfAborted(ctx.signal);
|
|
2490
3163
|
return generateSeedreamImage(req, ctx);
|
|
2491
3164
|
},
|
|
2492
3165
|
async generateVideo(req, ctx) {
|
|
3166
|
+
throwIfAborted(ctx.signal);
|
|
2493
3167
|
return generateSeedanceVideo(req, ctx);
|
|
2494
3168
|
}
|
|
2495
3169
|
};
|
|
@@ -2509,7 +3183,7 @@ function arkKey(ctx) {
|
|
|
2509
3183
|
function throwArkError(status, body, model) {
|
|
2510
3184
|
const parsed = import_zod5.z.string().safeParse(body);
|
|
2511
3185
|
const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
|
|
2512
|
-
if (/sensitive.?content|
|
|
3186
|
+
if (/sensitive.?content|human.?face/i.test(text2)) {
|
|
2513
3187
|
const init = {
|
|
2514
3188
|
code: "content_blocked",
|
|
2515
3189
|
message: `ark rejected the request: ${text2.slice(0, 500)}`,
|
|
@@ -2534,7 +3208,7 @@ function throwArkError(status, body, model) {
|
|
|
2534
3208
|
throw classifyHttpError(status, body, "ark", model);
|
|
2535
3209
|
}
|
|
2536
3210
|
function seedreamSize(aspect, size) {
|
|
2537
|
-
const tier = size === "
|
|
3211
|
+
const tier = size === "4K" || size === "1K" ? size : "2K";
|
|
2538
3212
|
const table = SEEDREAM_SIZES[tier];
|
|
2539
3213
|
return table[aspect ?? ""] ?? table["1:1"] ?? "2048x2048";
|
|
2540
3214
|
}
|
|
@@ -2545,10 +3219,6 @@ function sniffedImageMime(bytes) {
|
|
|
2545
3219
|
return "image/webp";
|
|
2546
3220
|
return "image/jpeg";
|
|
2547
3221
|
}
|
|
2548
|
-
function arkUrl(ref) {
|
|
2549
|
-
if ("url" in ref) return ref.url;
|
|
2550
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2551
|
-
}
|
|
2552
3222
|
var SeedreamImageSchema = import_zod5.z.object({
|
|
2553
3223
|
url: import_zod5.z.string().optional(),
|
|
2554
3224
|
b64_json: import_zod5.z.string().optional()
|
|
@@ -2575,7 +3245,7 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2575
3245
|
const key = arkKey(ctx);
|
|
2576
3246
|
const modelId = ctx.model.id;
|
|
2577
3247
|
const size = seedreamSize(req.aspectRatio, req.size);
|
|
2578
|
-
const refs = (req.references ?? []).map(
|
|
3248
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
2579
3249
|
const body = {
|
|
2580
3250
|
model: ctx.model.providerModelId,
|
|
2581
3251
|
prompt: req.prompt,
|
|
@@ -2627,10 +3297,18 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2627
3297
|
if (req.quality !== void 0) usage2.imageQuality = req.quality;
|
|
2628
3298
|
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
|
|
2629
3299
|
}
|
|
3300
|
+
var SeedanceUsageSchema = import_zod5.z.object({
|
|
3301
|
+
total_tokens: import_zod5.z.number().optional(),
|
|
3302
|
+
completion_tokens: import_zod5.z.number().optional()
|
|
3303
|
+
});
|
|
2630
3304
|
var SeedanceResponseSchema = import_zod5.z.object({
|
|
2631
3305
|
id: import_zod5.z.string().optional(),
|
|
2632
3306
|
status: import_zod5.z.string().optional(),
|
|
2633
3307
|
content: import_zod5.z.object({ video_url: import_zod5.z.string().optional() }).optional(),
|
|
3308
|
+
usage: SeedanceUsageSchema.optional(),
|
|
3309
|
+
duration: import_zod5.z.number().optional(),
|
|
3310
|
+
framespersecond: import_zod5.z.number().optional(),
|
|
3311
|
+
resolution: import_zod5.z.string().optional(),
|
|
2634
3312
|
error: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.object({ message: import_zod5.z.string().optional() })]).optional()
|
|
2635
3313
|
});
|
|
2636
3314
|
var SeedanceErrorMessageSchema = import_zod5.z.object({ message: import_zod5.z.string().optional() });
|
|
@@ -2662,42 +3340,42 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2662
3340
|
if (req.firstFrame) {
|
|
2663
3341
|
content.push({
|
|
2664
3342
|
type: "image_url",
|
|
2665
|
-
image_url: { url:
|
|
3343
|
+
image_url: { url: refToUrl(req.firstFrame) },
|
|
2666
3344
|
role: "first_frame"
|
|
2667
3345
|
});
|
|
2668
3346
|
}
|
|
2669
3347
|
if (req.lastFrame) {
|
|
2670
3348
|
content.push({
|
|
2671
3349
|
type: "image_url",
|
|
2672
|
-
image_url: { url:
|
|
3350
|
+
image_url: { url: refToUrl(req.lastFrame) },
|
|
2673
3351
|
role: "last_frame"
|
|
2674
3352
|
});
|
|
2675
3353
|
}
|
|
2676
3354
|
for (const ref of req.referenceImages ?? []) {
|
|
2677
3355
|
content.push({
|
|
2678
3356
|
type: "image_url",
|
|
2679
|
-
image_url: { url:
|
|
3357
|
+
image_url: { url: refToUrl(ref) },
|
|
2680
3358
|
role: "reference_image"
|
|
2681
3359
|
});
|
|
2682
3360
|
}
|
|
2683
3361
|
if (req.sourceVideo) {
|
|
2684
3362
|
content.push({
|
|
2685
3363
|
type: "video_url",
|
|
2686
|
-
video_url: { url:
|
|
3364
|
+
video_url: { url: refToUrl(req.sourceVideo) },
|
|
2687
3365
|
role: "reference_video"
|
|
2688
3366
|
});
|
|
2689
3367
|
}
|
|
2690
3368
|
for (const ref of req.referenceVideos ?? []) {
|
|
2691
3369
|
content.push({
|
|
2692
3370
|
type: "video_url",
|
|
2693
|
-
video_url: { url:
|
|
3371
|
+
video_url: { url: refToUrl(ref) },
|
|
2694
3372
|
role: "reference_video"
|
|
2695
3373
|
});
|
|
2696
3374
|
}
|
|
2697
3375
|
for (const ref of req.referenceAudios ?? []) {
|
|
2698
3376
|
content.push({
|
|
2699
3377
|
type: "audio_url",
|
|
2700
|
-
audio_url: { url:
|
|
3378
|
+
audio_url: { url: refToUrl(ref) },
|
|
2701
3379
|
role: "reference_audio"
|
|
2702
3380
|
});
|
|
2703
3381
|
}
|
|
@@ -2711,6 +3389,7 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2711
3389
|
if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
|
|
2712
3390
|
if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
|
|
2713
3391
|
if (req.seed !== void 0) body.seed = req.seed;
|
|
3392
|
+
if (req.watermark !== void 0) body.watermark = req.watermark;
|
|
2714
3393
|
const submit = await withRetry(async () => {
|
|
2715
3394
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
|
|
2716
3395
|
method: "POST",
|
|
@@ -2774,6 +3453,11 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2774
3453
|
"Seedance task succeeded but returned no video_url",
|
|
2775
3454
|
modelId
|
|
2776
3455
|
);
|
|
3456
|
+
const tokens = polled.usage;
|
|
3457
|
+
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
3458
|
+
usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
3459
|
+
usage2.outputTokens = tokens.completion_tokens;
|
|
3460
|
+
}
|
|
2777
3461
|
return {
|
|
2778
3462
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
2779
3463
|
usage: usage2,
|
|
@@ -2837,24 +3521,17 @@ var defaultDeps = { createFalClient: defaultCreateFalClient };
|
|
|
2837
3521
|
function createFalAdapter(deps = defaultDeps) {
|
|
2838
3522
|
return {
|
|
2839
3523
|
id: "fal",
|
|
2840
|
-
generateImage: (req, ctx) =>
|
|
2841
|
-
|
|
3524
|
+
generateImage: (req, ctx) => {
|
|
3525
|
+
throwIfAborted(ctx.signal);
|
|
3526
|
+
return generateMuseImage(req, ctx, deps);
|
|
3527
|
+
},
|
|
3528
|
+
generateVideo: (req, ctx) => {
|
|
3529
|
+
throwIfAborted(ctx.signal);
|
|
3530
|
+
return generateFalVideo(req, ctx, deps);
|
|
3531
|
+
}
|
|
2842
3532
|
};
|
|
2843
3533
|
}
|
|
2844
3534
|
var falAdapter = createFalAdapter();
|
|
2845
|
-
function refToUrl(ref) {
|
|
2846
|
-
if ("url" in ref) return ref.url;
|
|
2847
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2848
|
-
}
|
|
2849
|
-
async function readBody(res) {
|
|
2850
|
-
const text2 = await res.text().catch(() => "");
|
|
2851
|
-
try {
|
|
2852
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
2853
|
-
return decoded.success ? decoded.data : text2;
|
|
2854
|
-
} catch {
|
|
2855
|
-
return text2;
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
3535
|
var falDetailSchema = import_zod6.z.object({ detail: JsonValueSchema });
|
|
2859
3536
|
function liftDetail(body) {
|
|
2860
3537
|
const parsed = falDetailSchema.safeParse(body);
|
|
@@ -3091,8 +3768,12 @@ async function generateMuseImage(req, ctx, deps) {
|
|
|
3091
3768
|
raw: payload
|
|
3092
3769
|
};
|
|
3093
3770
|
}
|
|
3771
|
+
var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3772
|
+
"minimax/h3-max",
|
|
3773
|
+
"minimax/h3-max/reference-to-video"
|
|
3774
|
+
]);
|
|
3094
3775
|
function minimaxFamily(providerModelId) {
|
|
3095
|
-
return providerModelId.toLowerCase()
|
|
3776
|
+
return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
|
|
3096
3777
|
}
|
|
3097
3778
|
function minimaxBase(req, family) {
|
|
3098
3779
|
const resolution = (family === "h3-max" ? req.resolution ?? "768p" : req.resolution ?? "2k").toUpperCase();
|
|
@@ -3100,14 +3781,17 @@ function minimaxBase(req, family) {
|
|
|
3100
3781
|
prompt: req.prompt.trim(),
|
|
3101
3782
|
duration: req.durationSeconds ?? 5,
|
|
3102
3783
|
resolution,
|
|
3103
|
-
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3104
|
-
enable_safety_checker: true
|
|
3784
|
+
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3105
3785
|
};
|
|
3786
|
+
if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
|
|
3106
3787
|
if (req.seed !== void 0) input.seed = req.seed;
|
|
3107
3788
|
return input;
|
|
3108
3789
|
}
|
|
3790
|
+
var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3791
|
+
"fal-ai/kling-video/o1/video-to-video/reference"
|
|
3792
|
+
]);
|
|
3109
3793
|
function isKling(providerModelId) {
|
|
3110
|
-
return providerModelId.toLowerCase()
|
|
3794
|
+
return KLING_MODEL_IDS.has(providerModelId.toLowerCase());
|
|
3111
3795
|
}
|
|
3112
3796
|
function klingO1Input(req) {
|
|
3113
3797
|
const source = req.sourceVideo ? refToUrl(req.sourceVideo) : void 0;
|
|
@@ -3180,7 +3864,9 @@ async function generateFalVideo(req, ctx, deps) {
|
|
|
3180
3864
|
if (lastFrame) base.end_image_url = lastFrame;
|
|
3181
3865
|
} else {
|
|
3182
3866
|
endpoint = `minimax/${family}/text-to-video`;
|
|
3183
|
-
|
|
3867
|
+
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
3868
|
+
base.aspect_ratio = req.aspectRatio;
|
|
3869
|
+
}
|
|
3184
3870
|
}
|
|
3185
3871
|
if (ctx.routing.fal === "cloudflare-passthrough") {
|
|
3186
3872
|
return await passthroughVideoJob(ctx, req, endpoint, base);
|
|
@@ -3666,6 +4352,14 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3666
4352
|
model: modelId
|
|
3667
4353
|
});
|
|
3668
4354
|
}
|
|
4355
|
+
if (req.lastFrame !== void 0 && req.firstFrame === void 0) {
|
|
4356
|
+
throw new ModelKitError({
|
|
4357
|
+
code: "missing_input",
|
|
4358
|
+
message: `${modelId} requires firstFrame when lastFrame is set`,
|
|
4359
|
+
provider: "google-genai",
|
|
4360
|
+
model: modelId
|
|
4361
|
+
});
|
|
4362
|
+
}
|
|
3669
4363
|
const duration = req.durationSeconds ?? 8;
|
|
3670
4364
|
const personGeneration = req.firstFrame ?? refs.length > 0 ? "allow_adult" : "allow_all";
|
|
3671
4365
|
let image;
|
|
@@ -3732,7 +4426,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3732
4426
|
throwSdkError(cause, modelId);
|
|
3733
4427
|
}
|
|
3734
4428
|
};
|
|
3735
|
-
const jobId = operation.name ??
|
|
4429
|
+
const jobId = operation.name ?? crypto.randomUUID();
|
|
3736
4430
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3737
4431
|
return {
|
|
3738
4432
|
jobId,
|
|
@@ -3871,6 +4565,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3871
4565
|
});
|
|
3872
4566
|
}
|
|
3873
4567
|
for (const ref of videos) {
|
|
4568
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3874
4569
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "video/mp4", modelId);
|
|
3875
4570
|
parts.push({
|
|
3876
4571
|
type: "video",
|
|
@@ -3879,6 +4574,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3879
4574
|
});
|
|
3880
4575
|
}
|
|
3881
4576
|
if (req.firstFrame) {
|
|
4577
|
+
if (req.firstFrame.label !== void 0)
|
|
4578
|
+
parts.push({ type: "text", text: req.firstFrame.label });
|
|
3882
4579
|
const media = await resolveMedia(
|
|
3883
4580
|
req.firstFrame,
|
|
3884
4581
|
ctx.fetch,
|
|
@@ -3897,6 +4594,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3897
4594
|
}
|
|
3898
4595
|
}
|
|
3899
4596
|
for (const ref of images) {
|
|
4597
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3900
4598
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
|
|
3901
4599
|
if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
|
|
3902
4600
|
parts.push({
|
|
@@ -3940,7 +4638,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3940
4638
|
} finally {
|
|
3941
4639
|
await cleanupUploads();
|
|
3942
4640
|
}
|
|
3943
|
-
const jobId = interaction.id ??
|
|
4641
|
+
const jobId = interaction.id ?? crypto.randomUUID();
|
|
3944
4642
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3945
4643
|
const getInteraction = async () => {
|
|
3946
4644
|
try {
|
|
@@ -4166,11 +4864,11 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4166
4864
|
const model = google(ctx.model.providerModelId);
|
|
4167
4865
|
const content = [];
|
|
4168
4866
|
for (const ref of req.references ?? []) {
|
|
4867
|
+
if (ref.label !== void 0) content.push({ type: "text", text: ref.label });
|
|
4169
4868
|
if ("url" in ref) content.push({ type: "image", image: ref.url });
|
|
4170
4869
|
else content.push({ type: "image", image: ref.bytes, mediaType: ref.mime });
|
|
4171
4870
|
}
|
|
4172
4871
|
content.push({ type: "text", text: req.prompt });
|
|
4173
|
-
void ctx.call.postCropToAspect;
|
|
4174
4872
|
const imageConfig = {};
|
|
4175
4873
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4176
4874
|
imageConfig.aspectRatio = req.aspectRatio;
|
|
@@ -4186,7 +4884,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4186
4884
|
const timeout = AbortSignal.timeout(GEMINI_IMAGE_TIMEOUT_MS);
|
|
4187
4885
|
const signal = ctx.signal !== void 0 ? AbortSignal.any([ctx.signal, timeout]) : timeout;
|
|
4188
4886
|
try {
|
|
4189
|
-
|
|
4887
|
+
const genOptions = {
|
|
4190
4888
|
model,
|
|
4191
4889
|
messages: [{ role: "user", content }],
|
|
4192
4890
|
maxRetries: 0,
|
|
@@ -4194,7 +4892,9 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4194
4892
|
google: googleOptions
|
|
4195
4893
|
},
|
|
4196
4894
|
abortSignal: signal
|
|
4197
|
-
}
|
|
4895
|
+
};
|
|
4896
|
+
if (req.temperature !== void 0) genOptions.temperature = req.temperature;
|
|
4897
|
+
return await deps.runTextGeneration(genOptions);
|
|
4198
4898
|
} catch (cause) {
|
|
4199
4899
|
throw toProviderError(cause, ctx);
|
|
4200
4900
|
}
|
|
@@ -4398,26 +5098,14 @@ function headers(ctx) {
|
|
|
4398
5098
|
const { key, secret } = credentials(ctx);
|
|
4399
5099
|
return { "Content-Type": "application/json", "hf-api-key": key, "hf-secret": secret };
|
|
4400
5100
|
}
|
|
4401
|
-
function refToUrl2(ref) {
|
|
4402
|
-
if ("url" in ref) return ref.url;
|
|
4403
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
4404
|
-
}
|
|
4405
|
-
async function readBody2(res) {
|
|
4406
|
-
const text2 = await res.text().catch(() => "");
|
|
4407
|
-
try {
|
|
4408
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
4409
|
-
return decoded.success ? decoded.data : text2;
|
|
4410
|
-
} catch {
|
|
4411
|
-
return text2;
|
|
4412
|
-
}
|
|
4413
|
-
}
|
|
4414
5101
|
function klingEndpoint(providerModelId) {
|
|
4415
5102
|
if (providerModelId.startsWith("http")) return providerModelId;
|
|
4416
5103
|
const path = providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId;
|
|
4417
5104
|
return `${PLATFORM}/${path}`;
|
|
4418
5105
|
}
|
|
4419
|
-
|
|
4420
|
-
|
|
5106
|
+
var DOP_MODEL_IDS = /* @__PURE__ */ new Set(["dop", "dop-preview"]);
|
|
5107
|
+
function higgsfieldVideoKind(providerModelId) {
|
|
5108
|
+
return DOP_MODEL_IDS.has(providerModelId.toLowerCase()) ? "dop" : "kling";
|
|
4421
5109
|
}
|
|
4422
5110
|
function videoUsage3(ctx, req, duration) {
|
|
4423
5111
|
const event = {
|
|
@@ -4461,12 +5149,12 @@ async function createRequest(ctx, url, init) {
|
|
|
4461
5149
|
throw classifyThrown("higgsfield", cause, ctx.model.id);
|
|
4462
5150
|
}
|
|
4463
5151
|
if (!res.ok) {
|
|
4464
|
-
throw classifyHttpError(res.status, await
|
|
5152
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4465
5153
|
}
|
|
4466
5154
|
return res;
|
|
4467
5155
|
}
|
|
4468
5156
|
async function generateKlingVideo(req, ctx) {
|
|
4469
|
-
const firstFrame = req.firstFrame ?
|
|
5157
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4470
5158
|
if (!firstFrame) {
|
|
4471
5159
|
throw new ModelKitError({
|
|
4472
5160
|
code: "missing_input",
|
|
@@ -4485,7 +5173,7 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4485
5173
|
if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
|
|
4486
5174
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4487
5175
|
body.aspect_ratio = req.aspectRatio;
|
|
4488
|
-
if (req.lastFrame) body.last_image_url =
|
|
5176
|
+
if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
|
|
4489
5177
|
const endpoint = klingEndpoint(ctx.model.providerModelId);
|
|
4490
5178
|
const retryOptions = {};
|
|
4491
5179
|
if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
|
|
@@ -4511,9 +5199,9 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4511
5199
|
} catch {
|
|
4512
5200
|
return void 0;
|
|
4513
5201
|
}
|
|
4514
|
-
if (res.status >= 500) return void 0;
|
|
5202
|
+
if (res.status === 429 || res.status >= 500) return void 0;
|
|
4515
5203
|
if (!res.ok) {
|
|
4516
|
-
throw classifyHttpError(res.status, await
|
|
5204
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4517
5205
|
}
|
|
4518
5206
|
const payload = JsonValueSchema.parse(await res.json());
|
|
4519
5207
|
const parsed = klingStatusSchema.safeParse(payload);
|
|
@@ -4620,7 +5308,7 @@ function dopUrl(body) {
|
|
|
4620
5308
|
var dopCreateSchema = import_zod10.z.object({ id: import_zod10.z.string() });
|
|
4621
5309
|
var dopStatusSchema = import_zod10.z.object({ status: import_zod10.z.string().optional() });
|
|
4622
5310
|
async function generateDopVideo(req, ctx) {
|
|
4623
|
-
const firstFrame = req.firstFrame ?
|
|
5311
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4624
5312
|
if (!firstFrame) {
|
|
4625
5313
|
throw new ModelKitError({
|
|
4626
5314
|
code: "missing_input",
|
|
@@ -4640,7 +5328,7 @@ async function generateDopVideo(req, ctx) {
|
|
|
4640
5328
|
webhook: null
|
|
4641
5329
|
};
|
|
4642
5330
|
if (req.lastFrame) {
|
|
4643
|
-
params.input_images_end = [{ type: "image_url", image_url:
|
|
5331
|
+
params.input_images_end = [{ type: "image_url", image_url: refToUrl(req.lastFrame) }];
|
|
4644
5332
|
}
|
|
4645
5333
|
if (req.seed !== void 0) params.seed = req.seed;
|
|
4646
5334
|
const retryOptions = {};
|
|
@@ -4730,7 +5418,10 @@ async function generateDopVideo(req, ctx) {
|
|
|
4730
5418
|
}
|
|
4731
5419
|
var higgsfieldAdapter = {
|
|
4732
5420
|
id: "higgsfield",
|
|
4733
|
-
generateVideo: (req, ctx) =>
|
|
5421
|
+
generateVideo: (req, ctx) => {
|
|
5422
|
+
throwIfAborted(ctx.signal);
|
|
5423
|
+
return higgsfieldVideoKind(ctx.model.providerModelId) === "dop" ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx);
|
|
5424
|
+
}
|
|
4734
5425
|
};
|
|
4735
5426
|
|
|
4736
5427
|
// src/adapters/openai-image.ts
|
|
@@ -4825,6 +5516,7 @@ var openaiUsageSchema = import_zod11.z.object({
|
|
|
4825
5516
|
var openaiImageAdapter = {
|
|
4826
5517
|
id: "openai-image",
|
|
4827
5518
|
async generateImage(req, ctx) {
|
|
5519
|
+
throwIfAborted(ctx.signal);
|
|
4828
5520
|
const apiKey = ctx.keys.openai;
|
|
4829
5521
|
if (!apiKey)
|
|
4830
5522
|
throw new ModelKitError({
|
|
@@ -4834,6 +5526,13 @@ var openaiImageAdapter = {
|
|
|
4834
5526
|
model: ctx.model.id,
|
|
4835
5527
|
retryable: false
|
|
4836
5528
|
});
|
|
5529
|
+
if ((req.references ?? []).some((ref) => ref.label !== void 0)) {
|
|
5530
|
+
ctx.warnings.push({
|
|
5531
|
+
code: "option_ignored",
|
|
5532
|
+
field: "references.label",
|
|
5533
|
+
message: "openai-image cannot express reference labels; ignoring them"
|
|
5534
|
+
});
|
|
5535
|
+
}
|
|
4837
5536
|
const client2 = new import_openai2.default({ apiKey, fetch: ctx.fetch, maxRetries: 0 });
|
|
4838
5537
|
const size = req.exactSize !== void 0 ? req.exactSize : req.aspectRatio === void 0 || req.aspectRatio === "adaptive" ? void 0 : aspectRatioToSize(req.aspectRatio, req.size ?? "1K");
|
|
4839
5538
|
const refs = req.references ?? [];
|
|
@@ -4847,24 +5546,34 @@ var openaiImageAdapter = {
|
|
|
4847
5546
|
try {
|
|
4848
5547
|
if (!isEdit) {
|
|
4849
5548
|
if (size !== void 0) {
|
|
4850
|
-
return await client2.images.generate(
|
|
5549
|
+
return await client2.images.generate(
|
|
5550
|
+
{
|
|
5551
|
+
model: ctx.model.providerModelId,
|
|
5552
|
+
prompt: req.prompt,
|
|
5553
|
+
size,
|
|
5554
|
+
quality: sdkQuality,
|
|
5555
|
+
...count
|
|
5556
|
+
},
|
|
5557
|
+
{ signal: ctx.signal }
|
|
5558
|
+
);
|
|
5559
|
+
}
|
|
5560
|
+
return await client2.images.generate(
|
|
5561
|
+
{
|
|
4851
5562
|
model: ctx.model.providerModelId,
|
|
4852
5563
|
prompt: req.prompt,
|
|
4853
|
-
size,
|
|
4854
5564
|
quality: sdkQuality,
|
|
4855
5565
|
...count
|
|
4856
|
-
}
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
model: ctx.model.providerModelId,
|
|
4860
|
-
prompt: req.prompt,
|
|
4861
|
-
quality: sdkQuality,
|
|
4862
|
-
...count
|
|
4863
|
-
});
|
|
5566
|
+
},
|
|
5567
|
+
{ signal: ctx.signal }
|
|
5568
|
+
);
|
|
4864
5569
|
}
|
|
4865
5570
|
const files = await Promise.all(
|
|
4866
5571
|
refs.slice(0, MAX_EDIT_REFERENCES).map(async (ref, i) => {
|
|
4867
|
-
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch
|
|
5572
|
+
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch, {
|
|
5573
|
+
signal: ctx.signal,
|
|
5574
|
+
provider: "openai-image",
|
|
5575
|
+
model: ctx.model.id
|
|
5576
|
+
});
|
|
4868
5577
|
const ext = mime.includes("jpeg") ? "jpg" : mime.includes("webp") ? "webp" : "png";
|
|
4869
5578
|
return new File([bytes], `ref-${i}.${ext}`, { type: mime });
|
|
4870
5579
|
})
|
|
@@ -4872,22 +5581,28 @@ var openaiImageAdapter = {
|
|
|
4872
5581
|
const single = files.length === 1 ? files[0] : void 0;
|
|
4873
5582
|
const imageInput = single ?? files;
|
|
4874
5583
|
if (size !== void 0) {
|
|
4875
|
-
return await client2.images.edit(
|
|
5584
|
+
return await client2.images.edit(
|
|
5585
|
+
{
|
|
5586
|
+
model: ctx.model.providerModelId,
|
|
5587
|
+
image: imageInput,
|
|
5588
|
+
prompt: req.prompt,
|
|
5589
|
+
size,
|
|
5590
|
+
quality: sdkQuality,
|
|
5591
|
+
...count
|
|
5592
|
+
},
|
|
5593
|
+
{ signal: ctx.signal }
|
|
5594
|
+
);
|
|
5595
|
+
}
|
|
5596
|
+
return await client2.images.edit(
|
|
5597
|
+
{
|
|
4876
5598
|
model: ctx.model.providerModelId,
|
|
4877
5599
|
image: imageInput,
|
|
4878
5600
|
prompt: req.prompt,
|
|
4879
|
-
size,
|
|
4880
5601
|
quality: sdkQuality,
|
|
4881
5602
|
...count
|
|
4882
|
-
}
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
model: ctx.model.providerModelId,
|
|
4886
|
-
image: imageInput,
|
|
4887
|
-
prompt: req.prompt,
|
|
4888
|
-
quality: sdkQuality,
|
|
4889
|
-
...count
|
|
4890
|
-
});
|
|
5603
|
+
},
|
|
5604
|
+
{ signal: ctx.signal }
|
|
5605
|
+
);
|
|
4891
5606
|
} catch (cause) {
|
|
4892
5607
|
throw toProviderError2(cause, ctx);
|
|
4893
5608
|
}
|
|
@@ -4969,7 +5684,7 @@ async function refToBytes(ctx, ref) {
|
|
|
4969
5684
|
if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
|
|
4970
5685
|
let res;
|
|
4971
5686
|
try {
|
|
4972
|
-
res = await ctx.fetch(ref.url);
|
|
5687
|
+
res = await ctx.fetch(ref.url, ctx.signal ? { signal: ctx.signal } : {});
|
|
4973
5688
|
} catch (cause) {
|
|
4974
5689
|
throw classifyThrown("prodia", cause, ctx.model.id);
|
|
4975
5690
|
}
|
|
@@ -5015,6 +5730,12 @@ function emptyImage() {
|
|
|
5015
5730
|
retryable: false
|
|
5016
5731
|
});
|
|
5017
5732
|
}
|
|
5733
|
+
function inputExtension(mime) {
|
|
5734
|
+
if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
|
|
5735
|
+
if (mime.includes("webp")) return "webp";
|
|
5736
|
+
if (mime.includes("gif")) return "gif";
|
|
5737
|
+
return "png";
|
|
5738
|
+
}
|
|
5018
5739
|
function isBgRemove(providerModelId) {
|
|
5019
5740
|
const id = providerModelId.toLowerCase();
|
|
5020
5741
|
return id.includes("remove-background") || id.includes("bg-remove");
|
|
@@ -5023,6 +5744,7 @@ function isKlein(providerModelId) {
|
|
|
5023
5744
|
return providerModelId.toLowerCase().includes("klein");
|
|
5024
5745
|
}
|
|
5025
5746
|
async function generateProdiaImage(req, ctx) {
|
|
5747
|
+
throwIfAborted(ctx.signal);
|
|
5026
5748
|
const key = ctx.keys.prodia;
|
|
5027
5749
|
if (!key) {
|
|
5028
5750
|
throw new ModelKitError({
|
|
@@ -5121,7 +5843,9 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5121
5843
|
"input",
|
|
5122
5844
|
// Uint8Array<ArrayBufferLike> is not a valid BlobPart under the
|
|
5123
5845
|
// strict lib types; copy into a fresh ArrayBuffer-backed view.
|
|
5124
|
-
new File([new Uint8Array(input.bytes)], `input-${i}.
|
|
5846
|
+
new File([new Uint8Array(input.bytes)], `input-${i}.${inputExtension(input.mime)}`, {
|
|
5847
|
+
type: input.mime
|
|
5848
|
+
})
|
|
5125
5849
|
);
|
|
5126
5850
|
});
|
|
5127
5851
|
const retryOpts = {
|
|
@@ -5136,11 +5860,13 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5136
5860
|
res = await withRetry(async () => {
|
|
5137
5861
|
let attemptRes;
|
|
5138
5862
|
try {
|
|
5139
|
-
|
|
5863
|
+
const init = {
|
|
5140
5864
|
method: "POST",
|
|
5141
5865
|
headers: { Authorization: `Bearer ${key}`, Accept: accept },
|
|
5142
5866
|
body: form
|
|
5143
|
-
}
|
|
5867
|
+
};
|
|
5868
|
+
if (ctx.signal !== void 0) init.signal = ctx.signal;
|
|
5869
|
+
attemptRes = await ctx.fetch(PRODIA_JOB_URL, init);
|
|
5144
5870
|
} catch (err) {
|
|
5145
5871
|
throw classifyThrown("prodia", err, ctx.model.id);
|
|
5146
5872
|
}
|
|
@@ -5201,11 +5927,7 @@ function client(ctx, deps) {
|
|
|
5201
5927
|
retryable: false
|
|
5202
5928
|
});
|
|
5203
5929
|
}
|
|
5204
|
-
return deps.createReplicateClient({ auth: token });
|
|
5205
|
-
}
|
|
5206
|
-
function refToUrl3(ref) {
|
|
5207
|
-
if ("url" in ref) return ref.url;
|
|
5208
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5930
|
+
return deps.createReplicateClient({ auth: token, fetch: ctx.fetch });
|
|
5209
5931
|
}
|
|
5210
5932
|
function route(providerModelId) {
|
|
5211
5933
|
if (providerModelId.includes(":")) {
|
|
@@ -5225,8 +5947,9 @@ function replicateError(cause, ctx) {
|
|
|
5225
5947
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
5226
5948
|
return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
|
|
5227
5949
|
}
|
|
5228
|
-
function
|
|
5229
|
-
|
|
5950
|
+
function baseModelId(providerModelId) {
|
|
5951
|
+
const colon = providerModelId.indexOf(":");
|
|
5952
|
+
return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
|
|
5230
5953
|
}
|
|
5231
5954
|
function predictionErrorBody(cause) {
|
|
5232
5955
|
const parsed = JsonValueSchema.safeParse(cause);
|
|
@@ -5274,6 +5997,7 @@ function noOutput() {
|
|
|
5274
5997
|
});
|
|
5275
5998
|
}
|
|
5276
5999
|
async function runPrediction(ctx, input, deps) {
|
|
6000
|
+
throwIfAborted(ctx.signal);
|
|
5277
6001
|
const api = client(ctx, deps);
|
|
5278
6002
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5279
6003
|
let prediction;
|
|
@@ -5281,12 +6005,14 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5281
6005
|
prediction = await withRetry(
|
|
5282
6006
|
async () => {
|
|
5283
6007
|
try {
|
|
5284
|
-
return await api.predictions.create(
|
|
6008
|
+
return await api.predictions.create(
|
|
6009
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
6010
|
+
);
|
|
5285
6011
|
} catch (cause) {
|
|
5286
6012
|
throw replicateError(cause, ctx);
|
|
5287
6013
|
}
|
|
5288
6014
|
},
|
|
5289
|
-
|
|
6015
|
+
{ attempts: 1 }
|
|
5290
6016
|
);
|
|
5291
6017
|
} catch (cause) {
|
|
5292
6018
|
throw replicateError(cause, ctx);
|
|
@@ -5299,7 +6025,10 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5299
6025
|
const done = await pollUntil(async () => {
|
|
5300
6026
|
let current;
|
|
5301
6027
|
try {
|
|
5302
|
-
current = await api.predictions.get(
|
|
6028
|
+
current = await api.predictions.get(
|
|
6029
|
+
prediction.id,
|
|
6030
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
6031
|
+
);
|
|
5303
6032
|
} catch (cause) {
|
|
5304
6033
|
throw replicateError(cause, ctx);
|
|
5305
6034
|
}
|
|
@@ -5366,21 +6095,32 @@ async function download(ctx, url) {
|
|
|
5366
6095
|
const mime = res.headers.get("content-type") ?? "image/png";
|
|
5367
6096
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
5368
6097
|
}
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
}
|
|
5376
|
-
function
|
|
5377
|
-
return
|
|
5378
|
-
}
|
|
5379
|
-
|
|
5380
|
-
|
|
6098
|
+
var REPLICATE_IMAGE_KINDS = {
|
|
6099
|
+
"topazlabs/image-upscale": "topaz",
|
|
6100
|
+
"philz1337x/crystal-upscaler": "upscaler",
|
|
6101
|
+
"wan-video/wan-2.7-image-pro": "wan",
|
|
6102
|
+
"qwen/qwen-image-2-pro": "qwen-image",
|
|
6103
|
+
"qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
|
|
6104
|
+
};
|
|
6105
|
+
function imageKind(providerModelId) {
|
|
6106
|
+
return REPLICATE_IMAGE_KINDS[baseModelId(providerModelId)] ?? "generic";
|
|
6107
|
+
}
|
|
6108
|
+
var REPLICATE_VIDEO_KINDS = {
|
|
6109
|
+
"kling-video/v2.5-turbo/pro/image-to-video": "kling",
|
|
6110
|
+
"kling-video/v3.0/pro/image-to-video": "kling",
|
|
6111
|
+
"kwaivgi/kling-v3-video": "kling",
|
|
6112
|
+
"kwaivgi/kling-v3-omni-video": "kling-omni",
|
|
6113
|
+
"minimax/hailuo-02": "hailuo"
|
|
6114
|
+
};
|
|
6115
|
+
function videoKind(providerModelId) {
|
|
6116
|
+
return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)] ?? "wan";
|
|
5381
6117
|
}
|
|
5382
|
-
|
|
5383
|
-
|
|
6118
|
+
var REPLICATE_AUDIO_KINDS = {
|
|
6119
|
+
"zsxkib/mmaudio": "mmaudio",
|
|
6120
|
+
"elevenlabs/music": "elevenlabs"
|
|
6121
|
+
};
|
|
6122
|
+
function audioKind(providerModelId) {
|
|
6123
|
+
return REPLICATE_AUDIO_KINDS[baseModelId(providerModelId)] ?? "lyria";
|
|
5384
6124
|
}
|
|
5385
6125
|
var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
|
|
5386
6126
|
"1:1",
|
|
@@ -5423,87 +6163,113 @@ function wanImageSize(aspectRatio, size) {
|
|
|
5423
6163
|
async function generateReplicateImage(req, ctx, deps) {
|
|
5424
6164
|
const id = ctx.model.providerModelId;
|
|
5425
6165
|
let input;
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
6166
|
+
switch (imageKind(id)) {
|
|
6167
|
+
case "topaz": {
|
|
6168
|
+
const first = (req.references ?? [])[0];
|
|
6169
|
+
if (!first) {
|
|
6170
|
+
throw new ModelKitError({
|
|
6171
|
+
code: "missing_input",
|
|
6172
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
6173
|
+
provider: "replicate",
|
|
6174
|
+
model: ctx.model.id,
|
|
6175
|
+
retryable: false
|
|
6176
|
+
});
|
|
6177
|
+
}
|
|
6178
|
+
let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
|
|
6179
|
+
if (format !== "png" && format !== "jpg") {
|
|
6180
|
+
ctx.warnings.push({
|
|
6181
|
+
code: "option_ignored",
|
|
6182
|
+
field: "outputFormat",
|
|
6183
|
+
from: format,
|
|
6184
|
+
message: "topazlabs/image-upscale supports only png and jpg; using png"
|
|
6185
|
+
});
|
|
6186
|
+
format = "png";
|
|
6187
|
+
}
|
|
6188
|
+
const upscale = req.upscale;
|
|
6189
|
+
const topaz = {
|
|
6190
|
+
image: refToUrl(first),
|
|
6191
|
+
enhance_model: upscale?.enhanceModel ?? "Standard V2",
|
|
6192
|
+
output_format: format,
|
|
6193
|
+
upscale_factor: `${req.scaleFactor ?? 2}x`,
|
|
6194
|
+
face_enhancement: upscale?.faceEnhancement ?? false
|
|
6195
|
+
};
|
|
6196
|
+
if (upscale?.subjectDetection !== void 0)
|
|
6197
|
+
topaz.subject_detection = upscale.subjectDetection;
|
|
6198
|
+
if (upscale?.faceEnhancementCreativity !== void 0)
|
|
6199
|
+
topaz.face_enhancement_creativity = upscale.faceEnhancementCreativity;
|
|
6200
|
+
if (upscale?.faceEnhancementStrength !== void 0)
|
|
6201
|
+
topaz.face_enhancement_strength = upscale.faceEnhancementStrength;
|
|
6202
|
+
input = topaz;
|
|
6203
|
+
break;
|
|
5436
6204
|
}
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
6205
|
+
case "upscaler": {
|
|
6206
|
+
const first = (req.references ?? [])[0];
|
|
6207
|
+
if (!first) {
|
|
6208
|
+
throw new ModelKitError({
|
|
6209
|
+
code: "missing_input",
|
|
6210
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
6211
|
+
provider: "replicate",
|
|
6212
|
+
model: ctx.model.id,
|
|
6213
|
+
retryable: false
|
|
6214
|
+
});
|
|
6215
|
+
}
|
|
6216
|
+
const imageInput = { prompt: req.prompt };
|
|
6217
|
+
imageInput.image = refToUrl(first);
|
|
6218
|
+
imageInput.creativity = 0;
|
|
6219
|
+
imageInput.scale_factor = 2;
|
|
6220
|
+
imageInput.output_format = "png";
|
|
6221
|
+
input = imageInput;
|
|
6222
|
+
break;
|
|
5446
6223
|
}
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
} else if (isUpscaler(id)) {
|
|
5455
|
-
const refs = req.references ?? [];
|
|
5456
|
-
const first = refs[0];
|
|
5457
|
-
if (!first) {
|
|
5458
|
-
throw new ModelKitError({
|
|
5459
|
-
code: "missing_input",
|
|
5460
|
-
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
5461
|
-
provider: "replicate",
|
|
5462
|
-
model: ctx.model.id,
|
|
5463
|
-
retryable: false
|
|
5464
|
-
});
|
|
6224
|
+
case "wan": {
|
|
6225
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6226
|
+
const imageInput = { prompt: req.prompt };
|
|
6227
|
+
if (refs.length > 0) imageInput.images = refs;
|
|
6228
|
+
imageInput.size = wanImageSize(req.aspectRatio, req.size);
|
|
6229
|
+
input = imageInput;
|
|
6230
|
+
break;
|
|
5465
6231
|
}
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
} else if (isQwen(id)) {
|
|
5479
|
-
const refs = (req.references ?? []).map(refToUrl3);
|
|
5480
|
-
const firstUrl = refs[0];
|
|
5481
|
-
const imageInput = { prompt: req.prompt };
|
|
5482
|
-
if (firstUrl !== void 0) {
|
|
5483
|
-
imageInput.image = firstUrl;
|
|
5484
|
-
if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
|
|
6232
|
+
case "qwen-image": {
|
|
6233
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6234
|
+
const firstUrl = refs[0];
|
|
6235
|
+
const imageInput = { prompt: req.prompt };
|
|
6236
|
+
if (firstUrl !== void 0) {
|
|
6237
|
+
imageInput.image = firstUrl;
|
|
6238
|
+
imageInput.match_input_image = true;
|
|
6239
|
+
} else if (req.aspectRatio !== void 0 && QWEN_IMAGE_RATIOS.has(req.aspectRatio)) {
|
|
6240
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
6241
|
+
}
|
|
6242
|
+
input = imageInput;
|
|
6243
|
+
break;
|
|
5485
6244
|
}
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
6245
|
+
case "qwen-edit": {
|
|
6246
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6247
|
+
const firstUrl = refs[0];
|
|
6248
|
+
const imageInput = { prompt: req.prompt };
|
|
6249
|
+
if (firstUrl !== void 0) imageInput.image = firstUrl;
|
|
6250
|
+
if (req.aspectRatio !== void 0) {
|
|
6251
|
+
if (QWEN_EDIT_RATIOS.has(req.aspectRatio))
|
|
6252
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
6253
|
+
else
|
|
6254
|
+
ctx.warnings.push({
|
|
6255
|
+
code: "option_ignored",
|
|
6256
|
+
field: "aspectRatio",
|
|
6257
|
+
from: req.aspectRatio,
|
|
6258
|
+
message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6261
|
+
if (req.outputFormat !== void 0) {
|
|
6262
|
+
imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
|
|
6263
|
+
}
|
|
6264
|
+
input = imageInput;
|
|
6265
|
+
break;
|
|
5496
6266
|
}
|
|
5497
|
-
|
|
5498
|
-
|
|
6267
|
+
default: {
|
|
6268
|
+
const first = (req.references ?? [])[0];
|
|
6269
|
+
const imageInput = { prompt: req.prompt };
|
|
6270
|
+
if (first) imageInput.image = refToUrl(first);
|
|
6271
|
+
input = imageInput;
|
|
5499
6272
|
}
|
|
5500
|
-
input = imageInput;
|
|
5501
|
-
} else {
|
|
5502
|
-
const refs = req.references ?? [];
|
|
5503
|
-
const first = refs[0];
|
|
5504
|
-
const imageInput = { prompt: req.prompt };
|
|
5505
|
-
if (first) imageInput.image = refToUrl3(first);
|
|
5506
|
-
input = imageInput;
|
|
5507
6273
|
}
|
|
5508
6274
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5509
6275
|
const file = await download(ctx, url);
|
|
@@ -5520,8 +6286,8 @@ function wanSize(aspectRatio) {
|
|
|
5520
6286
|
return w > h ? "2048*1152" : "1536*2048";
|
|
5521
6287
|
}
|
|
5522
6288
|
function klingInput(req) {
|
|
5523
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5524
|
-
if (req.lastFrame) images.push(
|
|
6289
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
6290
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5525
6291
|
const input = {
|
|
5526
6292
|
prompt: req.prompt,
|
|
5527
6293
|
duration: req.durationSeconds ?? 10,
|
|
@@ -5539,13 +6305,18 @@ function klingInput(req) {
|
|
|
5539
6305
|
if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
|
|
5540
6306
|
return input;
|
|
5541
6307
|
}
|
|
6308
|
+
function klingOmniMode(req) {
|
|
6309
|
+
if (req.resolution === "1080p") return "pro";
|
|
6310
|
+
if (req.resolution === "720p") return "standard";
|
|
6311
|
+
return req.mode ?? "standard";
|
|
6312
|
+
}
|
|
5542
6313
|
function klingOmniInput(req) {
|
|
5543
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5544
|
-
if (req.lastFrame) images.push(
|
|
6314
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
6315
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5545
6316
|
const input = {
|
|
5546
6317
|
prompt: req.prompt,
|
|
5547
6318
|
duration: req.durationSeconds ?? 10,
|
|
5548
|
-
mode: req
|
|
6319
|
+
mode: klingOmniMode(req),
|
|
5549
6320
|
generate_audio: req.generateAudio ?? false
|
|
5550
6321
|
};
|
|
5551
6322
|
const startImage = images[0];
|
|
@@ -5556,7 +6327,7 @@ function klingOmniInput(req) {
|
|
|
5556
6327
|
} else if (req.aspectRatio !== "adaptive") {
|
|
5557
6328
|
input.aspect_ratio = req.aspectRatio ?? "16:9";
|
|
5558
6329
|
}
|
|
5559
|
-
const refs = (req.referenceImages ?? []).map(
|
|
6330
|
+
const refs = (req.referenceImages ?? []).map(refToUrl);
|
|
5560
6331
|
if (refs.length > 0) input.reference_images = refs;
|
|
5561
6332
|
return input;
|
|
5562
6333
|
}
|
|
@@ -5567,8 +6338,8 @@ function hailuoInput(req) {
|
|
|
5567
6338
|
resolution: req.resolution ?? "768p",
|
|
5568
6339
|
prompt_optimizer: true
|
|
5569
6340
|
};
|
|
5570
|
-
if (req.firstFrame) input.first_frame_image =
|
|
5571
|
-
if (req.lastFrame) input.last_frame_image =
|
|
6341
|
+
if (req.firstFrame) input.first_frame_image = refToUrl(req.firstFrame);
|
|
6342
|
+
if (req.lastFrame) input.last_frame_image = refToUrl(req.lastFrame);
|
|
5572
6343
|
return input;
|
|
5573
6344
|
}
|
|
5574
6345
|
function wanInput(req) {
|
|
@@ -5577,12 +6348,13 @@ function wanInput(req) {
|
|
|
5577
6348
|
duration: req.durationSeconds ?? 5,
|
|
5578
6349
|
size: wanSize(req.aspectRatio)
|
|
5579
6350
|
};
|
|
5580
|
-
if (req.firstFrame) input.image =
|
|
6351
|
+
if (req.firstFrame) input.image = refToUrl(req.firstFrame);
|
|
5581
6352
|
return input;
|
|
5582
6353
|
}
|
|
5583
6354
|
async function generateReplicateVideo(req, ctx, deps) {
|
|
5584
|
-
|
|
5585
|
-
const
|
|
6355
|
+
throwIfAborted(ctx.signal);
|
|
6356
|
+
const kind = videoKind(ctx.model.providerModelId);
|
|
6357
|
+
const input = kind === "kling" ? klingInput(req) : kind === "kling-omni" ? klingOmniInput(req) : kind === "hailuo" ? hailuoInput(req) : wanInput(req);
|
|
5586
6358
|
const api = client(ctx, deps);
|
|
5587
6359
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5588
6360
|
let prediction;
|
|
@@ -5590,12 +6362,14 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5590
6362
|
prediction = await withRetry(
|
|
5591
6363
|
async () => {
|
|
5592
6364
|
try {
|
|
5593
|
-
return await api.predictions.create(
|
|
6365
|
+
return await api.predictions.create(
|
|
6366
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
6367
|
+
);
|
|
5594
6368
|
} catch (cause) {
|
|
5595
6369
|
throw replicateError(cause, ctx);
|
|
5596
6370
|
}
|
|
5597
6371
|
},
|
|
5598
|
-
|
|
6372
|
+
{ attempts: 1 }
|
|
5599
6373
|
);
|
|
5600
6374
|
} catch (cause) {
|
|
5601
6375
|
throw replicateError(cause, ctx);
|
|
@@ -5604,7 +6378,10 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5604
6378
|
const check = async () => {
|
|
5605
6379
|
let current;
|
|
5606
6380
|
try {
|
|
5607
|
-
current = await api.predictions.get(
|
|
6381
|
+
current = await api.predictions.get(
|
|
6382
|
+
jobId,
|
|
6383
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
6384
|
+
);
|
|
5608
6385
|
} catch (cause) {
|
|
5609
6386
|
throw replicateError(cause, ctx);
|
|
5610
6387
|
}
|
|
@@ -5705,7 +6482,7 @@ function mmaudioInput(req, ctx) {
|
|
|
5705
6482
|
});
|
|
5706
6483
|
}
|
|
5707
6484
|
const input = {
|
|
5708
|
-
video:
|
|
6485
|
+
video: refToUrl(video),
|
|
5709
6486
|
duration: req.durationSeconds ?? 8,
|
|
5710
6487
|
seed: req.seed ?? -1
|
|
5711
6488
|
};
|
|
@@ -5724,8 +6501,8 @@ function predictionRaw(prediction) {
|
|
|
5724
6501
|
return raw;
|
|
5725
6502
|
}
|
|
5726
6503
|
async function generateReplicateAudio(req, ctx, deps) {
|
|
5727
|
-
const
|
|
5728
|
-
const input =
|
|
6504
|
+
const kind = audioKind(ctx.model.providerModelId);
|
|
6505
|
+
const input = kind === "mmaudio" ? mmaudioInput(req, ctx) : kind === "elevenlabs" ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
|
|
5729
6506
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5730
6507
|
const usage2 = audioUsage(ctx, req);
|
|
5731
6508
|
if (ctx.model.usage.unit === "seconds") {
|
|
@@ -5754,10 +6531,6 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
5754
6531
|
};
|
|
5755
6532
|
}
|
|
5756
6533
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
5757
|
-
function refToUrl4(ref) {
|
|
5758
|
-
if ("url" in ref) return ref.url;
|
|
5759
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5760
|
-
}
|
|
5761
6534
|
var xaiResponseStatusSchema = import_zod13.z.object({
|
|
5762
6535
|
response: import_zod13.z.object({ status: import_zod13.z.number() }).partial()
|
|
5763
6536
|
});
|
|
@@ -5789,13 +6562,14 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5789
6562
|
retryable: false
|
|
5790
6563
|
});
|
|
5791
6564
|
}
|
|
5792
|
-
const refUrls = (req.referenceImages ?? []).map(
|
|
5793
|
-
const resolution = req.resolution === "480p" ? "480p" : "720p";
|
|
6565
|
+
const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
|
|
5794
6566
|
const xaiOptions = {
|
|
5795
|
-
resolution,
|
|
5796
6567
|
pollIntervalMs: POLL_INTERVAL_MS2,
|
|
5797
6568
|
pollTimeoutMs: POLL_TIMEOUT_MS2
|
|
5798
6569
|
};
|
|
6570
|
+
if (req.resolution === "480p" || req.resolution === "720p" || req.resolution === "1080p") {
|
|
6571
|
+
xaiOptions.resolution = req.resolution;
|
|
6572
|
+
}
|
|
5799
6573
|
if (refUrls.length > 0) {
|
|
5800
6574
|
xaiOptions.mode = "reference-to-video";
|
|
5801
6575
|
xaiOptions.referenceImageUrls = refUrls;
|
|
@@ -5815,7 +6589,7 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5815
6589
|
providerOptions: { xai: xaiOptions }
|
|
5816
6590
|
};
|
|
5817
6591
|
if (req.firstFrame) {
|
|
5818
|
-
callBody.frameImages = [{ image:
|
|
6592
|
+
callBody.frameImages = [{ image: refToUrl(req.firstFrame), frameType: "first_frame" }];
|
|
5819
6593
|
}
|
|
5820
6594
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
5821
6595
|
callBody.aspectRatio = req.aspectRatio;
|
|
@@ -5851,7 +6625,8 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5851
6625
|
return settled;
|
|
5852
6626
|
};
|
|
5853
6627
|
return {
|
|
5854
|
-
|
|
6628
|
+
// xAI exposes no request id on the synchronous handle, so each job gets a fresh one.
|
|
6629
|
+
jobId: crypto.randomUUID(),
|
|
5855
6630
|
async poll() {
|
|
5856
6631
|
if (failed !== void 0) return { status: "failed" };
|
|
5857
6632
|
return settled ? { status: "succeeded" } : { status: "pending" };
|
|
@@ -5986,6 +6761,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
|
|
|
5986
6761
|
prodiaAdapter,
|
|
5987
6762
|
readErrorBody,
|
|
5988
6763
|
replicateAdapter,
|
|
6764
|
+
resolveAudioOptions,
|
|
5989
6765
|
resolveImageOptions,
|
|
5990
6766
|
resolveKeys,
|
|
5991
6767
|
resolveVideoOptions,
|