@shop-os/modelkit 0.6.0 → 0.7.0
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/CHANGELOG.md +17 -0
- package/README.md +3 -3
- package/dist/catalog.cjs +241 -46
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +6 -3
- package/dist/catalog.d.ts +6 -3
- package/dist/catalog.js +241 -46
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +895 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +894 -114
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -375,8 +375,59 @@ var FAL_IMAGE_MODELS = [
|
|
|
375
375
|
}
|
|
376
376
|
];
|
|
377
377
|
|
|
378
|
-
// src/catalog/image.ts
|
|
378
|
+
// src/catalog/image-luma.ts
|
|
379
379
|
var IMAGE_USAGE2 = { unit: "images" };
|
|
380
|
+
var EXPOSURE2 = ["cowork", "space_builder"];
|
|
381
|
+
var LOBE2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light";
|
|
382
|
+
var LUMA_LOGO = `${LOBE2}/luma-color.png`;
|
|
383
|
+
var UNI_RATIOS = ["adaptive", "16:9", "3:2", "1:1", "2:3", "9:16"];
|
|
384
|
+
function uniImage(id, label, providerModelId, description) {
|
|
385
|
+
return {
|
|
386
|
+
// https://docs.agents.lumalabs.ai: type "image" without references, else
|
|
387
|
+
// "image_edit" with the first reference as source and up to 8 more as
|
|
388
|
+
// image_ref. The output is always 2048 px on the long side.
|
|
389
|
+
id,
|
|
390
|
+
aliases: [],
|
|
391
|
+
label,
|
|
392
|
+
type: "image",
|
|
393
|
+
adapter: "luma",
|
|
394
|
+
providerModelId,
|
|
395
|
+
lifecycle: "active",
|
|
396
|
+
exposure: EXPOSURE2,
|
|
397
|
+
constraints: {
|
|
398
|
+
aspectRatios: [...UNI_RATIOS],
|
|
399
|
+
sizes: ["2K"],
|
|
400
|
+
references: { images: 9 },
|
|
401
|
+
supports: ["outputFormat"],
|
|
402
|
+
prompt: { referenceSyntax: "numbered", maxChars: 6e3 }
|
|
403
|
+
},
|
|
404
|
+
defaults: { size: "2K", aspectRatio: "adaptive" },
|
|
405
|
+
usage: { ...IMAGE_USAGE2 },
|
|
406
|
+
pricingKind: "image_size",
|
|
407
|
+
display: {
|
|
408
|
+
provider: "luma",
|
|
409
|
+
description,
|
|
410
|
+
logo: LUMA_LOGO
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
var LUMA_IMAGE_MODELS = [
|
|
415
|
+
uniImage(
|
|
416
|
+
"uni-1",
|
|
417
|
+
"Uni-1",
|
|
418
|
+
"uni-1",
|
|
419
|
+
"Luma Uni-1 fast image generation and editing; takes a prompt and up to 9 reference images and outputs 2K."
|
|
420
|
+
),
|
|
421
|
+
uniImage(
|
|
422
|
+
"uni-1-max",
|
|
423
|
+
"Uni-1 Max",
|
|
424
|
+
"uni-1-max",
|
|
425
|
+
"Luma Uni-1 Max higher-quality image generation and editing; takes a prompt and up to 9 reference images and outputs 2K."
|
|
426
|
+
)
|
|
427
|
+
];
|
|
428
|
+
|
|
429
|
+
// src/catalog/image.ts
|
|
430
|
+
var IMAGE_USAGE3 = { unit: "images" };
|
|
380
431
|
var GEMINI_RATIOS = [
|
|
381
432
|
"1:1",
|
|
382
433
|
"2:3",
|
|
@@ -421,7 +472,7 @@ function geminiImage(id, label, aliases, sizes, display, exposure, references, p
|
|
|
421
472
|
exposure,
|
|
422
473
|
constraints,
|
|
423
474
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
424
|
-
usage: { ...
|
|
475
|
+
usage: { ...IMAGE_USAGE3, slug: "gemini" },
|
|
425
476
|
pricingKind: "image_size",
|
|
426
477
|
display
|
|
427
478
|
};
|
|
@@ -534,7 +585,7 @@ var IMAGE_MODELS = [
|
|
|
534
585
|
prompt: GPT_IMAGE_PROMPT
|
|
535
586
|
},
|
|
536
587
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
537
|
-
usage: { ...
|
|
588
|
+
usage: { ...IMAGE_USAGE3, slug: "gpt" },
|
|
538
589
|
pricingKind: "image_size",
|
|
539
590
|
display: {
|
|
540
591
|
provider: "openai",
|
|
@@ -570,7 +621,7 @@ var IMAGE_MODELS = [
|
|
|
570
621
|
prompt: GPT_IMAGE_PROMPT
|
|
571
622
|
},
|
|
572
623
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
573
|
-
usage: { ...
|
|
624
|
+
usage: { ...IMAGE_USAGE3 },
|
|
574
625
|
pricingKind: "image_size",
|
|
575
626
|
display: {
|
|
576
627
|
provider: "openai",
|
|
@@ -605,7 +656,7 @@ var IMAGE_MODELS = [
|
|
|
605
656
|
prompt: GPT_IMAGE_PROMPT
|
|
606
657
|
},
|
|
607
658
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
608
|
-
usage: { ...
|
|
659
|
+
usage: { ...IMAGE_USAGE3 },
|
|
609
660
|
pricingKind: "image_size",
|
|
610
661
|
display: {
|
|
611
662
|
provider: "openai",
|
|
@@ -640,7 +691,7 @@ var IMAGE_MODELS = [
|
|
|
640
691
|
supports: ["count", "outputFormat"]
|
|
641
692
|
},
|
|
642
693
|
defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png", count: 1 },
|
|
643
|
-
usage: { ...
|
|
694
|
+
usage: { ...IMAGE_USAGE3, slug: "muse" },
|
|
644
695
|
pricingKind: "image_size",
|
|
645
696
|
display: {
|
|
646
697
|
provider: "meta",
|
|
@@ -667,7 +718,7 @@ var IMAGE_MODELS = [
|
|
|
667
718
|
supports: ["quality", "count", "seed"]
|
|
668
719
|
},
|
|
669
720
|
defaults: { size: "2K", aspectRatio: "1:1", quality: "medium", count: 1 },
|
|
670
|
-
usage: { ...
|
|
721
|
+
usage: { ...IMAGE_USAGE3, slug: "ideogram" },
|
|
671
722
|
pricingKind: "image_size",
|
|
672
723
|
display: {
|
|
673
724
|
provider: "ideogram",
|
|
@@ -692,7 +743,7 @@ var IMAGE_MODELS = [
|
|
|
692
743
|
supports: ["seed", "outputFormat"]
|
|
693
744
|
},
|
|
694
745
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
695
|
-
usage: { ...
|
|
746
|
+
usage: { ...IMAGE_USAGE3 },
|
|
696
747
|
pricingKind: "image_size",
|
|
697
748
|
display: {
|
|
698
749
|
provider: "bytedance",
|
|
@@ -730,7 +781,7 @@ var IMAGE_MODELS = [
|
|
|
730
781
|
supports: ["seed"]
|
|
731
782
|
},
|
|
732
783
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
733
|
-
usage: { ...
|
|
784
|
+
usage: { ...IMAGE_USAGE3 },
|
|
734
785
|
pricingKind: "image_size",
|
|
735
786
|
display: {
|
|
736
787
|
provider: "bytedance",
|
|
@@ -756,7 +807,7 @@ var IMAGE_MODELS = [
|
|
|
756
807
|
prompt: { referenceSyntax: "numbered", maxChars: 32768 }
|
|
757
808
|
},
|
|
758
809
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
759
|
-
usage: { ...
|
|
810
|
+
usage: { ...IMAGE_USAGE3 },
|
|
760
811
|
pricingKind: "image_size",
|
|
761
812
|
display: {
|
|
762
813
|
provider: "black-forest-labs",
|
|
@@ -783,7 +834,7 @@ var IMAGE_MODELS = [
|
|
|
783
834
|
supports: []
|
|
784
835
|
},
|
|
785
836
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
786
|
-
usage: { ...
|
|
837
|
+
usage: { ...IMAGE_USAGE3 },
|
|
787
838
|
pricingKind: "image_size",
|
|
788
839
|
display: {
|
|
789
840
|
provider: "google",
|
|
@@ -808,7 +859,7 @@ var IMAGE_MODELS = [
|
|
|
808
859
|
supports: []
|
|
809
860
|
},
|
|
810
861
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
811
|
-
usage: { ...
|
|
862
|
+
usage: { ...IMAGE_USAGE3 },
|
|
812
863
|
pricingKind: "image_size",
|
|
813
864
|
display: {
|
|
814
865
|
provider: "google",
|
|
@@ -894,7 +945,8 @@ var IMAGE_MODELS = [
|
|
|
894
945
|
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."
|
|
895
946
|
}
|
|
896
947
|
},
|
|
897
|
-
...FAL_IMAGE_MODELS
|
|
948
|
+
...FAL_IMAGE_MODELS,
|
|
949
|
+
...LUMA_IMAGE_MODELS
|
|
898
950
|
];
|
|
899
951
|
|
|
900
952
|
// src/catalog/audio-formats.ts
|
|
@@ -1090,7 +1142,7 @@ var VEED_SUBTITLE_LANGUAGES = [
|
|
|
1090
1142
|
];
|
|
1091
1143
|
|
|
1092
1144
|
// src/catalog/canvas-tools.ts
|
|
1093
|
-
var
|
|
1145
|
+
var EXPOSURE3 = ["cowork", "space_builder"];
|
|
1094
1146
|
var META_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/characters/1787909065794-k9a7zz.png";
|
|
1095
1147
|
var VEED_SUBTITLE_PRESETS = [
|
|
1096
1148
|
"simple",
|
|
@@ -1132,7 +1184,7 @@ var SAM_3_IMAGE = {
|
|
|
1132
1184
|
adapter: "fal",
|
|
1133
1185
|
providerModelId: "fal-ai/sam-3/image",
|
|
1134
1186
|
lifecycle: "active",
|
|
1135
|
-
exposure:
|
|
1187
|
+
exposure: EXPOSURE3,
|
|
1136
1188
|
constraints: {
|
|
1137
1189
|
references: { images: 1 },
|
|
1138
1190
|
requires: ["references"],
|
|
@@ -1155,7 +1207,7 @@ var VEED_SUBTITLES = {
|
|
|
1155
1207
|
adapter: "fal",
|
|
1156
1208
|
providerModelId: "veed/subtitles",
|
|
1157
1209
|
lifecycle: "active",
|
|
1158
|
-
exposure:
|
|
1210
|
+
exposure: EXPOSURE3,
|
|
1159
1211
|
constraints: {
|
|
1160
1212
|
supports: [],
|
|
1161
1213
|
// fal: up to 2 hours at 1080p or below, 1 hour above.
|
|
@@ -3260,7 +3312,7 @@ var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a
|
|
|
3260
3312
|
var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3261
3313
|
var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
|
|
3262
3314
|
var PER_CALL = { unit: "images" };
|
|
3263
|
-
var
|
|
3315
|
+
var EXPOSURE4 = ["cowork", "space_builder"];
|
|
3264
3316
|
var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
|
|
3265
3317
|
function elevenLabsTts(tts) {
|
|
3266
3318
|
return {
|
|
@@ -3271,7 +3323,7 @@ function elevenLabsTts(tts) {
|
|
|
3271
3323
|
adapter: "fal",
|
|
3272
3324
|
providerModelId: tts.providerModelId,
|
|
3273
3325
|
lifecycle: "active",
|
|
3274
|
-
exposure:
|
|
3326
|
+
exposure: EXPOSURE4,
|
|
3275
3327
|
constraints: {
|
|
3276
3328
|
voices: ELEVENLABS_VOICES,
|
|
3277
3329
|
languages: tts.languages,
|
|
@@ -3296,7 +3348,7 @@ function geminiTts(id, label, description) {
|
|
|
3296
3348
|
adapter: "fal",
|
|
3297
3349
|
providerModelId,
|
|
3298
3350
|
lifecycle: "active",
|
|
3299
|
-
exposure:
|
|
3351
|
+
exposure: EXPOSURE4,
|
|
3300
3352
|
constraints: {
|
|
3301
3353
|
voices: GEMINI_TTS_VOICES,
|
|
3302
3354
|
supports: ["style"],
|
|
@@ -3319,7 +3371,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3319
3371
|
adapter: "fal",
|
|
3320
3372
|
providerModelId,
|
|
3321
3373
|
lifecycle: "active",
|
|
3322
|
-
exposure:
|
|
3374
|
+
exposure: EXPOSURE4,
|
|
3323
3375
|
constraints: {
|
|
3324
3376
|
requires: ["sourceVideo", "sourceAudio"],
|
|
3325
3377
|
references: LIPSYNC_AUDIO,
|
|
@@ -3380,7 +3432,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3380
3432
|
adapter: "fal",
|
|
3381
3433
|
providerModelId: "fal-ai/minimax/speech-2.8-hd",
|
|
3382
3434
|
lifecycle: "active",
|
|
3383
|
-
exposure:
|
|
3435
|
+
exposure: EXPOSURE4,
|
|
3384
3436
|
constraints: {
|
|
3385
3437
|
voices: MINIMAX_VOICES,
|
|
3386
3438
|
languages: MINIMAX_SPEECH_LANGUAGES,
|
|
@@ -3405,7 +3457,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3405
3457
|
adapter: "fal",
|
|
3406
3458
|
providerModelId: "fal-ai/elevenlabs/voice-changer",
|
|
3407
3459
|
lifecycle: "active",
|
|
3408
|
-
exposure:
|
|
3460
|
+
exposure: EXPOSURE4,
|
|
3409
3461
|
constraints: {
|
|
3410
3462
|
requires: ["sourceAudio"],
|
|
3411
3463
|
// The flat price assumes at most a minute of speech.
|
|
@@ -3432,7 +3484,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3432
3484
|
adapter: "fal",
|
|
3433
3485
|
providerModelId: "fal-ai/elevenlabs/dubbing",
|
|
3434
3486
|
lifecycle: "active",
|
|
3435
|
-
exposure:
|
|
3487
|
+
exposure: EXPOSURE4,
|
|
3436
3488
|
constraints: {
|
|
3437
3489
|
requiresOneOf: ["sourceVideo", "sourceAudio"],
|
|
3438
3490
|
// The flat price covers 60 s of source.
|
|
@@ -3480,7 +3532,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3480
3532
|
adapter: "fal",
|
|
3481
3533
|
providerModelId: "veed/lipsync/v2",
|
|
3482
3534
|
lifecycle: "active",
|
|
3483
|
-
exposure:
|
|
3535
|
+
exposure: EXPOSURE4,
|
|
3484
3536
|
constraints: {
|
|
3485
3537
|
requires: ["sourceVideo", "sourceAudio"],
|
|
3486
3538
|
references: LIPSYNC_AUDIO,
|
|
@@ -3506,7 +3558,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3506
3558
|
adapter: "fal",
|
|
3507
3559
|
providerModelId: "minimax/h3-max/lip-sync/image-to-video",
|
|
3508
3560
|
lifecycle: "active",
|
|
3509
|
-
exposure:
|
|
3561
|
+
exposure: EXPOSURE4,
|
|
3510
3562
|
constraints: {
|
|
3511
3563
|
requires: ["firstFrame", "sourceAudio"],
|
|
3512
3564
|
resolutions: ["480p", "768p", "1080p", "2k"],
|
|
@@ -3532,7 +3584,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3532
3584
|
adapter: "fal",
|
|
3533
3585
|
providerModelId: "fal-ai/elevenlabs/speech-to-text/scribe-v2",
|
|
3534
3586
|
lifecycle: "active",
|
|
3535
|
-
exposure:
|
|
3587
|
+
exposure: EXPOSURE4,
|
|
3536
3588
|
constraints: {
|
|
3537
3589
|
requires: ["sourceAudio"],
|
|
3538
3590
|
// The flat price covers 10 minutes of audio.
|
|
@@ -5068,8 +5120,113 @@ var VIDEO_FAMILY_MODELS = [
|
|
|
5068
5120
|
}
|
|
5069
5121
|
];
|
|
5070
5122
|
|
|
5071
|
-
// src/catalog/video.ts
|
|
5123
|
+
// src/catalog/video-luma.ts
|
|
5072
5124
|
var VIDEO_USAGE2 = { unit: "seconds" };
|
|
5125
|
+
var EXPOSURE5 = ["cowork", "space_builder"];
|
|
5126
|
+
var LUMA_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/luma-color.png";
|
|
5127
|
+
var RAY_RATIOS = ["9:16", "3:4", "1:1", "4:3", "16:9", "21:9"];
|
|
5128
|
+
var RAY_RESOLUTIONS = ["360p", "720p", "1080p"];
|
|
5129
|
+
var RAY_PROMPT = { referenceSyntax: "numbered", maxChars: 6e3 };
|
|
5130
|
+
var LUMA_VIDEO_MODELS = [
|
|
5131
|
+
{
|
|
5132
|
+
// https://docs.agents.lumalabs.ai: type "video" with a fixed 5 s duration;
|
|
5133
|
+
// firstFrame and lastFrame ride as start_frame and end_frame.
|
|
5134
|
+
id: "ray-3.2",
|
|
5135
|
+
aliases: [],
|
|
5136
|
+
label: "Ray 3.2",
|
|
5137
|
+
type: "video",
|
|
5138
|
+
adapter: "luma",
|
|
5139
|
+
providerModelId: "ray-3.2",
|
|
5140
|
+
lifecycle: "active",
|
|
5141
|
+
exposure: EXPOSURE5,
|
|
5142
|
+
constraints: {
|
|
5143
|
+
aspectRatios: ["adaptive", ...RAY_RATIOS],
|
|
5144
|
+
resolutions: [...RAY_RESOLUTIONS],
|
|
5145
|
+
durations: [5],
|
|
5146
|
+
supports: ["lastFrame"],
|
|
5147
|
+
prompt: { ...RAY_PROMPT },
|
|
5148
|
+
audio: "never"
|
|
5149
|
+
},
|
|
5150
|
+
defaults: { durationSeconds: 5, resolution: "720p", aspectRatio: "adaptive" },
|
|
5151
|
+
usage: { ...VIDEO_USAGE2 },
|
|
5152
|
+
pricingKind: "video_per_second",
|
|
5153
|
+
display: {
|
|
5154
|
+
provider: "luma",
|
|
5155
|
+
description: "Luma Ray 3.2 text- and image-to-video with optional first and last frames, 5-second clips at up to 1080p.",
|
|
5156
|
+
logo: LUMA_LOGO2
|
|
5157
|
+
},
|
|
5158
|
+
capabilities: {}
|
|
5159
|
+
},
|
|
5160
|
+
{
|
|
5161
|
+
// https://docs.agents.lumalabs.ai: type "video_edit" with a source video of
|
|
5162
|
+
// up to 18 s; the output keeps the source length, so there is no durations
|
|
5163
|
+
// knob, no aspect_ratio and no end frame. Luma bills its 5 s price for any
|
|
5164
|
+
// source (live, 2026-10-21) and the row is priced per source second, so a
|
|
5165
|
+
// source under 5 s is refused: it would be billed below Luma's charge.
|
|
5166
|
+
id: "ray-3.2-edit",
|
|
5167
|
+
aliases: [],
|
|
5168
|
+
label: "Ray 3.2 Edit",
|
|
5169
|
+
type: "video",
|
|
5170
|
+
adapter: "luma",
|
|
5171
|
+
providerModelId: "ray-3.2",
|
|
5172
|
+
lifecycle: "active",
|
|
5173
|
+
exposure: EXPOSURE5,
|
|
5174
|
+
constraints: {
|
|
5175
|
+
resolutions: [...RAY_RESOLUTIONS],
|
|
5176
|
+
requires: ["sourceVideo"],
|
|
5177
|
+
sourceVideoSeconds: { min: 5, max: 18 },
|
|
5178
|
+
supports: [],
|
|
5179
|
+
prompt: { ...RAY_PROMPT },
|
|
5180
|
+
audio: "never"
|
|
5181
|
+
},
|
|
5182
|
+
defaults: { resolution: "720p" },
|
|
5183
|
+
usage: { ...VIDEO_USAGE2 },
|
|
5184
|
+
pricingKind: "video_per_second",
|
|
5185
|
+
display: {
|
|
5186
|
+
provider: "luma",
|
|
5187
|
+
description: "Luma Ray 3.2 video edit: changes a 5-18 second clip from a prompt, keeping its length.",
|
|
5188
|
+
logo: LUMA_LOGO2
|
|
5189
|
+
},
|
|
5190
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: true }
|
|
5191
|
+
},
|
|
5192
|
+
{
|
|
5193
|
+
// https://docs.agents.lumalabs.ai: type "video_reframe" with a required
|
|
5194
|
+
// target aspect_ratio; the source is up to 10 s and the output keeps its
|
|
5195
|
+
// length whatever video.duration says, while Luma bills that duration
|
|
5196
|
+
// (live, 2026-10-21). So there is no durations knob, and a source under
|
|
5197
|
+
// 5 s is refused, as on ray-3.2-edit. 1080p is not offered for the
|
|
5198
|
+
// vertical targets 9:16 and 3:4.
|
|
5199
|
+
id: "ray-3.2-reframe",
|
|
5200
|
+
aliases: [],
|
|
5201
|
+
label: "Ray 3.2 Reframe",
|
|
5202
|
+
type: "video",
|
|
5203
|
+
adapter: "luma",
|
|
5204
|
+
providerModelId: "ray-3.2",
|
|
5205
|
+
lifecycle: "active",
|
|
5206
|
+
exposure: EXPOSURE5,
|
|
5207
|
+
constraints: {
|
|
5208
|
+
aspectRatios: [...RAY_RATIOS],
|
|
5209
|
+
resolutions: [...RAY_RESOLUTIONS],
|
|
5210
|
+
requires: ["sourceVideo"],
|
|
5211
|
+
sourceVideoSeconds: { min: 5, max: 10 },
|
|
5212
|
+
supports: [],
|
|
5213
|
+
prompt: { ...RAY_PROMPT },
|
|
5214
|
+
audio: "never"
|
|
5215
|
+
},
|
|
5216
|
+
defaults: { resolution: "720p", aspectRatio: "16:9" },
|
|
5217
|
+
usage: { ...VIDEO_USAGE2 },
|
|
5218
|
+
pricingKind: "video_per_second",
|
|
5219
|
+
display: {
|
|
5220
|
+
provider: "luma",
|
|
5221
|
+
description: "Luma Ray 3.2 Reframe: changes a 5-10 second clip to a new aspect ratio and fills the new area from the prompt.",
|
|
5222
|
+
logo: LUMA_LOGO2
|
|
5223
|
+
},
|
|
5224
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: true }
|
|
5225
|
+
}
|
|
5226
|
+
];
|
|
5227
|
+
|
|
5228
|
+
// src/catalog/video.ts
|
|
5229
|
+
var VIDEO_USAGE3 = { unit: "seconds" };
|
|
5073
5230
|
var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
|
|
5074
5231
|
var KLING_RATIOS2 = ["16:9", "9:16", "1:1", "adaptive"];
|
|
5075
5232
|
var KLING_OMNI_RATIOS = ["16:9", "9:16", "1:1"];
|
|
@@ -5122,7 +5279,7 @@ var VIDEO_MODELS = [
|
|
|
5122
5279
|
audio: "always"
|
|
5123
5280
|
},
|
|
5124
5281
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
5125
|
-
usage: { ...
|
|
5282
|
+
usage: { ...VIDEO_USAGE3, slug: "veo" },
|
|
5126
5283
|
pricingKind: "video_per_second",
|
|
5127
5284
|
display: {
|
|
5128
5285
|
provider: "google",
|
|
@@ -5155,7 +5312,7 @@ var VIDEO_MODELS = [
|
|
|
5155
5312
|
audio: "always"
|
|
5156
5313
|
},
|
|
5157
5314
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
5158
|
-
usage: { ...
|
|
5315
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5159
5316
|
pricingKind: "video_per_second",
|
|
5160
5317
|
display: {
|
|
5161
5318
|
provider: "google",
|
|
@@ -5185,7 +5342,7 @@ var VIDEO_MODELS = [
|
|
|
5185
5342
|
audio: "always"
|
|
5186
5343
|
},
|
|
5187
5344
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
5188
|
-
usage: { ...
|
|
5345
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5189
5346
|
pricingKind: "video_per_second",
|
|
5190
5347
|
display: {
|
|
5191
5348
|
provider: "google",
|
|
@@ -5222,7 +5379,7 @@ var VIDEO_MODELS = [
|
|
|
5222
5379
|
audio: "always"
|
|
5223
5380
|
},
|
|
5224
5381
|
defaults: {},
|
|
5225
|
-
usage: { ...
|
|
5382
|
+
usage: { ...VIDEO_USAGE3, slug: "gemini_omni" },
|
|
5226
5383
|
pricingKind: "video_per_second",
|
|
5227
5384
|
display: {
|
|
5228
5385
|
provider: "google",
|
|
@@ -5259,7 +5416,7 @@ var VIDEO_MODELS = [
|
|
|
5259
5416
|
audio: "always"
|
|
5260
5417
|
},
|
|
5261
5418
|
defaults: {},
|
|
5262
|
-
usage: { ...
|
|
5419
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5263
5420
|
pricingKind: "video_per_second",
|
|
5264
5421
|
display: {
|
|
5265
5422
|
provider: "google",
|
|
@@ -5308,7 +5465,7 @@ var VIDEO_MODELS = [
|
|
|
5308
5465
|
aspectRatio: "16:9",
|
|
5309
5466
|
generateAudio: true
|
|
5310
5467
|
},
|
|
5311
|
-
usage: { ...
|
|
5468
|
+
usage: { ...VIDEO_USAGE3, slug: "seedance2", providerLabel: "byteplus" },
|
|
5312
5469
|
pricingKind: "video_per_second",
|
|
5313
5470
|
display: {
|
|
5314
5471
|
provider: "bytedance",
|
|
@@ -5351,7 +5508,7 @@ var VIDEO_MODELS = [
|
|
|
5351
5508
|
aspectRatio: "16:9",
|
|
5352
5509
|
generateAudio: true
|
|
5353
5510
|
},
|
|
5354
|
-
usage: { ...
|
|
5511
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5355
5512
|
pricingKind: "video_per_second",
|
|
5356
5513
|
display: {
|
|
5357
5514
|
provider: "bytedance",
|
|
@@ -5401,7 +5558,7 @@ var VIDEO_MODELS = [
|
|
|
5401
5558
|
aspectRatio: "16:9",
|
|
5402
5559
|
generateAudio: true
|
|
5403
5560
|
},
|
|
5404
|
-
usage: { ...
|
|
5561
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5405
5562
|
pricingKind: "video_per_second",
|
|
5406
5563
|
display: {
|
|
5407
5564
|
provider: "bytedance",
|
|
@@ -5463,7 +5620,7 @@ var VIDEO_MODELS = [
|
|
|
5463
5620
|
cfgScale: 0.5,
|
|
5464
5621
|
negativePrompt: NEGATIVE_PROMPT
|
|
5465
5622
|
},
|
|
5466
|
-
usage: { ...
|
|
5623
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5467
5624
|
pricingKind: "video_per_second",
|
|
5468
5625
|
display: {
|
|
5469
5626
|
provider: "kuaishou",
|
|
@@ -5495,7 +5652,7 @@ var VIDEO_MODELS = [
|
|
|
5495
5652
|
cfgScale: 0.5,
|
|
5496
5653
|
generateAudio: true
|
|
5497
5654
|
},
|
|
5498
|
-
usage: { ...
|
|
5655
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5499
5656
|
pricingKind: "video_per_second",
|
|
5500
5657
|
display: {
|
|
5501
5658
|
provider: "kuaishou",
|
|
@@ -5563,7 +5720,7 @@ var VIDEO_MODELS = [
|
|
|
5563
5720
|
aspectRatio: "16:9",
|
|
5564
5721
|
promptExpansion: "balanced"
|
|
5565
5722
|
},
|
|
5566
|
-
usage: { ...
|
|
5723
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5567
5724
|
pricingKind: "video_per_second",
|
|
5568
5725
|
display: {
|
|
5569
5726
|
provider: "minimax",
|
|
@@ -5597,7 +5754,7 @@ var VIDEO_MODELS = [
|
|
|
5597
5754
|
aspectRatio: "16:9",
|
|
5598
5755
|
promptExpansion: "balanced"
|
|
5599
5756
|
},
|
|
5600
|
-
usage: { ...
|
|
5757
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5601
5758
|
pricingKind: "video_per_second",
|
|
5602
5759
|
display: {
|
|
5603
5760
|
provider: "minimax",
|
|
@@ -5639,7 +5796,7 @@ var VIDEO_MODELS = [
|
|
|
5639
5796
|
aspectRatio: "adaptive",
|
|
5640
5797
|
promptExpansion: "balanced"
|
|
5641
5798
|
},
|
|
5642
|
-
usage: { ...
|
|
5799
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5643
5800
|
pricingKind: "video_per_second",
|
|
5644
5801
|
display: {
|
|
5645
5802
|
provider: "minimax",
|
|
@@ -5683,7 +5840,7 @@ var VIDEO_MODELS = [
|
|
|
5683
5840
|
aspectRatio: "adaptive",
|
|
5684
5841
|
promptExpansion: "balanced"
|
|
5685
5842
|
},
|
|
5686
|
-
usage: { ...
|
|
5843
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5687
5844
|
pricingKind: "video_per_second",
|
|
5688
5845
|
display: {
|
|
5689
5846
|
provider: "minimax",
|
|
@@ -5728,7 +5885,7 @@ var VIDEO_MODELS = [
|
|
|
5728
5885
|
aspectRatio: "adaptive",
|
|
5729
5886
|
generateAudio: true
|
|
5730
5887
|
},
|
|
5731
|
-
usage: { ...
|
|
5888
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5732
5889
|
pricingKind: "video_per_second",
|
|
5733
5890
|
display: {
|
|
5734
5891
|
provider: "alibaba",
|
|
@@ -5755,7 +5912,7 @@ var VIDEO_MODELS = [
|
|
|
5755
5912
|
audio: "never"
|
|
5756
5913
|
},
|
|
5757
5914
|
defaults: { durationSeconds: 5, aspectRatio: "16:9" },
|
|
5758
|
-
usage: { ...
|
|
5915
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5759
5916
|
pricingKind: "video_per_second",
|
|
5760
5917
|
display: {
|
|
5761
5918
|
provider: "kuaishou",
|
|
@@ -5804,7 +5961,7 @@ var VIDEO_MODELS = [
|
|
|
5804
5961
|
audio: "never"
|
|
5805
5962
|
},
|
|
5806
5963
|
defaults: {},
|
|
5807
|
-
usage: { ...
|
|
5964
|
+
usage: { ...VIDEO_USAGE3 },
|
|
5808
5965
|
// Higgsfield bills DoP per generation: a fixed-length clip with no duration knob.
|
|
5809
5966
|
pricingKind: "flat",
|
|
5810
5967
|
display: {
|
|
@@ -5813,7 +5970,8 @@ var VIDEO_MODELS = [
|
|
|
5813
5970
|
},
|
|
5814
5971
|
capabilities: {}
|
|
5815
5972
|
},
|
|
5816
|
-
...VIDEO_FAMILY_MODELS
|
|
5973
|
+
...VIDEO_FAMILY_MODELS,
|
|
5974
|
+
...LUMA_VIDEO_MODELS
|
|
5817
5975
|
];
|
|
5818
5976
|
|
|
5819
5977
|
// src/catalog/video-tools.ts
|
|
@@ -6787,7 +6945,8 @@ var ADAPTER_IDS = [
|
|
|
6787
6945
|
"replicate",
|
|
6788
6946
|
"prodia",
|
|
6789
6947
|
"higgsfield",
|
|
6790
|
-
"xai-video"
|
|
6948
|
+
"xai-video",
|
|
6949
|
+
"luma"
|
|
6791
6950
|
];
|
|
6792
6951
|
var ModelTypeSchema = z3.enum([
|
|
6793
6952
|
"text",
|
|
@@ -10917,6 +11076,30 @@ var klingV3Family = {
|
|
|
10917
11076
|
}
|
|
10918
11077
|
};
|
|
10919
11078
|
|
|
11079
|
+
// src/replicate-video-kinds.ts
|
|
11080
|
+
function replicateBaseModelId(providerModelId) {
|
|
11081
|
+
const colon = providerModelId.indexOf(":");
|
|
11082
|
+
return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
|
|
11083
|
+
}
|
|
11084
|
+
var REPLICATE_VIDEO_KINDS = /* @__PURE__ */ new Map([
|
|
11085
|
+
["kling-video/v2.5-turbo/pro/image-to-video", "kling"],
|
|
11086
|
+
["kling-video/v3.0/pro/image-to-video", "kling"],
|
|
11087
|
+
["kwaivgi/kling-v3-video", "kling"],
|
|
11088
|
+
["kwaivgi/kling-v3-omni-video", "kling-omni"],
|
|
11089
|
+
["minimax/hailuo-02", "hailuo"]
|
|
11090
|
+
]);
|
|
11091
|
+
function videoKind(providerModelId) {
|
|
11092
|
+
return REPLICATE_VIDEO_KINDS.get(replicateBaseModelId(providerModelId));
|
|
11093
|
+
}
|
|
11094
|
+
var KLING_TIERS = [
|
|
11095
|
+
{ mode: "standard", resolution: "720p" },
|
|
11096
|
+
{ mode: "pro", resolution: "1080p" },
|
|
11097
|
+
{ mode: "4k", resolution: "4k" }
|
|
11098
|
+
];
|
|
11099
|
+
function klingTier(req) {
|
|
11100
|
+
return KLING_TIERS.find((tier) => tier.resolution === req.resolution) ?? KLING_TIERS.find((tier) => tier.mode === req.mode) ?? KLING_TIERS[0];
|
|
11101
|
+
}
|
|
11102
|
+
|
|
10920
11103
|
// src/resolve-video-rules.ts
|
|
10921
11104
|
var MOTION_PRO2 = "fal-ai/kling-video/v3/pro/motion-control";
|
|
10922
11105
|
var MOTION_STANDARD2 = "fal-ai/kling-video/v3/standard/motion-control";
|
|
@@ -11090,6 +11273,16 @@ function h3EndFrameRatioWarning(model, ratio) {
|
|
|
11090
11273
|
message: `${model.id} follows the end frame's aspect ratio`
|
|
11091
11274
|
};
|
|
11092
11275
|
}
|
|
11276
|
+
function isReplicateKling(model) {
|
|
11277
|
+
if (model.adapter !== "replicate") return false;
|
|
11278
|
+
const kind = videoKind(model.providerModelId);
|
|
11279
|
+
return kind === "kling" || kind === "kling-omni";
|
|
11280
|
+
}
|
|
11281
|
+
function fillReplicateKlingResolution(model, req) {
|
|
11282
|
+
if (isReplicateKling(model) && req.resolution === void 0) {
|
|
11283
|
+
req.resolution = klingTier(req).resolution;
|
|
11284
|
+
}
|
|
11285
|
+
}
|
|
11093
11286
|
function applyFalVideoRules(model, req, callerRatio, warnings) {
|
|
11094
11287
|
if (model.adapter !== "fal") return;
|
|
11095
11288
|
const problem = falVideoProblem(model.providerModelId, withPromptForResolve(req));
|
|
@@ -13418,9 +13611,608 @@ var higgsfieldAdapter = {
|
|
|
13418
13611
|
}
|
|
13419
13612
|
};
|
|
13420
13613
|
|
|
13614
|
+
// src/adapters/luma.ts
|
|
13615
|
+
import { z as z25 } from "zod";
|
|
13616
|
+
|
|
13617
|
+
// src/adapters/mp4-duration.ts
|
|
13618
|
+
function mp4DurationSeconds(bytes) {
|
|
13619
|
+
const moov = findBox(bytes, 0, bytes.length, "moov");
|
|
13620
|
+
if (!moov) return void 0;
|
|
13621
|
+
const mvhd = findBox(bytes, moov.start + 8, moov.end, "mvhd");
|
|
13622
|
+
if (!mvhd) return void 0;
|
|
13623
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13624
|
+
const size = mvhd.end - mvhd.start;
|
|
13625
|
+
if (size < 8 + 4) return void 0;
|
|
13626
|
+
const version = view.getUint8(mvhd.start + 8);
|
|
13627
|
+
if (version === 0) {
|
|
13628
|
+
if (size < 8 + 4 + 4 + 4 + 4 + 4) return void 0;
|
|
13629
|
+
const timescale = view.getUint32(mvhd.start + 8 + 4 + 4 + 4);
|
|
13630
|
+
const duration = view.getUint32(mvhd.start + 8 + 4 + 4 + 4 + 4);
|
|
13631
|
+
if (timescale === 0) return void 0;
|
|
13632
|
+
return duration / timescale;
|
|
13633
|
+
}
|
|
13634
|
+
if (version === 1) {
|
|
13635
|
+
if (size < 8 + 4 + 8 + 8 + 4 + 8) return void 0;
|
|
13636
|
+
const timescale = view.getUint32(mvhd.start + 8 + 4 + 8 + 8);
|
|
13637
|
+
const high = view.getUint32(mvhd.start + 8 + 4 + 8 + 8 + 4);
|
|
13638
|
+
const low = view.getUint32(mvhd.start + 8 + 4 + 8 + 8 + 4 + 4);
|
|
13639
|
+
if (timescale === 0) return void 0;
|
|
13640
|
+
return (high * 2 ** 32 + low) / timescale;
|
|
13641
|
+
}
|
|
13642
|
+
return void 0;
|
|
13643
|
+
}
|
|
13644
|
+
function findBox(bytes, from, to, type) {
|
|
13645
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13646
|
+
let offset = from;
|
|
13647
|
+
while (offset + 8 <= to) {
|
|
13648
|
+
const size = view.getUint32(offset);
|
|
13649
|
+
const name = String.fromCharCode(
|
|
13650
|
+
view.getUint8(offset + 4),
|
|
13651
|
+
view.getUint8(offset + 5),
|
|
13652
|
+
view.getUint8(offset + 6),
|
|
13653
|
+
view.getUint8(offset + 7)
|
|
13654
|
+
);
|
|
13655
|
+
if (size < 8 || offset + size > to) return void 0;
|
|
13656
|
+
if (name === type) return { start: offset, end: offset + size };
|
|
13657
|
+
offset += size;
|
|
13658
|
+
}
|
|
13659
|
+
return void 0;
|
|
13660
|
+
}
|
|
13661
|
+
|
|
13662
|
+
// src/adapters/luma.ts
|
|
13663
|
+
var DEFAULT_BASE_URL = "https://agents.lumalabs.ai";
|
|
13664
|
+
var IMAGE_POLL_INTERVAL_MS = 3e3;
|
|
13665
|
+
var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
13666
|
+
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
13667
|
+
var VIDEO_TIMEOUT_MS = 20 * 6e4;
|
|
13668
|
+
var PROMPT_MAX_CHARS = 6e3;
|
|
13669
|
+
var LUMA_IMAGE_MODEL_IDS = /* @__PURE__ */ new Set(["uni-1", "uni-1-max"]);
|
|
13670
|
+
var LUMA_VIDEO_MODEL_ID = "ray-3.2";
|
|
13671
|
+
var LUMA_VIDEO_MODES = /* @__PURE__ */ new Map([
|
|
13672
|
+
["ray-3.2", "generate"],
|
|
13673
|
+
["ray-3.2-edit", "edit"],
|
|
13674
|
+
["ray-3.2-reframe", "reframe"]
|
|
13675
|
+
]);
|
|
13676
|
+
function lumaRowRefusal(row2) {
|
|
13677
|
+
const provider = row2.providerModelId.toLowerCase();
|
|
13678
|
+
if (row2.type === "image") {
|
|
13679
|
+
return LUMA_IMAGE_MODEL_IDS.has(provider) ? void 0 : "luma image rows need providerModelId uni-1 or uni-1-max";
|
|
13680
|
+
}
|
|
13681
|
+
if (row2.type === "video") {
|
|
13682
|
+
if (provider !== LUMA_VIDEO_MODEL_ID) return "luma video rows need providerModelId ray-3.2";
|
|
13683
|
+
return !LUMA_VIDEO_MODES.has(row2.id) ? `luma routes ray-3.2 rows by catalog id; it knows ${[...LUMA_VIDEO_MODES.keys()].join(", ")}` : void 0;
|
|
13684
|
+
}
|
|
13685
|
+
return `luma has no ${row2.type} rows`;
|
|
13686
|
+
}
|
|
13687
|
+
function lumaBase(ctx) {
|
|
13688
|
+
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
|
|
13689
|
+
}
|
|
13690
|
+
function lumaKey(ctx) {
|
|
13691
|
+
const key = ctx.keys.luma;
|
|
13692
|
+
if (!key) {
|
|
13693
|
+
throw new ModelKitError({
|
|
13694
|
+
code: "auth",
|
|
13695
|
+
message: "Missing API key for luma",
|
|
13696
|
+
provider: "luma",
|
|
13697
|
+
model: ctx.model.id,
|
|
13698
|
+
retryable: false
|
|
13699
|
+
});
|
|
13700
|
+
}
|
|
13701
|
+
return key;
|
|
13702
|
+
}
|
|
13703
|
+
function checkPrompt(req, ctx) {
|
|
13704
|
+
const prompt = req.prompt.trim();
|
|
13705
|
+
if (prompt.length === 0) {
|
|
13706
|
+
throw new ModelKitError({
|
|
13707
|
+
code: "missing_input",
|
|
13708
|
+
message: `${ctx.model.id} needs a prompt`,
|
|
13709
|
+
provider: "luma",
|
|
13710
|
+
model: ctx.model.id,
|
|
13711
|
+
retryable: false
|
|
13712
|
+
});
|
|
13713
|
+
}
|
|
13714
|
+
if (req.prompt.length > PROMPT_MAX_CHARS) {
|
|
13715
|
+
throw new ModelKitError({
|
|
13716
|
+
code: "unsupported_option",
|
|
13717
|
+
message: `${ctx.model.id} takes a prompt of at most ${PROMPT_MAX_CHARS} characters`,
|
|
13718
|
+
provider: "luma",
|
|
13719
|
+
model: ctx.model.id,
|
|
13720
|
+
retryable: false
|
|
13721
|
+
});
|
|
13722
|
+
}
|
|
13723
|
+
return req.prompt;
|
|
13724
|
+
}
|
|
13725
|
+
function imageRef(ref) {
|
|
13726
|
+
if ("url" in ref) return { url: ref.url };
|
|
13727
|
+
return { data: mediaRefToBase64(ref.bytes), media_type: ref.mime };
|
|
13728
|
+
}
|
|
13729
|
+
function videoRef(ref) {
|
|
13730
|
+
if ("url" in ref) return { url: ref.url, media_type: "video/mp4" };
|
|
13731
|
+
const mediaType = ref.mime.startsWith("video/") ? ref.mime : "video/mp4";
|
|
13732
|
+
return { data: mediaRefToBase64(ref.bytes), media_type: mediaType };
|
|
13733
|
+
}
|
|
13734
|
+
function lumaOutputFormat(req, ctx) {
|
|
13735
|
+
const format = req.outputFormat;
|
|
13736
|
+
if (format === void 0 || format === "png" || format === "jpeg") return format;
|
|
13737
|
+
if ((ctx.call.onUnsupported ?? "error") === "error") {
|
|
13738
|
+
throw new ModelKitError({
|
|
13739
|
+
code: "unsupported_option",
|
|
13740
|
+
message: `${ctx.model.id} has no outputFormat "${format}". Supported: png, jpeg.`,
|
|
13741
|
+
provider: "luma",
|
|
13742
|
+
model: ctx.model.id,
|
|
13743
|
+
retryable: false
|
|
13744
|
+
});
|
|
13745
|
+
}
|
|
13746
|
+
ctx.warnings.push({
|
|
13747
|
+
code: "option_ignored",
|
|
13748
|
+
field: "outputFormat",
|
|
13749
|
+
from: format,
|
|
13750
|
+
to: "png",
|
|
13751
|
+
message: `${ctx.model.id} has no outputFormat "${format}"; using png`
|
|
13752
|
+
});
|
|
13753
|
+
return "png";
|
|
13754
|
+
}
|
|
13755
|
+
function refuseOrDrop(ctx, field, message) {
|
|
13756
|
+
if ((ctx.call.onUnsupported ?? "error") === "error") {
|
|
13757
|
+
throw new ModelKitError({
|
|
13758
|
+
code: "unsupported_option",
|
|
13759
|
+
message,
|
|
13760
|
+
provider: "luma",
|
|
13761
|
+
model: ctx.model.id,
|
|
13762
|
+
retryable: false
|
|
13763
|
+
});
|
|
13764
|
+
}
|
|
13765
|
+
ctx.warnings.push({ code: "option_ignored", field, message });
|
|
13766
|
+
}
|
|
13767
|
+
function lumaVideoMode(ctx) {
|
|
13768
|
+
const mode = LUMA_VIDEO_MODES.get(ctx.model.id);
|
|
13769
|
+
if (mode === void 0) {
|
|
13770
|
+
throw new ModelKitError({
|
|
13771
|
+
code: "unsupported_option",
|
|
13772
|
+
message: `luma routes ray-3.2 rows by catalog id; "${ctx.model.id}" is not a luma video row`,
|
|
13773
|
+
provider: "luma",
|
|
13774
|
+
model: ctx.model.id,
|
|
13775
|
+
retryable: false
|
|
13776
|
+
});
|
|
13777
|
+
}
|
|
13778
|
+
return mode;
|
|
13779
|
+
}
|
|
13780
|
+
function reframeTooTall(req) {
|
|
13781
|
+
const vertical = req.aspectRatio === "9:16" || req.aspectRatio === "3:4";
|
|
13782
|
+
return vertical && req.resolution === "1080p";
|
|
13783
|
+
}
|
|
13784
|
+
function sentResolution(req, mode) {
|
|
13785
|
+
return mode === "reframe" && reframeTooTall(req) ? "720p" : req.resolution;
|
|
13786
|
+
}
|
|
13787
|
+
function lumaReframeResolution(req, ctx) {
|
|
13788
|
+
const requested = req.resolution;
|
|
13789
|
+
if (requested === void 0 || !reframeTooTall(req)) return requested;
|
|
13790
|
+
const message = `${ctx.model.id} renders 9:16 and 3:4 reframes at up to 720p`;
|
|
13791
|
+
if ((ctx.call.onUnsupported ?? "error") === "error") {
|
|
13792
|
+
throw new ModelKitError({
|
|
13793
|
+
code: "unsupported_option",
|
|
13794
|
+
message,
|
|
13795
|
+
provider: "luma",
|
|
13796
|
+
model: ctx.model.id,
|
|
13797
|
+
retryable: false
|
|
13798
|
+
});
|
|
13799
|
+
}
|
|
13800
|
+
ctx.warnings.push({
|
|
13801
|
+
code: "resolution_coerced",
|
|
13802
|
+
field: "resolution",
|
|
13803
|
+
from: requested,
|
|
13804
|
+
to: "720p",
|
|
13805
|
+
message
|
|
13806
|
+
});
|
|
13807
|
+
return "720p";
|
|
13808
|
+
}
|
|
13809
|
+
var lumaGenerationSchema = z25.looseObject({
|
|
13810
|
+
id: z25.string(),
|
|
13811
|
+
state: z25.string().optional(),
|
|
13812
|
+
output: z25.array(
|
|
13813
|
+
z25.looseObject({
|
|
13814
|
+
type: z25.string().optional(),
|
|
13815
|
+
url: z25.string().optional()
|
|
13816
|
+
})
|
|
13817
|
+
).optional(),
|
|
13818
|
+
failure_reason: z25.string().optional().nullable(),
|
|
13819
|
+
failure_code: z25.string().optional().nullable()
|
|
13820
|
+
});
|
|
13821
|
+
function lumaFailure(ctx, code, reason) {
|
|
13822
|
+
const detail = reason ?? code ?? "unknown_error";
|
|
13823
|
+
const message = `Luma generation failed: ${detail}`;
|
|
13824
|
+
switch (code) {
|
|
13825
|
+
case "content_moderated":
|
|
13826
|
+
return new ModelKitError({
|
|
13827
|
+
code: "content_blocked",
|
|
13828
|
+
message,
|
|
13829
|
+
provider: "luma",
|
|
13830
|
+
model: ctx.model.id,
|
|
13831
|
+
retryable: false
|
|
13832
|
+
});
|
|
13833
|
+
case "rate_limited":
|
|
13834
|
+
return new ModelKitError({
|
|
13835
|
+
code: "rate_limited",
|
|
13836
|
+
message,
|
|
13837
|
+
provider: "luma",
|
|
13838
|
+
model: ctx.model.id
|
|
13839
|
+
});
|
|
13840
|
+
case "generation_failed":
|
|
13841
|
+
case "output_not_found":
|
|
13842
|
+
return new ModelKitError({
|
|
13843
|
+
code: "provider_rejected",
|
|
13844
|
+
message,
|
|
13845
|
+
provider: "luma",
|
|
13846
|
+
model: ctx.model.id,
|
|
13847
|
+
retryable: true
|
|
13848
|
+
});
|
|
13849
|
+
case "budget_exhausted":
|
|
13850
|
+
return new ModelKitError({
|
|
13851
|
+
code: "provider_billing",
|
|
13852
|
+
message,
|
|
13853
|
+
provider: "luma",
|
|
13854
|
+
model: ctx.model.id,
|
|
13855
|
+
retryable: false
|
|
13856
|
+
});
|
|
13857
|
+
case "image_too_large":
|
|
13858
|
+
case "unsupported_format":
|
|
13859
|
+
return new ModelKitError({
|
|
13860
|
+
code: "unsupported_option",
|
|
13861
|
+
message,
|
|
13862
|
+
provider: "luma",
|
|
13863
|
+
model: ctx.model.id,
|
|
13864
|
+
retryable: false
|
|
13865
|
+
});
|
|
13866
|
+
default:
|
|
13867
|
+
return new ModelKitError({
|
|
13868
|
+
code: "provider_rejected",
|
|
13869
|
+
message,
|
|
13870
|
+
provider: "luma",
|
|
13871
|
+
model: ctx.model.id,
|
|
13872
|
+
retryable: false
|
|
13873
|
+
});
|
|
13874
|
+
}
|
|
13875
|
+
}
|
|
13876
|
+
function requestInit2(ctx, key, body) {
|
|
13877
|
+
const init = {
|
|
13878
|
+
method: body !== void 0 ? "POST" : "GET",
|
|
13879
|
+
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" }
|
|
13880
|
+
};
|
|
13881
|
+
if (body !== void 0) init.body = body;
|
|
13882
|
+
if (ctx.signal !== void 0) init.signal = ctx.signal;
|
|
13883
|
+
return init;
|
|
13884
|
+
}
|
|
13885
|
+
async function lumaRequest(ctx, url, body) {
|
|
13886
|
+
const key = lumaKey(ctx);
|
|
13887
|
+
let res;
|
|
13888
|
+
try {
|
|
13889
|
+
res = await ctx.fetch(url, requestInit2(ctx, key, body));
|
|
13890
|
+
} catch (cause) {
|
|
13891
|
+
throw classifyThrown("luma", cause, ctx.model.id);
|
|
13892
|
+
}
|
|
13893
|
+
if (!res.ok) {
|
|
13894
|
+
throw classifyHttpError(res.status, await readBody(res), "luma", ctx.model.id);
|
|
13895
|
+
}
|
|
13896
|
+
return res;
|
|
13897
|
+
}
|
|
13898
|
+
async function submitGeneration(ctx, body) {
|
|
13899
|
+
const retryOptions = mediaRetryOptions(ctx.call, ctx.signal);
|
|
13900
|
+
const res = await withRetry(
|
|
13901
|
+
() => lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations`, JSON.stringify(body)),
|
|
13902
|
+
retryOptions
|
|
13903
|
+
);
|
|
13904
|
+
const parsed = lumaGenerationSchema.safeParse(await res.json());
|
|
13905
|
+
if (!parsed.success) {
|
|
13906
|
+
throw new ModelKitError({
|
|
13907
|
+
code: "provider_rejected",
|
|
13908
|
+
message: "Luma submit returned no generation id",
|
|
13909
|
+
provider: "luma",
|
|
13910
|
+
model: ctx.model.id,
|
|
13911
|
+
retryable: false
|
|
13912
|
+
});
|
|
13913
|
+
}
|
|
13914
|
+
return parsed.data;
|
|
13915
|
+
}
|
|
13916
|
+
async function readGeneration(ctx, id) {
|
|
13917
|
+
const res = await lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations/${id}`);
|
|
13918
|
+
const payload = JsonValueSchema.parse(await res.json());
|
|
13919
|
+
const parsed = lumaGenerationSchema.safeParse(payload);
|
|
13920
|
+
if (!parsed.success) {
|
|
13921
|
+
throw new ModelKitError({
|
|
13922
|
+
code: "provider_rejected",
|
|
13923
|
+
message: "Luma returned an unreadable generation",
|
|
13924
|
+
provider: "luma",
|
|
13925
|
+
model: ctx.model.id,
|
|
13926
|
+
retryable: false
|
|
13927
|
+
});
|
|
13928
|
+
}
|
|
13929
|
+
return parsed.data;
|
|
13930
|
+
}
|
|
13931
|
+
function outputUrl(generation, type) {
|
|
13932
|
+
const outputs = generation.output ?? [];
|
|
13933
|
+
const match = outputs.find((item) => item.type === type && item.url);
|
|
13934
|
+
if (match?.url) return match.url;
|
|
13935
|
+
const fallback = outputs.find((item) => item.url);
|
|
13936
|
+
return fallback?.url;
|
|
13937
|
+
}
|
|
13938
|
+
async function readGenerationOnce(ctx, id) {
|
|
13939
|
+
try {
|
|
13940
|
+
return await readGeneration(ctx, id);
|
|
13941
|
+
} catch (cause) {
|
|
13942
|
+
if (ctx.call.maxRetries === 0) throw cause;
|
|
13943
|
+
if (isModelKitError(cause) && (cause.code === "network" || cause.status === 429 || (cause.status ?? 0) >= 500)) {
|
|
13944
|
+
return void 0;
|
|
13945
|
+
}
|
|
13946
|
+
throw cause;
|
|
13947
|
+
}
|
|
13948
|
+
}
|
|
13949
|
+
async function checkGeneration(ctx, id, type) {
|
|
13950
|
+
const generation = await readGenerationOnce(ctx, id);
|
|
13951
|
+
if (generation === void 0) return void 0;
|
|
13952
|
+
if (generation.state === "completed") {
|
|
13953
|
+
const url = outputUrl(generation, type);
|
|
13954
|
+
if (!url) {
|
|
13955
|
+
throw new ModelKitError({
|
|
13956
|
+
code: "provider_rejected",
|
|
13957
|
+
message: "Luma completed without an output URL",
|
|
13958
|
+
provider: "luma",
|
|
13959
|
+
model: ctx.model.id,
|
|
13960
|
+
retryable: false
|
|
13961
|
+
});
|
|
13962
|
+
}
|
|
13963
|
+
return url;
|
|
13964
|
+
}
|
|
13965
|
+
if (generation.state === "failed") {
|
|
13966
|
+
throw lumaFailure(
|
|
13967
|
+
ctx,
|
|
13968
|
+
generation.failure_code ?? void 0,
|
|
13969
|
+
generation.failure_reason ?? void 0
|
|
13970
|
+
);
|
|
13971
|
+
}
|
|
13972
|
+
return void 0;
|
|
13973
|
+
}
|
|
13974
|
+
async function downloadBytes(ctx, url, fallback) {
|
|
13975
|
+
let bytes;
|
|
13976
|
+
let header;
|
|
13977
|
+
try {
|
|
13978
|
+
const out = await mediaRefToBytes({ url }, ctx.fetch, {
|
|
13979
|
+
...ctx.signal !== void 0 && { signal: ctx.signal },
|
|
13980
|
+
provider: "luma",
|
|
13981
|
+
model: ctx.model.id
|
|
13982
|
+
});
|
|
13983
|
+
bytes = out.bytes;
|
|
13984
|
+
header = out.mime;
|
|
13985
|
+
} catch (cause) {
|
|
13986
|
+
throw classifyThrown("luma", cause, ctx.model.id);
|
|
13987
|
+
}
|
|
13988
|
+
const kind = fallback.split("/")[0];
|
|
13989
|
+
const usable = header !== void 0 && header.startsWith(`${kind}/`);
|
|
13990
|
+
return { bytes, mime: usable ? header : fallback };
|
|
13991
|
+
}
|
|
13992
|
+
function imageUsage2(ctx) {
|
|
13993
|
+
return {
|
|
13994
|
+
model: ctx.model.id,
|
|
13995
|
+
provider: "luma",
|
|
13996
|
+
modality: "IMAGE",
|
|
13997
|
+
unit: "images",
|
|
13998
|
+
quantity: 1,
|
|
13999
|
+
imageSize: "2K"
|
|
14000
|
+
};
|
|
14001
|
+
}
|
|
14002
|
+
var GENERATE_SECONDS = 5;
|
|
14003
|
+
var MAX_PLAUSIBLE_SECONDS = 60;
|
|
14004
|
+
function billedSeconds(req, mode, bytes) {
|
|
14005
|
+
if (mode === "generate") return GENERATE_SECONDS;
|
|
14006
|
+
const measured = mp4DurationSeconds(bytes);
|
|
14007
|
+
const source2 = req.sourceVideo;
|
|
14008
|
+
const length = measured !== void 0 && measured > 0 && measured <= MAX_PLAUSIBLE_SECONDS ? measured : source2 !== void 0 && "url" in source2 ? source2.durationSeconds : void 0;
|
|
14009
|
+
return Math.max(length ?? 0, GENERATE_SECONDS);
|
|
14010
|
+
}
|
|
14011
|
+
function videoUsage4(ctx, req, mode, bytes) {
|
|
14012
|
+
const seconds3 = billedSeconds(req, mode, bytes);
|
|
14013
|
+
const event = {
|
|
14014
|
+
model: ctx.model.id,
|
|
14015
|
+
provider: "luma",
|
|
14016
|
+
modality: "VIDEO",
|
|
14017
|
+
unit: "seconds",
|
|
14018
|
+
quantity: seconds3,
|
|
14019
|
+
durationSeconds: seconds3
|
|
14020
|
+
};
|
|
14021
|
+
const resolution = sentResolution(req, mode);
|
|
14022
|
+
if (resolution !== void 0) event.resolution = resolution;
|
|
14023
|
+
return event;
|
|
14024
|
+
}
|
|
14025
|
+
function imageBody(req, ctx, outputFormat) {
|
|
14026
|
+
const prompt = checkPrompt(req, ctx);
|
|
14027
|
+
const model = ctx.model.providerModelId;
|
|
14028
|
+
const ratio = req.aspectRatio !== "adaptive" ? req.aspectRatio : void 0;
|
|
14029
|
+
const [source2, ...rest] = req.references ?? [];
|
|
14030
|
+
if (source2 === void 0) {
|
|
14031
|
+
const body2 = { model, type: "image", prompt };
|
|
14032
|
+
if (ratio !== void 0) body2["aspect_ratio"] = ratio;
|
|
14033
|
+
if (outputFormat !== void 0) body2["output_format"] = outputFormat;
|
|
14034
|
+
return body2;
|
|
14035
|
+
}
|
|
14036
|
+
if (ratio !== void 0) {
|
|
14037
|
+
ctx.warnings.push({
|
|
14038
|
+
code: "option_ignored",
|
|
14039
|
+
field: "aspectRatio",
|
|
14040
|
+
message: `${ctx.model.id} keeps the source image's aspect ratio on an edit`
|
|
14041
|
+
});
|
|
14042
|
+
}
|
|
14043
|
+
const body = {
|
|
14044
|
+
model,
|
|
14045
|
+
type: "image_edit",
|
|
14046
|
+
prompt,
|
|
14047
|
+
source: imageRef(source2)
|
|
14048
|
+
};
|
|
14049
|
+
if (rest.length > 0) body["image_ref"] = rest.map(imageRef);
|
|
14050
|
+
if (outputFormat !== void 0) body["output_format"] = outputFormat;
|
|
14051
|
+
return body;
|
|
14052
|
+
}
|
|
14053
|
+
function videoBody(req, ctx, mode) {
|
|
14054
|
+
const prompt = checkPrompt(req, ctx);
|
|
14055
|
+
const model = ctx.model.providerModelId;
|
|
14056
|
+
const hasReferences = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
|
|
14057
|
+
if (hasReferences) {
|
|
14058
|
+
refuseOrDrop(
|
|
14059
|
+
ctx,
|
|
14060
|
+
"referenceImages",
|
|
14061
|
+
`${ctx.model.id} takes no reference images, videos or audio`
|
|
14062
|
+
);
|
|
14063
|
+
}
|
|
14064
|
+
if (mode === "generate") {
|
|
14065
|
+
const body = {
|
|
14066
|
+
model,
|
|
14067
|
+
type: "video",
|
|
14068
|
+
prompt,
|
|
14069
|
+
video: {
|
|
14070
|
+
...req.resolution !== void 0 && { resolution: req.resolution },
|
|
14071
|
+
duration: "5s",
|
|
14072
|
+
...req.firstFrame !== void 0 && { start_frame: imageRef(req.firstFrame) },
|
|
14073
|
+
...req.lastFrame !== void 0 && { end_frame: imageRef(req.lastFrame) }
|
|
14074
|
+
}
|
|
14075
|
+
};
|
|
14076
|
+
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
14077
|
+
body["aspect_ratio"] = req.aspectRatio;
|
|
14078
|
+
}
|
|
14079
|
+
return body;
|
|
14080
|
+
}
|
|
14081
|
+
const sourceVideo = req.sourceVideo;
|
|
14082
|
+
if (!sourceVideo) {
|
|
14083
|
+
throw new ModelKitError({
|
|
14084
|
+
code: "missing_input",
|
|
14085
|
+
message: `${ctx.model.id} requires sourceVideo`,
|
|
14086
|
+
provider: "luma",
|
|
14087
|
+
model: ctx.model.id,
|
|
14088
|
+
retryable: false
|
|
14089
|
+
});
|
|
14090
|
+
}
|
|
14091
|
+
if (mode === "edit") {
|
|
14092
|
+
if (req.lastFrame !== void 0) {
|
|
14093
|
+
refuseOrDrop(ctx, "lastFrame", `${ctx.model.id} takes no end frame`);
|
|
14094
|
+
}
|
|
14095
|
+
const body = {
|
|
14096
|
+
model,
|
|
14097
|
+
type: "video_edit",
|
|
14098
|
+
prompt,
|
|
14099
|
+
source: videoRef(sourceVideo),
|
|
14100
|
+
video: {
|
|
14101
|
+
...req.resolution !== void 0 && { resolution: req.resolution },
|
|
14102
|
+
...req.firstFrame !== void 0 && { start_frame: imageRef(req.firstFrame) },
|
|
14103
|
+
edit: { auto_controls: true }
|
|
14104
|
+
}
|
|
14105
|
+
};
|
|
14106
|
+
return body;
|
|
14107
|
+
}
|
|
14108
|
+
if (req.firstFrame !== void 0) {
|
|
14109
|
+
refuseOrDrop(ctx, "firstFrame", `${ctx.model.id} takes no start frame`);
|
|
14110
|
+
}
|
|
14111
|
+
if (req.lastFrame !== void 0) {
|
|
14112
|
+
refuseOrDrop(ctx, "lastFrame", `${ctx.model.id} takes no end frame`);
|
|
14113
|
+
}
|
|
14114
|
+
const aspectRatio = req.aspectRatio;
|
|
14115
|
+
if (aspectRatio === void 0 || aspectRatio === "adaptive") {
|
|
14116
|
+
throw new ModelKitError({
|
|
14117
|
+
code: "missing_input",
|
|
14118
|
+
message: `${ctx.model.id} needs an aspectRatio target`,
|
|
14119
|
+
provider: "luma",
|
|
14120
|
+
model: ctx.model.id,
|
|
14121
|
+
retryable: false
|
|
14122
|
+
});
|
|
14123
|
+
}
|
|
14124
|
+
const resolution = lumaReframeResolution(req, ctx);
|
|
14125
|
+
return {
|
|
14126
|
+
model,
|
|
14127
|
+
type: "video_reframe",
|
|
14128
|
+
prompt,
|
|
14129
|
+
aspect_ratio: aspectRatio,
|
|
14130
|
+
source: videoRef(sourceVideo),
|
|
14131
|
+
video: { ...resolution !== void 0 && { resolution } }
|
|
14132
|
+
};
|
|
14133
|
+
}
|
|
14134
|
+
async function generateLumaImage(req, ctx) {
|
|
14135
|
+
throwIfAborted(ctx.signal);
|
|
14136
|
+
lumaKey(ctx);
|
|
14137
|
+
if (!LUMA_IMAGE_MODEL_IDS.has(ctx.model.providerModelId.toLowerCase())) {
|
|
14138
|
+
throw new ModelKitError({
|
|
14139
|
+
code: "unsupported_option",
|
|
14140
|
+
message: `luma has no image mapping for "${ctx.model.providerModelId}"`,
|
|
14141
|
+
provider: "luma",
|
|
14142
|
+
model: ctx.model.id,
|
|
14143
|
+
retryable: false
|
|
14144
|
+
});
|
|
14145
|
+
}
|
|
14146
|
+
const format = lumaOutputFormat(req, ctx);
|
|
14147
|
+
const created = await submitGeneration(ctx, imageBody(req, ctx, format));
|
|
14148
|
+
const url = await pollUntil(checkGeneration.bind(null, ctx, created.id, "image"), {
|
|
14149
|
+
intervalMs: IMAGE_POLL_INTERVAL_MS,
|
|
14150
|
+
timeoutMs: IMAGE_TIMEOUT_MS,
|
|
14151
|
+
...ctx.signal !== void 0 && { signal: ctx.signal }
|
|
14152
|
+
});
|
|
14153
|
+
const image = await downloadBytes(ctx, url, format === "jpeg" ? "image/jpeg" : "image/png");
|
|
14154
|
+
return {
|
|
14155
|
+
images: [image],
|
|
14156
|
+
usage: imageUsage2(ctx),
|
|
14157
|
+
raw: created
|
|
14158
|
+
};
|
|
14159
|
+
}
|
|
14160
|
+
function lumaVideoJob(ctx, req, mode, id) {
|
|
14161
|
+
return {
|
|
14162
|
+
jobId: id,
|
|
14163
|
+
async poll() {
|
|
14164
|
+
const generation = await readGenerationOnce(ctx, id);
|
|
14165
|
+
if (generation?.state === "failed") return { status: "failed" };
|
|
14166
|
+
if (generation?.state === "completed") return { status: "succeeded" };
|
|
14167
|
+
return { status: "pending" };
|
|
14168
|
+
},
|
|
14169
|
+
async result(opts) {
|
|
14170
|
+
const signal = opts?.signal ?? ctx.signal;
|
|
14171
|
+
const url = await pollUntil(checkGeneration.bind(null, ctx, id, "video"), {
|
|
14172
|
+
intervalMs: opts?.pollIntervalMs ?? VIDEO_POLL_INTERVAL_MS,
|
|
14173
|
+
timeoutMs: opts?.timeoutMs ?? VIDEO_TIMEOUT_MS,
|
|
14174
|
+
...signal !== void 0 && { signal }
|
|
14175
|
+
});
|
|
14176
|
+
const video = await downloadBytes(ctx, url, "video/mp4");
|
|
14177
|
+
const result = {
|
|
14178
|
+
video,
|
|
14179
|
+
usage: videoUsage4(ctx, req, mode, video.bytes),
|
|
14180
|
+
raw: { id }
|
|
14181
|
+
};
|
|
14182
|
+
return result;
|
|
14183
|
+
}
|
|
14184
|
+
};
|
|
14185
|
+
}
|
|
14186
|
+
async function generateLumaVideo(req, ctx) {
|
|
14187
|
+
throwIfAborted(ctx.signal);
|
|
14188
|
+
lumaKey(ctx);
|
|
14189
|
+
if (ctx.model.providerModelId.toLowerCase() !== LUMA_VIDEO_MODEL_ID) {
|
|
14190
|
+
throw new ModelKitError({
|
|
14191
|
+
code: "unsupported_option",
|
|
14192
|
+
message: `luma has no video mapping for "${ctx.model.providerModelId}"`,
|
|
14193
|
+
provider: "luma",
|
|
14194
|
+
model: ctx.model.id,
|
|
14195
|
+
retryable: false
|
|
14196
|
+
});
|
|
14197
|
+
}
|
|
14198
|
+
const mode = lumaVideoMode(ctx);
|
|
14199
|
+
const created = await submitGeneration(ctx, videoBody(req, ctx, mode));
|
|
14200
|
+
return lumaVideoJob(ctx, req, mode, created.id);
|
|
14201
|
+
}
|
|
14202
|
+
var lumaAdapter = {
|
|
14203
|
+
id: "luma",
|
|
14204
|
+
generateImage: generateLumaImage,
|
|
14205
|
+
generateVideo: generateLumaVideo,
|
|
14206
|
+
resumeVideo: (req, jobId, ctx) => {
|
|
14207
|
+
throwIfAborted(ctx.signal);
|
|
14208
|
+
lumaKey(ctx);
|
|
14209
|
+
return lumaVideoJob(ctx, req, lumaVideoMode(ctx), jobId);
|
|
14210
|
+
}
|
|
14211
|
+
};
|
|
14212
|
+
|
|
13421
14213
|
// src/adapters/openai-image.ts
|
|
13422
14214
|
import OpenAI from "openai";
|
|
13423
|
-
import { z as
|
|
14215
|
+
import { z as z26 } from "zod";
|
|
13424
14216
|
var MAX_EDIT_REFERENCES = 16;
|
|
13425
14217
|
function aspectRatioToSize(ratio, tier) {
|
|
13426
14218
|
const TIER_LONG_EDGE = {
|
|
@@ -13503,9 +14295,9 @@ function toProviderError2(cause, ctx) {
|
|
|
13503
14295
|
ctx.model.id
|
|
13504
14296
|
);
|
|
13505
14297
|
}
|
|
13506
|
-
var openaiUsageSchema =
|
|
13507
|
-
input_tokens:
|
|
13508
|
-
output_tokens:
|
|
14298
|
+
var openaiUsageSchema = z26.object({
|
|
14299
|
+
input_tokens: z26.number().optional(),
|
|
14300
|
+
output_tokens: z26.number().optional()
|
|
13509
14301
|
});
|
|
13510
14302
|
var openaiImageAdapter = {
|
|
13511
14303
|
id: "openai-image",
|
|
@@ -13917,13 +14709,13 @@ var prodiaAdapter = {
|
|
|
13917
14709
|
import Replicate from "replicate";
|
|
13918
14710
|
|
|
13919
14711
|
// src/adapters/replicate-http.ts
|
|
13920
|
-
import { z as
|
|
13921
|
-
var predictionSchema =
|
|
13922
|
-
id:
|
|
13923
|
-
status:
|
|
14712
|
+
import { z as z27 } from "zod";
|
|
14713
|
+
var predictionSchema = z27.object({
|
|
14714
|
+
id: z27.string(),
|
|
14715
|
+
status: z27.string(),
|
|
13924
14716
|
output: JsonValueSchema.optional(),
|
|
13925
14717
|
error: JsonValueSchema.optional(),
|
|
13926
|
-
metrics:
|
|
14718
|
+
metrics: z27.object({ predict_time: z27.number().optional() }).optional()
|
|
13927
14719
|
});
|
|
13928
14720
|
function createReplicateHttpClient(opts) {
|
|
13929
14721
|
async function request(path, body, signal) {
|
|
@@ -13974,7 +14766,7 @@ function createReplicateHttpClient(opts) {
|
|
|
13974
14766
|
}
|
|
13975
14767
|
|
|
13976
14768
|
// src/adapters/replicate.ts
|
|
13977
|
-
import { z as
|
|
14769
|
+
import { z as z28 } from "zod";
|
|
13978
14770
|
var POLL_INTERVAL_MS = 1e3;
|
|
13979
14771
|
var POLL_TIMEOUT_MS = 15 * 6e4;
|
|
13980
14772
|
var defaultReplicateDeps = {
|
|
@@ -14014,8 +14806,8 @@ function route(providerModelId) {
|
|
|
14014
14806
|
if (!providerModelId.includes("/")) return { version: providerModelId };
|
|
14015
14807
|
return { model: providerModelId };
|
|
14016
14808
|
}
|
|
14017
|
-
var replicateResponseStatusSchema =
|
|
14018
|
-
response:
|
|
14809
|
+
var replicateResponseStatusSchema = z28.object({
|
|
14810
|
+
response: z28.object({ status: z28.number() }).partial()
|
|
14019
14811
|
});
|
|
14020
14812
|
function replicateError(cause, ctx) {
|
|
14021
14813
|
if (isModelKitError(cause)) return cause;
|
|
@@ -14024,10 +14816,6 @@ function replicateError(cause, ctx) {
|
|
|
14024
14816
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
14025
14817
|
return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
|
|
14026
14818
|
}
|
|
14027
|
-
function baseModelId(providerModelId) {
|
|
14028
|
-
const colon = providerModelId.indexOf(":");
|
|
14029
|
-
return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
|
|
14030
|
-
}
|
|
14031
14819
|
function predictionErrorBody(cause) {
|
|
14032
14820
|
const parsed = JsonValueSchema.safeParse(cause);
|
|
14033
14821
|
if (parsed.success) return parsed.data;
|
|
@@ -14042,7 +14830,7 @@ function isUrlFn(value) {
|
|
|
14042
14830
|
function extractOutputUrl(output) {
|
|
14043
14831
|
const root = Array.isArray(output) ? output[0] : output;
|
|
14044
14832
|
if (root === void 0) throw noOutput();
|
|
14045
|
-
const asString =
|
|
14833
|
+
const asString = z28.string().safeParse(root);
|
|
14046
14834
|
if (asString.success && asString.data) return asString.data;
|
|
14047
14835
|
if (root instanceof URL) return root.href;
|
|
14048
14836
|
if (isObjectOutput(root)) {
|
|
@@ -14051,15 +14839,15 @@ function extractOutputUrl(output) {
|
|
|
14051
14839
|
if (urlValue !== void 0 && isUrlFn(urlValue)) {
|
|
14052
14840
|
const called = urlValue();
|
|
14053
14841
|
if (called instanceof URL) return called.href;
|
|
14054
|
-
const calledString =
|
|
14842
|
+
const calledString = z28.string().safeParse(called);
|
|
14055
14843
|
if (calledString.success && calledString.data) return calledString.data;
|
|
14056
14844
|
} else {
|
|
14057
|
-
const direct =
|
|
14845
|
+
const direct = z28.string().safeParse(urlValue);
|
|
14058
14846
|
if (direct.success && direct.data) return direct.data;
|
|
14059
14847
|
}
|
|
14060
14848
|
}
|
|
14061
14849
|
if ("default" in root) {
|
|
14062
|
-
const fallback =
|
|
14850
|
+
const fallback = z28.string().safeParse(root.default);
|
|
14063
14851
|
if (fallback.success && fallback.data) return fallback.data;
|
|
14064
14852
|
}
|
|
14065
14853
|
}
|
|
@@ -14120,7 +14908,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
14120
14908
|
}
|
|
14121
14909
|
return void 0;
|
|
14122
14910
|
}, pollOpts);
|
|
14123
|
-
const predictTime =
|
|
14911
|
+
const predictTime = z28.number().safeParse(done.metrics?.predict_time);
|
|
14124
14912
|
if (done.output === void 0) throw noOutput();
|
|
14125
14913
|
return {
|
|
14126
14914
|
url: extractOutputUrl(done.output),
|
|
@@ -14128,7 +14916,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
14128
14916
|
raw: done
|
|
14129
14917
|
};
|
|
14130
14918
|
}
|
|
14131
|
-
function
|
|
14919
|
+
function imageUsage3(ctx, req) {
|
|
14132
14920
|
const event = {
|
|
14133
14921
|
model: ctx.model.id,
|
|
14134
14922
|
provider: "replicate",
|
|
@@ -14140,7 +14928,7 @@ function imageUsage2(ctx, req) {
|
|
|
14140
14928
|
if (req.quality !== void 0) event.imageQuality = req.quality;
|
|
14141
14929
|
return event;
|
|
14142
14930
|
}
|
|
14143
|
-
function
|
|
14931
|
+
function videoUsage5(ctx, req) {
|
|
14144
14932
|
const event = {
|
|
14145
14933
|
model: ctx.model.id,
|
|
14146
14934
|
provider: "replicate",
|
|
@@ -14181,17 +14969,7 @@ var REPLICATE_IMAGE_KINDS = {
|
|
|
14181
14969
|
"qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
|
|
14182
14970
|
};
|
|
14183
14971
|
function imageKind(providerModelId) {
|
|
14184
|
-
return REPLICATE_IMAGE_KINDS[
|
|
14185
|
-
}
|
|
14186
|
-
var REPLICATE_VIDEO_KINDS = {
|
|
14187
|
-
"kling-video/v2.5-turbo/pro/image-to-video": "kling",
|
|
14188
|
-
"kling-video/v3.0/pro/image-to-video": "kling",
|
|
14189
|
-
"kwaivgi/kling-v3-video": "kling",
|
|
14190
|
-
"kwaivgi/kling-v3-omni-video": "kling-omni",
|
|
14191
|
-
"minimax/hailuo-02": "hailuo"
|
|
14192
|
-
};
|
|
14193
|
-
function videoKind(providerModelId) {
|
|
14194
|
-
return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)];
|
|
14972
|
+
return REPLICATE_IMAGE_KINDS[replicateBaseModelId(providerModelId)] ?? "generic";
|
|
14195
14973
|
}
|
|
14196
14974
|
function isReplicateVideoKnown(providerModelId) {
|
|
14197
14975
|
return videoKind(providerModelId) !== void 0;
|
|
@@ -14202,7 +14980,7 @@ var REPLICATE_AUDIO_KINDS = {
|
|
|
14202
14980
|
"google/lyria-2": "lyria"
|
|
14203
14981
|
};
|
|
14204
14982
|
function audioKind(providerModelId) {
|
|
14205
|
-
return REPLICATE_AUDIO_KINDS[
|
|
14983
|
+
return REPLICATE_AUDIO_KINDS[replicateBaseModelId(providerModelId)];
|
|
14206
14984
|
}
|
|
14207
14985
|
function isReplicateAudioKnown(providerModelId) {
|
|
14208
14986
|
return audioKind(providerModelId) !== void 0;
|
|
@@ -14376,7 +15154,7 @@ async function generateReplicateImage(req, ctx, deps) {
|
|
|
14376
15154
|
}
|
|
14377
15155
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
14378
15156
|
const file = await download(ctx, url);
|
|
14379
|
-
const usage3 =
|
|
15157
|
+
const usage3 = imageUsage3(ctx, req);
|
|
14380
15158
|
usage3.quantity = predictTime;
|
|
14381
15159
|
return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage3, raw, outputUrl: url };
|
|
14382
15160
|
}
|
|
@@ -14406,14 +15184,6 @@ function replicateVideoResolution(providerModelId, req) {
|
|
|
14406
15184
|
if (kind === "hailuo") return hailuoResolution(req);
|
|
14407
15185
|
return req.resolution;
|
|
14408
15186
|
}
|
|
14409
|
-
var KLING_TIERS = [
|
|
14410
|
-
{ mode: "standard", resolution: "720p" },
|
|
14411
|
-
{ mode: "pro", resolution: "1080p" },
|
|
14412
|
-
{ mode: "4k", resolution: "4k" }
|
|
14413
|
-
];
|
|
14414
|
-
function klingTier(req) {
|
|
14415
|
-
return KLING_TIERS.find((tier) => tier.resolution === req.resolution) ?? KLING_TIERS.find((tier) => tier.mode === req.mode) ?? KLING_TIERS[0];
|
|
14416
|
-
}
|
|
14417
15187
|
function klingOmniInput(req) {
|
|
14418
15188
|
const input = {
|
|
14419
15189
|
prompt: req.prompt,
|
|
@@ -14491,7 +15261,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
14491
15261
|
throw replicateError(cause, ctx);
|
|
14492
15262
|
}
|
|
14493
15263
|
if (current.status === "succeeded") {
|
|
14494
|
-
const predictTime =
|
|
15264
|
+
const predictTime = z28.number().safeParse(current.metrics?.predict_time);
|
|
14495
15265
|
if (current.output === void 0) throw noOutput();
|
|
14496
15266
|
return {
|
|
14497
15267
|
url: extractOutputUrl(current.output),
|
|
@@ -14510,7 +15280,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
14510
15280
|
return void 0;
|
|
14511
15281
|
};
|
|
14512
15282
|
const toResult = (done) => {
|
|
14513
|
-
const usage3 =
|
|
15283
|
+
const usage3 = videoUsage5(ctx, req);
|
|
14514
15284
|
usage3.quantity = done.predictTime;
|
|
14515
15285
|
return { video: { url: done.url }, usage: usage3, raw: done.raw };
|
|
14516
15286
|
};
|
|
@@ -14633,7 +15403,7 @@ async function generateReplicateAudio(req, ctx, deps) {
|
|
|
14633
15403
|
// src/adapters/xai-video.ts
|
|
14634
15404
|
import { experimental_generateVideo } from "ai";
|
|
14635
15405
|
import { createXai as createXai2 } from "@ai-sdk/xai";
|
|
14636
|
-
import { z as
|
|
15406
|
+
import { z as z29 } from "zod";
|
|
14637
15407
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
14638
15408
|
var POLL_TIMEOUT_MS2 = 15 * 6e4;
|
|
14639
15409
|
var defaultXaiDeps = {
|
|
@@ -14646,8 +15416,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
14646
15416
|
};
|
|
14647
15417
|
}
|
|
14648
15418
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
14649
|
-
var xaiResponseStatusSchema =
|
|
14650
|
-
response:
|
|
15419
|
+
var xaiResponseStatusSchema = z29.object({
|
|
15420
|
+
response: z29.object({ status: z29.number() }).partial()
|
|
14651
15421
|
});
|
|
14652
15422
|
function xaiError(cause, ctx) {
|
|
14653
15423
|
const info = describeThrown(cause);
|
|
@@ -14655,12 +15425,12 @@ function xaiError(cause, ctx) {
|
|
|
14655
15425
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
14656
15426
|
return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
|
|
14657
15427
|
}
|
|
14658
|
-
var xaiMetaSchema =
|
|
15428
|
+
var xaiMetaSchema = z29.object({
|
|
14659
15429
|
videoUrl: JsonValueSchema.optional(),
|
|
14660
15430
|
costInUsdTicks: JsonValueSchema.optional(),
|
|
14661
15431
|
duration: JsonValueSchema.optional()
|
|
14662
15432
|
});
|
|
14663
|
-
var xaiProviderMetadataSchema =
|
|
15433
|
+
var xaiProviderMetadataSchema = z29.object({ xai: xaiMetaSchema });
|
|
14664
15434
|
function metaOf(result) {
|
|
14665
15435
|
const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
|
|
14666
15436
|
if (!parsed.success) return {};
|
|
@@ -14776,7 +15546,7 @@ async function mapResult(ctx, req, result) {
|
|
|
14776
15546
|
};
|
|
14777
15547
|
}
|
|
14778
15548
|
const meta = metaOf(result);
|
|
14779
|
-
const videoUrl =
|
|
15549
|
+
const videoUrl = z29.string().safeParse(meta.videoUrl);
|
|
14780
15550
|
if (videoUrl.success && videoUrl.data) {
|
|
14781
15551
|
const res = await ctx.fetch(videoUrl.data);
|
|
14782
15552
|
if (!res.ok) {
|
|
@@ -14799,7 +15569,7 @@ async function mapResult(ctx, req, result) {
|
|
|
14799
15569
|
});
|
|
14800
15570
|
}
|
|
14801
15571
|
function usage2(ctx, req, meta) {
|
|
14802
|
-
const costTicks =
|
|
15572
|
+
const costTicks = z29.number().safeParse(meta.costInUsdTicks);
|
|
14803
15573
|
const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
|
|
14804
15574
|
const event = {
|
|
14805
15575
|
model: ctx.model.id,
|
|
@@ -14847,7 +15617,8 @@ var DEFAULT_ADAPTERS = {
|
|
|
14847
15617
|
replicate: replicateAdapter,
|
|
14848
15618
|
prodia: prodiaAdapter,
|
|
14849
15619
|
higgsfield: higgsfieldAdapter,
|
|
14850
|
-
"xai-video": xaiVideoAdapter
|
|
15620
|
+
"xai-video": xaiVideoAdapter,
|
|
15621
|
+
luma: lumaAdapter
|
|
14851
15622
|
};
|
|
14852
15623
|
|
|
14853
15624
|
// src/catalog/data-only.ts
|
|
@@ -14963,6 +15734,10 @@ function dataOnlyCapable(row2) {
|
|
|
14963
15734
|
reason: "higgsfield providerModelId must be a platform path, not a URL"
|
|
14964
15735
|
};
|
|
14965
15736
|
}
|
|
15737
|
+
case "luma": {
|
|
15738
|
+
const reason = lumaRowRefusal(row2);
|
|
15739
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
15740
|
+
}
|
|
14966
15741
|
default: {
|
|
14967
15742
|
return assertNever(row2.adapter);
|
|
14968
15743
|
}
|
|
@@ -14982,22 +15757,22 @@ var liveState = store[KEY] ??= {
|
|
|
14982
15757
|
var liveCatalog = liveState.catalog;
|
|
14983
15758
|
|
|
14984
15759
|
// src/catalog/load.ts
|
|
14985
|
-
import { z as
|
|
15760
|
+
import { z as z30 } from "zod";
|
|
14986
15761
|
function rowCount() {
|
|
14987
15762
|
return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
|
|
14988
15763
|
}
|
|
14989
15764
|
function authHeaders(auth) {
|
|
14990
15765
|
return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
|
|
14991
15766
|
}
|
|
14992
|
-
var EnvelopeSchema =
|
|
14993
|
-
rows:
|
|
14994
|
-
revision:
|
|
15767
|
+
var EnvelopeSchema = z30.object({
|
|
15768
|
+
rows: z30.array(JsonValueSchema),
|
|
15769
|
+
revision: z30.string().optional()
|
|
14995
15770
|
});
|
|
14996
15771
|
function dropReason(path, message) {
|
|
14997
15772
|
return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
|
|
14998
15773
|
}
|
|
14999
15774
|
function rowId(raw) {
|
|
15000
|
-
const parsed =
|
|
15775
|
+
const parsed = z30.object({ id: z30.string().min(1) }).loose().safeParse(raw);
|
|
15001
15776
|
if (!parsed.success) return "?";
|
|
15002
15777
|
return parsed.data.id;
|
|
15003
15778
|
}
|
|
@@ -15641,8 +16416,10 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
15641
16416
|
warnings
|
|
15642
16417
|
);
|
|
15643
16418
|
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
16419
|
+
fillReplicateKlingResolution(model, merged);
|
|
15644
16420
|
const resolution = resolveVideoResolution(merged.resolution, model, onUnsupported, warnings);
|
|
15645
16421
|
if (resolution !== void 0) merged.resolution = resolution;
|
|
16422
|
+
if (isReplicateKling(model)) delete merged.mode;
|
|
15646
16423
|
const duration = resolveDuration(
|
|
15647
16424
|
merged.durationSeconds,
|
|
15648
16425
|
c.durations,
|
|
@@ -16044,7 +16821,8 @@ var ADAPTER_KEYS = {
|
|
|
16044
16821
|
replicate: ["replicate"],
|
|
16045
16822
|
prodia: ["prodia"],
|
|
16046
16823
|
higgsfield: ["higgsfield"],
|
|
16047
|
-
"xai-video": ["xai"]
|
|
16824
|
+
"xai-video": ["xai"],
|
|
16825
|
+
luma: ["luma"]
|
|
16048
16826
|
};
|
|
16049
16827
|
function hasAll(keys, names) {
|
|
16050
16828
|
if (!keys) return false;
|
|
@@ -16102,6 +16880,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
16102
16880
|
set("prodia", pick2("PRODIA_API_KEY", "PRODIA_TOKEN"));
|
|
16103
16881
|
set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
|
|
16104
16882
|
set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
|
|
16883
|
+
set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
|
|
16105
16884
|
set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
16106
16885
|
const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
|
|
16107
16886
|
const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
|
|
@@ -16124,7 +16903,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
16124
16903
|
|
|
16125
16904
|
// src/text.ts
|
|
16126
16905
|
import "ai";
|
|
16127
|
-
import { z as
|
|
16906
|
+
import { z as z31 } from "zod";
|
|
16128
16907
|
function mergeTextProviderOptions(catalog, caller) {
|
|
16129
16908
|
const merged = {};
|
|
16130
16909
|
const catalogOptions = catalog.providerOptions ?? {};
|
|
@@ -16163,8 +16942,8 @@ function passthroughTextModel(model) {
|
|
|
16163
16942
|
pricingKind: "token"
|
|
16164
16943
|
};
|
|
16165
16944
|
}
|
|
16166
|
-
var perplexityCostSchema =
|
|
16167
|
-
perplexity:
|
|
16945
|
+
var perplexityCostSchema = z31.object({
|
|
16946
|
+
perplexity: z31.object({ cost: z31.object({ totalCost: z31.number().finite().nonnegative() }) })
|
|
16168
16947
|
});
|
|
16169
16948
|
function reportedCostUsd(metadata) {
|
|
16170
16949
|
const parsed = perplexityCostSchema.safeParse(metadata);
|
|
@@ -16244,7 +17023,7 @@ import {
|
|
|
16244
17023
|
streamObject as aiStreamObject2,
|
|
16245
17024
|
streamText as aiStreamText2
|
|
16246
17025
|
} from "ai";
|
|
16247
|
-
import { z as
|
|
17026
|
+
import { z as z32 } from "zod";
|
|
16248
17027
|
|
|
16249
17028
|
// src/generated-image.ts
|
|
16250
17029
|
function toGeneratedImage(image) {
|
|
@@ -16593,10 +17372,10 @@ function textAbortOptions(sdk, context) {
|
|
|
16593
17372
|
if (abortSignal) return { abortSignal };
|
|
16594
17373
|
return {};
|
|
16595
17374
|
}
|
|
16596
|
-
var catalogId =
|
|
16597
|
-
var exactSize =
|
|
16598
|
-
var sdkRatio =
|
|
16599
|
-
var sizeTier =
|
|
17375
|
+
var catalogId = z32.string();
|
|
17376
|
+
var exactSize = z32.templateLiteral([z32.number(), "x", z32.number()]);
|
|
17377
|
+
var sdkRatio = z32.templateLiteral([z32.number(), ":", z32.number()]);
|
|
17378
|
+
var sizeTier = z32.enum(["512", "1K", "2K", "4K"]);
|
|
16600
17379
|
function isCatalogId(model) {
|
|
16601
17380
|
return catalogId.safeParse(model).success;
|
|
16602
17381
|
}
|
|
@@ -17340,6 +18119,7 @@ export {
|
|
|
17340
18119
|
languageModel,
|
|
17341
18120
|
liveCatalog,
|
|
17342
18121
|
liveState,
|
|
18122
|
+
lumaAdapter,
|
|
17343
18123
|
mergeTextProviderOptions,
|
|
17344
18124
|
missingTierKeys,
|
|
17345
18125
|
model3dCall,
|