@shop-os/modelkit 0.1.7 → 0.1.9

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.
@@ -0,0 +1,2216 @@
1
+ // src/errors.ts
2
+ var ModelKitError = class extends Error {
3
+ code;
4
+ provider;
5
+ model;
6
+ status;
7
+ body;
8
+ retryable;
9
+ constructor(init) {
10
+ super(init.message, { cause: init.cause });
11
+ this.name = "ModelKitError";
12
+ this.code = init.code;
13
+ this.provider = init.provider;
14
+ this.model = init.model;
15
+ this.status = init.status;
16
+ this.body = init.body;
17
+ this.retryable = init.retryable ?? defaultRetryable(init.code);
18
+ }
19
+ };
20
+ function defaultRetryable(code) {
21
+ return code === "timeout" || code === "network" || code === "rate_limited";
22
+ }
23
+ function isModelKitError(err) {
24
+ return err instanceof ModelKitError;
25
+ }
26
+
27
+ // src/catalog/registry.ts
28
+ var Catalog = class _Catalog {
29
+ byId = /* @__PURE__ */ new Map();
30
+ byAlias = /* @__PURE__ */ new Map();
31
+ constructor(models) {
32
+ for (const model of models) this.add(model);
33
+ }
34
+ add(model) {
35
+ if (this.byId.has(model.id)) {
36
+ throw new Error(`Duplicate model id "${model.id}"`);
37
+ }
38
+ if (this.byAlias.has(model.id)) {
39
+ throw new Error(
40
+ `Model id "${model.id}" collides with an alias of "${this.byAlias.get(model.id)}"`
41
+ );
42
+ }
43
+ for (const alias of model.aliases) {
44
+ if (alias === model.id) {
45
+ throw new Error(`Alias "${alias}" collides with its own model id "${model.id}"`);
46
+ }
47
+ const existing = this.byAlias.get(alias);
48
+ if (existing !== void 0) {
49
+ throw new Error(`Duplicate alias "${alias}" (already maps to "${existing}")`);
50
+ }
51
+ }
52
+ this.byId.set(model.id, model);
53
+ this.byAlias.set(model.id, model.id);
54
+ for (const alias of model.aliases) this.byAlias.set(alias, model.id);
55
+ }
56
+ /** Resolves a canonical id or any historical alias. */
57
+ resolveId(idOrAlias) {
58
+ return this.byAlias.get(idOrAlias);
59
+ }
60
+ get(idOrAlias) {
61
+ const id = this.resolveId(idOrAlias);
62
+ return id ? this.byId.get(id) : void 0;
63
+ }
64
+ require(idOrAlias) {
65
+ const model = this.get(idOrAlias);
66
+ if (!model) {
67
+ throw new ModelKitError({
68
+ code: "unknown_model",
69
+ message: `Unknown model "${idOrAlias}"`,
70
+ model: idOrAlias
71
+ });
72
+ }
73
+ if (model.lifecycle === "retired") {
74
+ const hint = model.replacedBy ? ` Use "${model.replacedBy}".` : "";
75
+ throw new ModelKitError({
76
+ code: "unknown_model",
77
+ message: `Model "${model.id}" is retired.${hint}`,
78
+ model: model.id
79
+ });
80
+ }
81
+ return model;
82
+ }
83
+ list(filter = {}) {
84
+ const lifecycles = filter.lifecycle ?? ["active"];
85
+ return [...this.byId.values()].filter(
86
+ (m) => (filter.type ? m.type === filter.type : true) && lifecycles.includes(m.lifecycle)
87
+ );
88
+ }
89
+ /** Merge rows by id. Used for catalogOverride. */
90
+ withOverrides(rows) {
91
+ return new _Catalog([
92
+ ...[...this.byId.values()].filter((m) => !rows.some((r) => r.id === m.id)),
93
+ ...rows
94
+ ]);
95
+ }
96
+ };
97
+
98
+ // src/catalog/image.ts
99
+ var IMAGE_USAGE = { unit: "images", modality: "IMAGE" };
100
+ var IMAGE_GENERATE_EDIT = { imageGenerate: true, imageEdit: true };
101
+ var GEMINI_RATIOS = [
102
+ "1:1",
103
+ "2:3",
104
+ "3:2",
105
+ "16:9",
106
+ "9:16",
107
+ "4:3",
108
+ "3:4",
109
+ "21:9",
110
+ "4:5",
111
+ "5:4",
112
+ "adaptive"
113
+ ];
114
+ function geminiImage(id, label, aliases, sizes, display, exposure) {
115
+ const model = {
116
+ id,
117
+ aliases,
118
+ label,
119
+ type: "image",
120
+ adapter: "google-image",
121
+ providerModelId: id,
122
+ lifecycle: "active",
123
+ exposure,
124
+ constraints: {
125
+ aspectRatios: [...GEMINI_RATIOS],
126
+ sizes,
127
+ supports: ["safetySettings", "temperature"]
128
+ },
129
+ defaults: { size: "1K", aspectRatio: "1:1" },
130
+ usage: { ...IMAGE_USAGE, slug: "gemini" },
131
+ pricingKind: "image_size",
132
+ display,
133
+ capabilities: { ...IMAGE_GENERATE_EDIT }
134
+ };
135
+ return model;
136
+ }
137
+ var IMAGE_MODELS = [
138
+ geminiImage(
139
+ "gemini-3-pro-image-preview",
140
+ "Nano Banana Pro",
141
+ ["nb-pro"],
142
+ ["1K", "2K", "4K"],
143
+ {
144
+ provider: "google",
145
+ description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
146
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
147
+ },
148
+ "catalog"
149
+ ),
150
+ geminiImage(
151
+ "gemini-3.1-flash-image-preview",
152
+ "Nano Banana 2",
153
+ ["nb-2"],
154
+ // Flash 3.1 is the only Gemini image model with the 512 tier.
155
+ ["512", "1K", "2K", "4K"],
156
+ {
157
+ provider: "google",
158
+ description: "Generate high-quality images at speed. Perfect for brainstorming, moodboards, concept testing, creative exploration, and large batch workflows.",
159
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
160
+ },
161
+ "catalog"
162
+ ),
163
+ geminiImage(
164
+ "gemini-3.1-flash-lite-image",
165
+ "Nano Banana Lite",
166
+ ["nb-lite"],
167
+ ["1K"],
168
+ {
169
+ provider: "google",
170
+ description: "The fastest and most affordable image model. Ideal for rapid drafts, bulk exploration, and iterative concept testing at 1K resolution.",
171
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
172
+ },
173
+ "catalog"
174
+ ),
175
+ // trigger-workflows validates 1K only; pricing seeds 2K/4K rows so allow all three.
176
+ geminiImage(
177
+ "gemini-2.5-flash-image",
178
+ "Gemini 2.5 Flash Image",
179
+ [],
180
+ ["1K", "2K", "4K"],
181
+ {
182
+ provider: "google",
183
+ description: "Nano Banana (legacy Gemini 2.5 Flash Image) native image generation and editing model for high-volume, low-latency creative workflows."
184
+ },
185
+ "internal"
186
+ ),
187
+ {
188
+ // Cowork "auto" lets OpenAI pick the size; the canonical equivalent is adaptive.
189
+ id: "gpt-image-2",
190
+ aliases: [],
191
+ label: "GPT-image-2",
192
+ type: "image",
193
+ adapter: "openai-image",
194
+ providerModelId: "gpt-image-2",
195
+ lifecycle: "active",
196
+ exposure: "catalog",
197
+ constraints: {
198
+ exactSizes: {
199
+ "1:1": "1024x1024",
200
+ "3:2": "1536x1024",
201
+ "2:3": "1024x1536",
202
+ "16:9": "2048x1152",
203
+ "9:16": "1152x2048",
204
+ "4:5": "1024x1280",
205
+ "5:4": "1280x1024"
206
+ },
207
+ aspectRatios: ["1:1", "3:2", "2:3", "16:9", "9:16", "4:5", "5:4", "adaptive"],
208
+ sizes: ["1K", "2K", "4K"],
209
+ qualityOptions: ["auto", "low", "medium", "high"],
210
+ references: { images: 16 },
211
+ supports: ["quality", "count"]
212
+ },
213
+ defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
214
+ usage: { ...IMAGE_USAGE, slug: "gpt" },
215
+ pricingKind: "image_size",
216
+ display: {
217
+ provider: "openai",
218
+ description: "The most capable model for image editing and complex creative instructions. Excels at text rendering, visual consistency, design generation, and iterative refinement.",
219
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/1204b494-8962-4f7f-af5e-699a8bdc98e3_compressed.png"
220
+ },
221
+ capabilities: { ...IMAGE_GENERATE_EDIT }
222
+ },
223
+ {
224
+ // Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
225
+ id: "gpt-image-2.5-sunburst",
226
+ aliases: [],
227
+ label: "GPT Image 2.5 Sunburst",
228
+ type: "image",
229
+ adapter: "openai-image",
230
+ providerModelId: "gpt-image-2.5-sunburst",
231
+ lifecycle: "active",
232
+ exposure: "internal",
233
+ constraints: {
234
+ exactSizes: {
235
+ "1:1": "1024x1024",
236
+ "3:2": "1536x1024",
237
+ "2:3": "1024x1536",
238
+ "16:9": "2048x1152",
239
+ "9:16": "1152x2048",
240
+ "4:5": "1024x1280",
241
+ "5:4": "1280x1024"
242
+ },
243
+ aspectRatios: ["1:1", "3:2", "2:3", "16:9", "9:16", "4:5", "5:4", "adaptive"],
244
+ sizes: ["1K", "2K", "4K"],
245
+ qualityOptions: ["auto", "low", "medium", "high"],
246
+ references: { images: 16 },
247
+ supports: ["quality", "count"]
248
+ },
249
+ defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
250
+ usage: { ...IMAGE_USAGE },
251
+ pricingKind: "image_size",
252
+ display: {
253
+ provider: "openai",
254
+ 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."
255
+ },
256
+ capabilities: { ...IMAGE_GENERATE_EDIT }
257
+ },
258
+ {
259
+ // Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
260
+ id: "gpt-image-2.5-flare",
261
+ aliases: [],
262
+ label: "GPT Image 2.5 Flare",
263
+ type: "image",
264
+ adapter: "openai-image",
265
+ providerModelId: "gpt-image-2.5-flare",
266
+ lifecycle: "active",
267
+ exposure: "internal",
268
+ constraints: {
269
+ exactSizes: {
270
+ "1:1": "1024x1024",
271
+ "3:2": "1536x1024",
272
+ "2:3": "1024x1536",
273
+ "16:9": "2048x1152",
274
+ "9:16": "1152x2048",
275
+ "4:5": "1024x1280",
276
+ "5:4": "1280x1024"
277
+ },
278
+ aspectRatios: ["1:1", "3:2", "2:3", "16:9", "9:16", "4:5", "5:4", "adaptive"],
279
+ sizes: ["1K", "2K", "4K"],
280
+ qualityOptions: ["auto", "low", "medium", "high"],
281
+ references: { images: 16 },
282
+ supports: ["quality", "count"]
283
+ },
284
+ defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
285
+ usage: { ...IMAGE_USAGE },
286
+ pricingKind: "image_size",
287
+ display: {
288
+ provider: "openai",
289
+ 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."
290
+ },
291
+ capabilities: { ...IMAGE_GENERATE_EDIT }
292
+ },
293
+ {
294
+ // Cowork allows 7 ratios; trigger-workflows allows 9 (adds 3:2, 9:21, drops 4:5/5:4).
295
+ id: "muse-image-1.0",
296
+ aliases: ["meta-muse"],
297
+ label: "Meta Muse",
298
+ type: "image",
299
+ adapter: "fal",
300
+ providerModelId: "muse-image-1.0",
301
+ lifecycle: "active",
302
+ exposure: "catalog",
303
+ constraints: {
304
+ aspectRatios: [
305
+ "21:9",
306
+ "16:9",
307
+ "4:3",
308
+ "3:2",
309
+ "1:1",
310
+ "2:3",
311
+ "3:4",
312
+ "9:16",
313
+ "4:5",
314
+ "5:4",
315
+ "9:21",
316
+ "adaptive"
317
+ ],
318
+ sizes: ["1K"],
319
+ references: { images: 10 },
320
+ supports: ["count", "outputFormat"]
321
+ },
322
+ defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png", count: 1 },
323
+ usage: { ...IMAGE_USAGE, slug: "muse" },
324
+ pricingKind: "image_size",
325
+ display: {
326
+ provider: "meta",
327
+ 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.",
328
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/characters/1787909065794-k9a7zz.png"
329
+ },
330
+ capabilities: { ...IMAGE_GENERATE_EDIT }
331
+ },
332
+ {
333
+ id: "seedream-5-0-pro",
334
+ aliases: ["seedream-4-5"],
335
+ label: "Seedream 5 Pro",
336
+ type: "image",
337
+ adapter: "ark",
338
+ providerModelId: "dola-seedream-5-0-pro-260628",
339
+ lifecycle: "active",
340
+ exposure: "catalog",
341
+ constraints: {
342
+ aspectRatios: ["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3", "21:9", "4:5", "5:4"],
343
+ sizes: ["1K", "2K"],
344
+ references: { images: 10 },
345
+ // Ark's Images API has no output-format, quality or count field; only
346
+ // the seed is forwarded, so anything else must warn, not vanish.
347
+ supports: ["seed"]
348
+ },
349
+ defaults: { size: "1K", aspectRatio: "1:1" },
350
+ usage: { ...IMAGE_USAGE },
351
+ pricingKind: "image_size",
352
+ display: {
353
+ provider: "bytedance",
354
+ 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."
355
+ },
356
+ capabilities: { ...IMAGE_GENERATE_EDIT }
357
+ },
358
+ {
359
+ id: "seedream-4.5",
360
+ aliases: [],
361
+ label: "Seedream 4.5",
362
+ type: "image",
363
+ adapter: "ark",
364
+ providerModelId: "seedream-4-5-251128",
365
+ lifecycle: "active",
366
+ exposure: "internal",
367
+ constraints: {
368
+ // 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
369
+ // omits the ratio instead. Advertise only sizes the adapter can send.
370
+ aspectRatios: [
371
+ "1:1",
372
+ "2:3",
373
+ "3:2",
374
+ "4:3",
375
+ "3:4",
376
+ "4:5",
377
+ "5:4",
378
+ "9:16",
379
+ "16:9",
380
+ "21:9",
381
+ "9:21"
382
+ ],
383
+ sizes: ["1K", "2K", "4K"],
384
+ references: { images: 10 },
385
+ supports: ["seed"]
386
+ },
387
+ defaults: { size: "1K", aspectRatio: "1:1" },
388
+ usage: { ...IMAGE_USAGE },
389
+ pricingKind: "image_size",
390
+ display: {
391
+ provider: "bytedance",
392
+ 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."
393
+ },
394
+ capabilities: { ...IMAGE_GENERATE_EDIT }
395
+ },
396
+ {
397
+ id: "flux-2-pro",
398
+ aliases: [],
399
+ label: "Flux 2 Pro",
400
+ type: "image",
401
+ adapter: "prodia",
402
+ providerModelId: "flux-2-pro",
403
+ lifecycle: "active",
404
+ exposure: "catalog",
405
+ constraints: {
406
+ aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
407
+ sizes: ["1K"],
408
+ // flux-2-pro's job type always returns image/png; only the seed is forwarded.
409
+ supports: ["seed"]
410
+ },
411
+ defaults: { size: "1K", aspectRatio: "1:1" },
412
+ usage: { ...IMAGE_USAGE },
413
+ pricingKind: "image_size",
414
+ display: {
415
+ provider: "black-forest-labs",
416
+ 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."
417
+ },
418
+ capabilities: { ...IMAGE_GENERATE_EDIT }
419
+ },
420
+ {
421
+ // Prodia's gemini-3-pro jobs take aspect_ratio + resolution (1K/2K/4K), not
422
+ // width/height; 97:30 is outside its aspect_ratio enum.
423
+ // https://docs.prodia.com/models/gemini-3/
424
+ id: "prodia-nano-banana-pro",
425
+ aliases: [],
426
+ label: "Nano Banana Pro via Prodia",
427
+ type: "image",
428
+ adapter: "prodia",
429
+ providerModelId: "inference.gemini-3-pro.img2img.v1",
430
+ lifecycle: "active",
431
+ exposure: "internal",
432
+ constraints: {
433
+ aspectRatios: ["1:1", "2:3", "3:2", "4:3", "3:4", "4:5", "5:4", "9:16", "16:9", "21:9"],
434
+ sizes: ["1K", "2K", "4K"],
435
+ requires: ["references"],
436
+ supports: ["seed"]
437
+ },
438
+ defaults: { size: "1K", aspectRatio: "1:1" },
439
+ usage: { ...IMAGE_USAGE },
440
+ pricingKind: "image_size",
441
+ display: {
442
+ provider: "google",
443
+ 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."
444
+ },
445
+ capabilities: { ...IMAGE_GENERATE_EDIT }
446
+ },
447
+ {
448
+ // Nano Banana (img2img.v2) is flat-rate with aspect_ratio only; 3:2, 4:5,
449
+ // 5:4 and 97:30 are not in its enum. https://docs.prodia.com/models/nano-banana/
450
+ id: "prodia-nano-banana",
451
+ aliases: [],
452
+ label: "Nano Banana via Prodia",
453
+ type: "image",
454
+ adapter: "prodia",
455
+ providerModelId: "inference.nano-banana.img2img.v2",
456
+ lifecycle: "active",
457
+ exposure: "internal",
458
+ constraints: {
459
+ aspectRatios: ["1:1", "2:3", "3:4", "4:3", "9:16", "16:9", "21:9"],
460
+ sizes: ["1K"],
461
+ requires: ["references"],
462
+ supports: ["seed"]
463
+ },
464
+ defaults: { size: "1K", aspectRatio: "1:1" },
465
+ usage: { ...IMAGE_USAGE },
466
+ pricingKind: "image_size",
467
+ display: {
468
+ provider: "google",
469
+ 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."
470
+ },
471
+ capabilities: { ...IMAGE_GENERATE_EDIT }
472
+ },
473
+ {
474
+ // WAN 2.7 takes `images` (up to 9) and a `size` enum whose exact values
475
+ // cover 1:1/16:9/9:16/4:3/3:4 only; other ratios have no spelling.
476
+ // https://replicate.com/wan-video/wan-2.7-image-pro (input schema)
477
+ id: "wan-2.7-image-pro",
478
+ aliases: [],
479
+ label: "WAN 2.7 Image Pro",
480
+ type: "image",
481
+ adapter: "replicate",
482
+ providerModelId: "wan-video/wan-2.7-image-pro",
483
+ lifecycle: "active",
484
+ exposure: "internal",
485
+ constraints: {
486
+ aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4"],
487
+ sizes: ["1K", "2K", "4K"],
488
+ references: { images: 9 },
489
+ supports: []
490
+ },
491
+ defaults: { size: "1K", aspectRatio: "1:1" },
492
+ usage: { unit: "compute_seconds", modality: "IMAGE" },
493
+ pricingKind: "image_size",
494
+ display: {
495
+ provider: "alibaba",
496
+ 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)."
497
+ },
498
+ capabilities: { ...IMAGE_GENERATE_EDIT }
499
+ },
500
+ {
501
+ // Qwen Image 2 Pro has aspect_ratio but no size input; resolution follows
502
+ // the reference image (match_input_image) or the provider default.
503
+ // https://replicate.com/qwen/qwen-image-2-pro (input schema)
504
+ id: "qwen-image-2-pro",
505
+ aliases: [],
506
+ label: "Qwen Image 2 Pro",
507
+ type: "image",
508
+ adapter: "replicate",
509
+ providerModelId: "qwen/qwen-image-2-pro",
510
+ lifecycle: "active",
511
+ exposure: "internal",
512
+ constraints: {
513
+ aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"],
514
+ sizes: [],
515
+ references: { images: 1 },
516
+ requires: ["references"],
517
+ supports: []
518
+ },
519
+ defaults: { aspectRatio: "1:1" },
520
+ usage: { unit: "compute_seconds", modality: "IMAGE" },
521
+ pricingKind: "image_size",
522
+ display: {
523
+ provider: "alibaba",
524
+ 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."
525
+ },
526
+ capabilities: { ...IMAGE_GENERATE_EDIT }
527
+ },
528
+ {
529
+ // Qwen Image Edit Plus takes aspect_ratio (or match_input_image) and
530
+ // output_format, but no size; no default ratio so edits keep following
531
+ // the input image. https://replicate.com/qwen-edit-apps/qwen-image-edit-plus-lora-skin
532
+ id: "qwen-image-edit-plus-lora-skin",
533
+ aliases: [],
534
+ label: "Qwen Image Edit Plus",
535
+ type: "image",
536
+ adapter: "replicate",
537
+ providerModelId: "qwen-edit-apps/qwen-image-edit-plus-lora-skin",
538
+ lifecycle: "active",
539
+ exposure: "internal",
540
+ constraints: {
541
+ aspectRatios: ["1:1", "16:9", "9:16", "4:3", "3:4"],
542
+ sizes: [],
543
+ references: { images: 1 },
544
+ requires: ["references"],
545
+ supports: ["outputFormat"]
546
+ },
547
+ defaults: { outputFormat: "png" },
548
+ usage: { unit: "compute_seconds", modality: "IMAGE" },
549
+ pricingKind: "image_size",
550
+ display: {
551
+ provider: "alibaba",
552
+ 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."
553
+ },
554
+ capabilities: { ...IMAGE_GENERATE_EDIT }
555
+ }
556
+ ];
557
+
558
+ // src/catalog/other.ts
559
+ var OTHER_MODELS = [
560
+ {
561
+ id: "lyria-3-clip-preview",
562
+ aliases: [],
563
+ label: "Lyria 3 Clip",
564
+ type: "audio",
565
+ adapter: "google-genai",
566
+ providerModelId: "lyria-3-clip-preview",
567
+ lifecycle: "active",
568
+ exposure: "catalog",
569
+ constraints: {
570
+ durations: [30],
571
+ references: { images: 10 },
572
+ supports: []
573
+ },
574
+ defaults: {},
575
+ usage: { unit: "images", modality: "AUDIO" },
576
+ pricingKind: "flat",
577
+ display: {
578
+ provider: "google",
579
+ 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."
580
+ },
581
+ capabilities: {}
582
+ },
583
+ {
584
+ id: "lyria-3-pro-preview",
585
+ aliases: [],
586
+ label: "Lyria 3 Pro",
587
+ type: "audio",
588
+ adapter: "google-genai",
589
+ providerModelId: "lyria-3-pro-preview",
590
+ lifecycle: "active",
591
+ exposure: "catalog",
592
+ constraints: {
593
+ references: { images: 10 },
594
+ supports: []
595
+ },
596
+ defaults: {},
597
+ usage: { unit: "images", modality: "AUDIO" },
598
+ pricingKind: "flat",
599
+ display: {
600
+ provider: "google",
601
+ 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."
602
+ },
603
+ capabilities: {}
604
+ },
605
+ {
606
+ id: "google/lyria-2",
607
+ aliases: [],
608
+ label: "Lyria 2 via Replicate",
609
+ type: "audio",
610
+ adapter: "replicate",
611
+ providerModelId: "google/lyria-2",
612
+ lifecycle: "active",
613
+ exposure: "internal",
614
+ constraints: {
615
+ durations: [30],
616
+ supports: ["seed", "negativePrompt"]
617
+ },
618
+ defaults: {},
619
+ usage: { unit: "compute_seconds", modality: "AUDIO" },
620
+ pricingKind: "flat",
621
+ display: {
622
+ provider: "google",
623
+ description: "Lyria 2 music generation on Replicate; produces 30 seconds of 48 kHz stereo audio from a text prompt."
624
+ },
625
+ capabilities: {}
626
+ },
627
+ {
628
+ id: "mmaudio",
629
+ aliases: ["zsxkib/mmaudio", "video-to-audio"],
630
+ label: "MMAudio video-to-audio",
631
+ type: "audio",
632
+ adapter: "replicate",
633
+ providerModelId: "zsxkib/mmaudio:62871fb59889b2d7c13777f08deb3b36bdff88f7e1d53a50ad7694548a41b484",
634
+ lifecycle: "active",
635
+ exposure: "catalog",
636
+ constraints: {
637
+ durations: { min: 1, max: 30 },
638
+ requires: ["sourceVideo"],
639
+ supports: ["seed", "negativePrompt"]
640
+ },
641
+ defaults: { durationSeconds: 8 },
642
+ usage: { unit: "compute_seconds", modality: "AUDIO" },
643
+ pricingKind: "flat",
644
+ display: {
645
+ provider: "mmaudio",
646
+ description: "MMAudio V2 video-to-audio model on Replicate; takes a source video and prompt and synthesizes synchronized environmental, action, and speech-like audio."
647
+ },
648
+ capabilities: {}
649
+ },
650
+ {
651
+ id: "elevenlabs-music",
652
+ aliases: ["elevenlabs/music"],
653
+ label: "ElevenLabs Music via Replicate",
654
+ type: "audio",
655
+ adapter: "replicate",
656
+ providerModelId: "elevenlabs/music",
657
+ lifecycle: "active",
658
+ exposure: "internal",
659
+ constraints: {
660
+ durations: { min: 5, max: 300 },
661
+ supports: ["instrumental"]
662
+ },
663
+ defaults: { durationSeconds: 15, instrumental: true },
664
+ // Replicate's run() does not report predict_time; billed by generated length.
665
+ usage: { unit: "seconds", modality: "AUDIO" },
666
+ pricingKind: "flat",
667
+ display: {
668
+ provider: "elevenlabs",
669
+ 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."
670
+ },
671
+ capabilities: {}
672
+ },
673
+ {
674
+ id: "topaz",
675
+ aliases: ["replicate-upscaler", "upscale", "topazlabs/image-upscale"],
676
+ label: "Topaz Upscale",
677
+ type: "upscale",
678
+ adapter: "replicate",
679
+ providerModelId: "topazlabs/image-upscale",
680
+ lifecycle: "active",
681
+ exposure: "catalog",
682
+ constraints: {
683
+ references: { images: 1 },
684
+ requires: ["references"],
685
+ supports: ["scaleFactor", "outputFormat", "upscale"]
686
+ },
687
+ defaults: { scaleFactor: 2, outputFormat: "png" },
688
+ usage: { unit: "compute_seconds", modality: "IMAGE" },
689
+ pricingKind: "flat",
690
+ display: {
691
+ provider: "topaz",
692
+ 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."
693
+ },
694
+ capabilities: { imageEdit: true }
695
+ },
696
+ {
697
+ id: "bg-remove",
698
+ aliases: [],
699
+ label: "Background Remover",
700
+ type: "bg-remove",
701
+ adapter: "prodia",
702
+ providerModelId: "inference.remove-background.v1",
703
+ lifecycle: "active",
704
+ exposure: "catalog",
705
+ constraints: {
706
+ references: { images: 1 },
707
+ requires: ["references"],
708
+ supports: []
709
+ },
710
+ defaults: {},
711
+ usage: { unit: "images", modality: "IMAGE" },
712
+ pricingKind: "flat",
713
+ display: {
714
+ provider: "prodia",
715
+ description: "Prodia background removal; takes one input image and returns a PNG cut-out of the subject plus an optional black-and-white mask."
716
+ },
717
+ capabilities: { imageEdit: true }
718
+ }
719
+ ];
720
+
721
+ // src/catalog/text.ts
722
+ var TEXT_USAGE = { unit: "tokens", modality: "TEXT" };
723
+ function text(id, label, providerModelId, extra) {
724
+ return {
725
+ id,
726
+ aliases: [],
727
+ label,
728
+ type: "text",
729
+ adapter: "ai-sdk-text",
730
+ providerModelId,
731
+ lifecycle: "active",
732
+ exposure: "internal",
733
+ constraints: { supports: [] },
734
+ defaults: {},
735
+ usage: { ...TEXT_USAGE },
736
+ pricingKind: "token",
737
+ ...extra
738
+ };
739
+ }
740
+ var ANTHROPIC_THINKING = {
741
+ anthropic: { thinking: { type: "enabled", budgetTokens: 4e3 }, sendReasoning: true }
742
+ };
743
+ var ANTHROPIC_ADAPTIVE = {
744
+ anthropic: { thinking: { type: "adaptive", display: "summarized" }, sendReasoning: true }
745
+ };
746
+ var OPENAI_REASONING = { openai: { reasoningEffort: "medium", reasoningSummary: "auto" } };
747
+ var DEEPSEEK_THINKING = { deepseek: { thinking: { type: "enabled" } } };
748
+ var TEXT_MODELS = [
749
+ text("gpt-4o", "GPT-4o", "gpt-4o", {
750
+ exposure: "internal",
751
+ display: {
752
+ provider: "openai",
753
+ costTier: 2,
754
+ description: "OpenAI GPT-4o flagship multimodal model; text and image input, 128K-token context."
755
+ },
756
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
757
+ }),
758
+ text("gpt-4o-mini", "GPT-4o mini", "gpt-4o-mini", {
759
+ exposure: "internal",
760
+ display: {
761
+ provider: "openai",
762
+ costTier: 1,
763
+ description: "OpenAI GPT-4o mini fast, low-cost multimodal model; text and image input, 128K-token context."
764
+ },
765
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
766
+ }),
767
+ text("gpt-5.1", "GPT-5.1", "gpt-5.1", {
768
+ exposure: "catalog",
769
+ display: {
770
+ provider: "openai",
771
+ costTier: 3,
772
+ description: "OpenAI GPT-5.1 reasoning model for coding and agentic tasks; text and image input, 400K-token context."
773
+ },
774
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
775
+ }),
776
+ text("gpt-5.2", "GPT-5.2", "gpt-5.2", {
777
+ exposure: "catalog",
778
+ display: {
779
+ provider: "openai",
780
+ costTier: 3,
781
+ description: "OpenAI GPT-5.2 reasoning model for complex professional work; text and image input, 400K-token context."
782
+ },
783
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
784
+ }),
785
+ // 1.05M-token context: https://platform.openai.com/docs/models/gpt-5.4
786
+ text("gpt-5.4", "GPT-5.4", "gpt-5.4", {
787
+ exposure: "internal",
788
+ display: {
789
+ provider: "openai",
790
+ costTier: 3,
791
+ description: "OpenAI GPT-5.4 flagship reasoning model; text and image input, 1.05M-token context."
792
+ },
793
+ capabilities: {
794
+ vision: true,
795
+ tools: true,
796
+ structuredOutput: true,
797
+ contextWindow: 105e4
798
+ }
799
+ }),
800
+ // OpenAI never shipped gpt-5.1-mini or gpt-5.2-mini; callers that still send them get 5.4 mini.
801
+ text("gpt-5.4-mini", "GPT-5.4 mini", "gpt-5.4-mini", {
802
+ exposure: "catalog",
803
+ aliases: ["gpt-5.1-mini", "gpt-5.2-mini"],
804
+ display: {
805
+ provider: "openai",
806
+ costTier: 1,
807
+ description: "OpenAI GPT-5.4 mini efficient reasoning model for high-volume workloads; text and image input, 400K-token context."
808
+ },
809
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
810
+ }),
811
+ text("gpt-5.5", "GPT-5.5", "gpt-5.5", {
812
+ exposure: "catalog",
813
+ display: {
814
+ provider: "openai",
815
+ costTier: 3,
816
+ description: "OpenAI GPT-5.5 flagship reasoning model for the most complex professional and coding work; text and image input, 1.05M-token context."
817
+ },
818
+ capabilities: {
819
+ vision: true,
820
+ tools: true,
821
+ structuredOutput: true,
822
+ contextWindow: 105e4
823
+ }
824
+ }),
825
+ text("gpt-5.6-luna", "GPT-5.6 Luna", "gpt-5.6-luna", {
826
+ providerOptions: OPENAI_REASONING,
827
+ exposure: "catalog",
828
+ display: {
829
+ provider: "openai",
830
+ costTier: 1,
831
+ description: "OpenAI GPT-5.6 Luna cost-optimized tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
832
+ },
833
+ capabilities: {
834
+ reasoning: true,
835
+ vision: true,
836
+ tools: true,
837
+ structuredOutput: true,
838
+ contextWindow: 105e4
839
+ }
840
+ }),
841
+ text("gpt-5.6-terra", "GPT-5.6 Terra", "gpt-5.6-terra", {
842
+ providerOptions: OPENAI_REASONING,
843
+ exposure: "catalog",
844
+ display: {
845
+ provider: "openai",
846
+ costTier: 2,
847
+ description: "OpenAI GPT-5.6 Terra balanced tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
848
+ },
849
+ capabilities: {
850
+ reasoning: true,
851
+ vision: true,
852
+ tools: true,
853
+ structuredOutput: true,
854
+ contextWindow: 105e4
855
+ }
856
+ }),
857
+ text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol", {
858
+ providerOptions: OPENAI_REASONING,
859
+ exposure: "catalog",
860
+ display: {
861
+ provider: "openai",
862
+ costTier: 3,
863
+ description: "OpenAI GPT-5.6 Sol flagship tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
864
+ },
865
+ capabilities: {
866
+ reasoning: true,
867
+ vision: true,
868
+ tools: true,
869
+ structuredOutput: true,
870
+ contextWindow: 105e4
871
+ }
872
+ }),
873
+ // Library key "claude-sonnet-4.5" maps to the SDK id "claude-sonnet-4-5".
874
+ text("claude-sonnet-4-5", "Claude Sonnet 4.5", "claude-sonnet-4-5", {
875
+ exposure: "internal",
876
+ aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"],
877
+ display: {
878
+ provider: "anthropic",
879
+ costTier: 2,
880
+ description: "Anthropic Claude Sonnet 4.5 (legacy) balanced model; text and image input, 200K-token context."
881
+ },
882
+ capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
883
+ }),
884
+ // Anthropic retired the dated 4.0 ids; callers that still send them get 4.6.
885
+ text("claude-sonnet-4-6", "Claude Sonnet 4.6", "claude-sonnet-4-6", {
886
+ providerOptions: ANTHROPIC_THINKING,
887
+ exposure: "catalog",
888
+ aliases: [
889
+ "claude-sonnet-4.6",
890
+ "claude-sonnet-4",
891
+ "claude-sonnet-4.0",
892
+ "claude-sonnet-4-20250514"
893
+ ],
894
+ display: {
895
+ provider: "anthropic",
896
+ costTier: 2,
897
+ description: "Anthropic Claude Sonnet 4.6 (legacy) balanced model; text and image input, 1M-token context."
898
+ },
899
+ capabilities: {
900
+ reasoning: true,
901
+ vision: true,
902
+ tools: true,
903
+ structuredOutput: true,
904
+ contextWindow: 1e6
905
+ }
906
+ }),
907
+ text("claude-sonnet-5", "Claude Sonnet 5", "claude-sonnet-5", {
908
+ providerOptions: ANTHROPIC_ADAPTIVE,
909
+ exposure: "catalog",
910
+ display: {
911
+ provider: "anthropic",
912
+ costTier: 3,
913
+ description: "Anthropic Claude Sonnet 5 current balanced model; text and image input, 1M-token context."
914
+ },
915
+ capabilities: {
916
+ reasoning: true,
917
+ vision: true,
918
+ tools: true,
919
+ structuredOutput: true,
920
+ contextWindow: 1e6
921
+ }
922
+ }),
923
+ text("claude-opus-4-8", "Claude Opus 4.8", "claude-opus-4-8", {
924
+ providerOptions: ANTHROPIC_ADAPTIVE,
925
+ exposure: "catalog",
926
+ aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"],
927
+ display: {
928
+ provider: "anthropic",
929
+ costTier: 3,
930
+ description: "Anthropic Claude Opus 4.8 (legacy) frontier model; text and image input, 1M-token context."
931
+ },
932
+ capabilities: {
933
+ reasoning: true,
934
+ vision: true,
935
+ tools: true,
936
+ structuredOutput: true,
937
+ contextWindow: 1e6
938
+ }
939
+ }),
940
+ text("claude-haiku-4-5", "Claude Haiku 4.5", "claude-haiku-4-5", {
941
+ providerOptions: ANTHROPIC_THINKING,
942
+ exposure: "catalog",
943
+ aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"],
944
+ display: {
945
+ provider: "anthropic",
946
+ costTier: 1,
947
+ description: "Anthropic Claude Haiku 4.5 fast model with near-frontier intelligence; text and image input, 200K-token context."
948
+ },
949
+ capabilities: {
950
+ reasoning: true,
951
+ vision: true,
952
+ tools: true,
953
+ structuredOutput: true,
954
+ contextWindow: 2e5
955
+ }
956
+ }),
957
+ text("claude-opus-5", "Claude Opus 5", "claude-opus-5", {
958
+ exposure: "internal",
959
+ aliases: ["claude-opus-5.0"],
960
+ display: {
961
+ provider: "anthropic",
962
+ costTier: 3,
963
+ description: "Anthropic Claude Opus 5 current frontier model for agentic coding and enterprise work; text and image input, 1M-token context."
964
+ },
965
+ capabilities: {
966
+ vision: true,
967
+ tools: true,
968
+ structuredOutput: true,
969
+ contextWindow: 1e6
970
+ }
971
+ }),
972
+ text("claude-fable-5", "Claude Fable 5", "claude-fable-5", {
973
+ exposure: "internal",
974
+ display: {
975
+ provider: "anthropic",
976
+ costTier: 3,
977
+ description: "Anthropic Claude Fable 5 (legacy) model for demanding reasoning and long-horizon agentic work; text and image input, 1M-token context."
978
+ },
979
+ capabilities: {
980
+ vision: true,
981
+ tools: true,
982
+ structuredOutput: true,
983
+ contextWindow: 1e6
984
+ }
985
+ }),
986
+ text("gemini-2.5-flash", "Gemini 2.5 Flash", "gemini-2.5-flash", {
987
+ exposure: "internal",
988
+ display: {
989
+ provider: "google",
990
+ costTier: 1,
991
+ description: "Google Gemini 2.5 Flash low-latency multimodal model for high-volume reasoning over text, images, video, and audio; 1M-token context."
992
+ },
993
+ capabilities: {
994
+ vision: true,
995
+ tools: true,
996
+ structuredOutput: true,
997
+ contextWindow: 1048576
998
+ }
999
+ }),
1000
+ text("gemini-2.5-pro", "Gemini 2.5 Pro", "gemini-2.5-pro", {
1001
+ exposure: "internal",
1002
+ display: {
1003
+ provider: "google",
1004
+ costTier: 2,
1005
+ 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."
1006
+ },
1007
+ capabilities: {
1008
+ vision: true,
1009
+ tools: true,
1010
+ structuredOutput: true,
1011
+ contextWindow: 1048576
1012
+ }
1013
+ }),
1014
+ text("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)", "gemini-3.1-pro-preview", {
1015
+ exposure: "catalog",
1016
+ display: {
1017
+ provider: "google",
1018
+ costTier: 2,
1019
+ description: "Google Gemini 3.1 Pro preview reasoning model for software engineering, tool use, and reliable agentic workflows; 1M-token context."
1020
+ },
1021
+ capabilities: {
1022
+ vision: true,
1023
+ tools: true,
1024
+ structuredOutput: true,
1025
+ contextWindow: 1048576
1026
+ }
1027
+ }),
1028
+ text("gemini-3.5-flash", "Gemini 3.5 Flash", "gemini-3.5-flash", {
1029
+ exposure: "catalog",
1030
+ display: {
1031
+ provider: "google",
1032
+ costTier: 1,
1033
+ description: "Google Gemini 3.5 Flash high-throughput model for frontier-level agentic tasks; text, image, video, audio, and PDF input, 1M-token context."
1034
+ },
1035
+ capabilities: {
1036
+ vision: true,
1037
+ tools: true,
1038
+ structuredOutput: true,
1039
+ contextWindow: 1048576
1040
+ }
1041
+ }),
1042
+ text("gemini-3.6-flash", "Gemini 3.6 Flash", "gemini-3.6-flash", {
1043
+ exposure: "catalog",
1044
+ display: {
1045
+ provider: "google",
1046
+ costTier: 1,
1047
+ description: "Google Gemini 3.6 Flash general-purpose multimodal agentic model balancing speed and capability; 1M-token context."
1048
+ },
1049
+ capabilities: {
1050
+ vision: true,
1051
+ tools: true,
1052
+ structuredOutput: true,
1053
+ contextWindow: 1048576
1054
+ }
1055
+ }),
1056
+ text("gemini-3.7-flash", "Gemini 3.7 Flash", "gemini-3.7-flash", {
1057
+ exposure: "catalog",
1058
+ display: {
1059
+ provider: "google",
1060
+ costTier: 1,
1061
+ recommended: true,
1062
+ description: "Google Gemini 3.7 Flash natively multimodal reasoning model for coding, agentic workflows, and multi-step execution; 1M-token context."
1063
+ },
1064
+ capabilities: {
1065
+ vision: true,
1066
+ tools: true,
1067
+ structuredOutput: true,
1068
+ contextWindow: 1048576
1069
+ }
1070
+ }),
1071
+ text("gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash", {
1072
+ exposure: "internal",
1073
+ display: {
1074
+ provider: "google",
1075
+ costTier: 1,
1076
+ description: "Google Gemini 3.8 Flash frontier model for long-horizon software engineering, autonomous agents, and enterprise workflows; 1M-token context."
1077
+ },
1078
+ capabilities: {
1079
+ vision: true,
1080
+ tools: true,
1081
+ structuredOutput: true,
1082
+ contextWindow: 1048576
1083
+ }
1084
+ }),
1085
+ // Renamed to gemini-3.6-flash in vibe-shared model-migration.ts.
1086
+ text("gemini-3-flash-preview", "Gemini 3 Flash (preview)", "gemini-3-flash-preview", {
1087
+ exposure: "internal",
1088
+ lifecycle: "deprecated",
1089
+ replacedBy: "gemini-3.6-flash"
1090
+ }),
1091
+ text("gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite", "gemini-3.1-flash-lite", {
1092
+ exposure: "internal",
1093
+ display: {
1094
+ provider: "google",
1095
+ costTier: 1,
1096
+ description: "Google Gemini 3.1 Flash-Lite low-latency multimodal model for high-volume agentic, translation, and data-extraction tasks; 1M-token context."
1097
+ },
1098
+ capabilities: {
1099
+ vision: true,
1100
+ tools: true,
1101
+ structuredOutput: true,
1102
+ contextWindow: 1048576
1103
+ }
1104
+ }),
1105
+ text("sonar", "Sonar", "sonar", {
1106
+ exposure: "internal",
1107
+ display: {
1108
+ provider: "perplexity",
1109
+ costTier: 1,
1110
+ description: "Perplexity Sonar lightweight web-grounded search model returning cited answers; 128K-token context."
1111
+ },
1112
+ capabilities: {
1113
+ vision: true,
1114
+ tools: false,
1115
+ structuredOutput: true,
1116
+ contextWindow: 128e3
1117
+ }
1118
+ }),
1119
+ text("sonar-pro", "Sonar Pro", "sonar-pro", {
1120
+ exposure: "internal",
1121
+ display: {
1122
+ provider: "perplexity",
1123
+ costTier: 2,
1124
+ description: "Perplexity Sonar Pro advanced web-grounded search model for complex multi-step queries; 200K-token context."
1125
+ },
1126
+ capabilities: {
1127
+ vision: true,
1128
+ tools: false,
1129
+ structuredOutput: true,
1130
+ contextWindow: 2e5
1131
+ }
1132
+ }),
1133
+ text("sonar-reasoning-pro", "Sonar Reasoning Pro", "sonar-reasoning-pro", {
1134
+ exposure: "internal",
1135
+ display: {
1136
+ provider: "perplexity",
1137
+ costTier: 2,
1138
+ description: "Perplexity Sonar Reasoning Pro chain-of-thought web-grounded search model for complex problem-solving; 128K-token context."
1139
+ },
1140
+ capabilities: {
1141
+ vision: true,
1142
+ tools: false,
1143
+ structuredOutput: true,
1144
+ contextWindow: 128e3
1145
+ }
1146
+ }),
1147
+ // DeepSeek retired V4 Flash upstream and routes the old id to V4.1 Flash at
1148
+ // Flash rates (https://api-docs.deepseek.com/news/news260910/); the old id
1149
+ // stays an alias so stored selections keep resolving.
1150
+ text("deepseek-flash", "DeepSeek V4.1 Flash", "deepseek-flash", {
1151
+ providerOptions: DEEPSEEK_THINKING,
1152
+ aliases: ["deepseek-v4-flash"],
1153
+ exposure: "catalog",
1154
+ display: {
1155
+ provider: "deepseek",
1156
+ costTier: 1,
1157
+ recommended: true,
1158
+ description: "DeepSeek V4.1 Flash thinking/non-thinking model with vision, tool calls, and JSON output; 1M-token context and up to 384K output tokens."
1159
+ },
1160
+ capabilities: {
1161
+ reasoning: true,
1162
+ vision: true,
1163
+ tools: true,
1164
+ structuredOutput: true,
1165
+ contextWindow: 1e6
1166
+ }
1167
+ }),
1168
+ text("deepseek-v4-pro", "DeepSeek V4 Pro", "deepseek-v4-pro", {
1169
+ providerOptions: DEEPSEEK_THINKING,
1170
+ exposure: "catalog",
1171
+ display: {
1172
+ provider: "deepseek",
1173
+ costTier: 2,
1174
+ 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."
1175
+ },
1176
+ capabilities: {
1177
+ reasoning: true,
1178
+ vision: false,
1179
+ tools: true,
1180
+ structuredOutput: true,
1181
+ contextWindow: 1e6
1182
+ }
1183
+ }),
1184
+ // 1M-token context: https://docs.x.ai/docs/models/grok-4.3
1185
+ text("grok-4.3", "Grok 4.3", "grok-4.3", {
1186
+ exposure: "catalog",
1187
+ display: {
1188
+ provider: "xai",
1189
+ costTier: 2,
1190
+ description: "xAI Grok 4.3 reasoning model with tool calling and structured outputs; text and image input, 1M-token context."
1191
+ },
1192
+ capabilities: {
1193
+ vision: true,
1194
+ tools: true,
1195
+ structuredOutput: true,
1196
+ contextWindow: 1e6
1197
+ }
1198
+ }),
1199
+ // Moonshot retired kimi-k2.5 on 2026-08-31 and no longer publishes its specs.
1200
+ text("kimi-k2.5", "Kimi K2.5", "kimi-k2.5", {
1201
+ defaults: { temperature: 1 },
1202
+ exposure: "catalog",
1203
+ display: {
1204
+ provider: "moonshot",
1205
+ costTier: 2,
1206
+ description: "Moonshot Kimi K2.5; the provider retired the model on 2026-08-31 and calls now return a model-not-found error."
1207
+ },
1208
+ capabilities: {}
1209
+ }),
1210
+ text("kimi-k3", "Kimi K3", "kimi-k3", {
1211
+ defaults: { temperature: 1 },
1212
+ exposure: "catalog",
1213
+ display: {
1214
+ provider: "moonshot",
1215
+ costTier: 2,
1216
+ description: "Moonshot Kimi K3 flagship model with native visual understanding and always-on thinking; text, image, and video input, 1M-token context."
1217
+ },
1218
+ capabilities: {
1219
+ reasoning: true,
1220
+ vision: true,
1221
+ tools: true,
1222
+ structuredOutput: true,
1223
+ contextWindow: 1e6
1224
+ }
1225
+ }),
1226
+ // Cowork calls the provider "MiniMax-M3"; the pricing key is lowercase.
1227
+ // 1M-token context: https://platform.minimax.io/docs/api-reference/text-openai-api
1228
+ text("minimax-m3", "MiniMax M3", "MiniMax-M3", {
1229
+ exposure: "catalog",
1230
+ aliases: ["MiniMax-M3"],
1231
+ display: {
1232
+ provider: "minimax",
1233
+ costTier: 2,
1234
+ description: "MiniMax M3 frontier multimodal model for agentic reasoning, tool use, and coding; text, image, and video input, 1M-token context."
1235
+ },
1236
+ capabilities: { vision: true, tools: true, contextWindow: 1e6 }
1237
+ })
1238
+ ];
1239
+
1240
+ // src/catalog/video.ts
1241
+ var VIDEO_USAGE = { unit: "seconds", modality: "VIDEO" };
1242
+ var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
1243
+ var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
1244
+ var OMNI_RATIOS = ["16:9", "9:16"];
1245
+ var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1246
+ var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1247
+ var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1248
+ var NEGATIVE_PROMPT = "blur, distort, and low quality";
1249
+ var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1250
+ var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1251
+ var VIDEO_MODELS = [
1252
+ {
1253
+ id: "veo-3.1",
1254
+ aliases: [
1255
+ "veo-3.1-generate-001",
1256
+ "veo-3.1-generate-preview",
1257
+ "veo3",
1258
+ "veo-3.1-frame-specific"
1259
+ ],
1260
+ label: "Veo 3.1",
1261
+ type: "video",
1262
+ adapter: "google-genai",
1263
+ providerModelId: "veo-3.1-generate-preview",
1264
+ lifecycle: "active",
1265
+ exposure: "catalog",
1266
+ constraints: {
1267
+ aspectRatios: [...OMNI_RATIOS],
1268
+ resolutions: ["720p", "1080p", "4k"],
1269
+ durations: [8],
1270
+ references: { images: 3 },
1271
+ supports: ["lastFrame"]
1272
+ },
1273
+ defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1274
+ usage: { ...VIDEO_USAGE, slug: "veo" },
1275
+ pricingKind: "video_per_second",
1276
+ display: {
1277
+ provider: "google",
1278
+ description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
1279
+ logo: GOOGLE_LOGO
1280
+ },
1281
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1282
+ },
1283
+ {
1284
+ id: "veo-3.1-fast",
1285
+ aliases: [
1286
+ "veo-3.1-fast-generate-001",
1287
+ "veo-3.1-fast-generate-preview",
1288
+ "veo-3.1-fast-generate-001-frame-specific"
1289
+ ],
1290
+ label: "Veo 3.1 Fast",
1291
+ type: "video",
1292
+ adapter: "google-genai",
1293
+ providerModelId: "veo-3.1-fast-generate-preview",
1294
+ lifecycle: "active",
1295
+ exposure: "internal",
1296
+ constraints: {
1297
+ aspectRatios: [...OMNI_RATIOS],
1298
+ resolutions: ["720p", "1080p", "4k"],
1299
+ durations: [4, 8],
1300
+ references: { images: 3 },
1301
+ supports: ["lastFrame"]
1302
+ },
1303
+ defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1304
+ usage: { ...VIDEO_USAGE },
1305
+ pricingKind: "video_per_second",
1306
+ display: {
1307
+ provider: "google",
1308
+ description: "Faster variant of Google Veo 3.1; text- and image-to-video with natively generated audio at 4 or 8 seconds."
1309
+ },
1310
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1311
+ },
1312
+ {
1313
+ id: "veo-3.1-lite",
1314
+ aliases: [
1315
+ "veo-3.1-lite-generate-001",
1316
+ "veo-3.1-lite-generate-preview",
1317
+ "veo-3.1-lite-generate-001-frame-specific"
1318
+ ],
1319
+ label: "Veo 3.1 Lite",
1320
+ type: "video",
1321
+ adapter: "google-genai",
1322
+ providerModelId: "veo-3.1-lite-generate-preview",
1323
+ lifecycle: "active",
1324
+ exposure: "internal",
1325
+ constraints: {
1326
+ aspectRatios: [...OMNI_RATIOS],
1327
+ resolutions: ["720p", "1080p"],
1328
+ durations: [4, 8],
1329
+ references: { images: 3 },
1330
+ supports: ["lastFrame"]
1331
+ },
1332
+ defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1333
+ usage: { ...VIDEO_USAGE },
1334
+ pricingKind: "video_per_second",
1335
+ display: {
1336
+ provider: "google",
1337
+ 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."
1338
+ },
1339
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1340
+ },
1341
+ {
1342
+ id: "gemini-omni-flash",
1343
+ aliases: [
1344
+ "gemini-omni-flash-preview",
1345
+ "geminiOmniFlash",
1346
+ "gemini-omni-video",
1347
+ "gemini-omni-reference",
1348
+ "gemini-omni-edit"
1349
+ ],
1350
+ label: "Gemini Omni Flash",
1351
+ type: "video",
1352
+ adapter: "google-genai",
1353
+ providerModelId: "gemini-omni-flash-preview",
1354
+ lifecycle: "active",
1355
+ exposure: "catalog",
1356
+ constraints: {
1357
+ // 1.0 rejects `resolution`; it renders 720p. No defaults: the adapter
1358
+ // sends ratio and duration only when the caller set them, so a
1359
+ // reference clip keeps its own framing.
1360
+ aspectRatios: [...OMNI_RATIOS],
1361
+ durations: [3, 4, 5, 6, 7, 8, 9, 10],
1362
+ references: { images: 6, videos: 1 },
1363
+ supports: []
1364
+ },
1365
+ defaults: {},
1366
+ usage: { ...VIDEO_USAGE, slug: "gemini_omni" },
1367
+ pricingKind: "video_per_second",
1368
+ display: {
1369
+ provider: "google",
1370
+ 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.",
1371
+ logo: GOOGLE_LOGO
1372
+ },
1373
+ capabilities: { acceptsSourceVideo: true }
1374
+ },
1375
+ {
1376
+ id: "gemini-omni-1.1-flash",
1377
+ aliases: ["gemini-omni-1.1-video", "gemini-omni-1.1-reference", "gemini-omni-1.1-edit"],
1378
+ label: "Gemini Omni 1.1 Flash",
1379
+ type: "video",
1380
+ adapter: "google-genai",
1381
+ providerModelId: "gemini-omni-1.1-flash",
1382
+ lifecycle: "active",
1383
+ exposure: "catalog",
1384
+ constraints: {
1385
+ aspectRatios: [...OMNI_RATIOS],
1386
+ resolutions: ["360p", "720p", "1080p", "4k"],
1387
+ durations: [3, 4, 5, 6, 7, 8, 9, 10],
1388
+ references: { images: 6, videos: 1 },
1389
+ supports: []
1390
+ },
1391
+ defaults: {},
1392
+ usage: { ...VIDEO_USAGE },
1393
+ pricingKind: "video_per_second",
1394
+ display: {
1395
+ provider: "google",
1396
+ 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."
1397
+ },
1398
+ capabilities: { acceptsSourceVideo: true }
1399
+ },
1400
+ {
1401
+ // vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
1402
+ id: "seedance-2.0",
1403
+ aliases: ["seedance2", "seedance-2-0", "dreamina-seedance-2-0-260128"],
1404
+ label: "Seedance 2.0",
1405
+ type: "video",
1406
+ adapter: "ark",
1407
+ providerModelId: "dreamina-seedance-2-0-260128",
1408
+ lifecycle: "active",
1409
+ exposure: "catalog",
1410
+ constraints: {
1411
+ aspectRatios: [...SEEDANCE_RATIOS],
1412
+ resolutions: ["480p", "720p", "1080p", "4k"],
1413
+ durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1414
+ durationPresets: [4, 6, 8, 10, 12, 15],
1415
+ references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1416
+ ratioIgnoredWith: ["firstFrame"],
1417
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1418
+ },
1419
+ defaults: {
1420
+ durationSeconds: 5,
1421
+ resolution: "720p",
1422
+ aspectRatio: "16:9",
1423
+ generateAudio: true
1424
+ },
1425
+ usage: { ...VIDEO_USAGE, slug: "seedance2", providerLabel: "byteplus" },
1426
+ pricingKind: "video_per_second",
1427
+ display: {
1428
+ provider: "bytedance",
1429
+ description: "High-quality AI video generation with reference image conditioning. Supports 4-15 second clips with human preprocessing.",
1430
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png"
1431
+ },
1432
+ capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1433
+ },
1434
+ {
1435
+ id: "seedance-2.0-fast",
1436
+ aliases: ["seedance-2-0-fast", "dreamina-seedance-2-0-fast-260128"],
1437
+ label: "Seedance 2.0 Fast",
1438
+ type: "video",
1439
+ adapter: "ark",
1440
+ providerModelId: "dreamina-seedance-2-0-fast-260128",
1441
+ lifecycle: "active",
1442
+ exposure: "catalog",
1443
+ constraints: {
1444
+ aspectRatios: [...SEEDANCE_RATIOS],
1445
+ resolutions: ["480p", "720p"],
1446
+ durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1447
+ references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1448
+ ratioIgnoredWith: ["firstFrame"],
1449
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1450
+ },
1451
+ defaults: {
1452
+ durationSeconds: 5,
1453
+ resolution: "720p",
1454
+ aspectRatio: "16:9",
1455
+ generateAudio: true
1456
+ },
1457
+ usage: { ...VIDEO_USAGE },
1458
+ pricingKind: "video_per_second",
1459
+ display: {
1460
+ provider: "bytedance",
1461
+ 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."
1462
+ },
1463
+ capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1464
+ },
1465
+ {
1466
+ // generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
1467
+ id: "seedance-2.5",
1468
+ aliases: ["seedance-2-5", "dreamina-seedance-2-5-260628"],
1469
+ label: "Seedance 2.5",
1470
+ type: "video",
1471
+ adapter: "ark",
1472
+ providerModelId: "dreamina-seedance-2-5-260628",
1473
+ lifecycle: "active",
1474
+ exposure: "catalog",
1475
+ constraints: {
1476
+ aspectRatios: [...SEEDANCE_RATIOS],
1477
+ resolutions: ["480p", "720p", "1080p"],
1478
+ durations: { min: 4, max: 30 },
1479
+ references: { images: 30, videos: 10, audios: 10 },
1480
+ ratioIgnoredWith: ["firstFrame"],
1481
+ supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1482
+ },
1483
+ defaults: {
1484
+ durationSeconds: 5,
1485
+ resolution: "720p",
1486
+ aspectRatio: "16:9",
1487
+ generateAudio: false
1488
+ },
1489
+ usage: { ...VIDEO_USAGE },
1490
+ pricingKind: "video_per_second",
1491
+ display: {
1492
+ provider: "bytedance",
1493
+ 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."
1494
+ },
1495
+ capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1496
+ },
1497
+ {
1498
+ // Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
1499
+ id: "grok-imagine",
1500
+ aliases: ["grok-imagine-video", "grokImagine"],
1501
+ label: "Grok Imagine",
1502
+ type: "video",
1503
+ adapter: "xai-video",
1504
+ providerModelId: "grok-imagine-video",
1505
+ lifecycle: "active",
1506
+ exposure: "catalog",
1507
+ constraints: {
1508
+ aspectRatios: [...GROK_RATIOS],
1509
+ resolutions: ["480p", "720p"],
1510
+ durations: { min: 1, max: 15 },
1511
+ durationPresets: [4, 6, 8, 10],
1512
+ references: { images: 7 },
1513
+ supports: []
1514
+ },
1515
+ // No resolution default: xAI picks its own unless the caller asks.
1516
+ defaults: { durationSeconds: 8, aspectRatio: "16:9" },
1517
+ usage: { unit: "reported_cost_usd", modality: "VIDEO" },
1518
+ pricingKind: "video_per_second",
1519
+ display: {
1520
+ provider: "xai",
1521
+ description: "xAI's reference-to-video model. Generates short clips conditioned on up to 7 reference images with flexible aspect ratios.",
1522
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/858b7fcc-9bd5-411d-aea1-a7b35ecfffab_compressed.png"
1523
+ },
1524
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1525
+ },
1526
+ {
1527
+ id: "kling-2.5",
1528
+ aliases: ["kling-v2.5-turbo-pro", "kling-2.5-turbo-pro", "kling-v2.5"],
1529
+ label: "Kling 2.5",
1530
+ type: "video",
1531
+ adapter: "higgsfield",
1532
+ providerModelId: "kling-video/v2.5-turbo/pro/image-to-video",
1533
+ lifecycle: "active",
1534
+ exposure: "catalog",
1535
+ constraints: {
1536
+ aspectRatios: [...KLING_RATIOS],
1537
+ durations: [5, 10],
1538
+ requires: ["firstFrame"],
1539
+ supports: ["cfgScale", "negativePrompt", "lastFrame"]
1540
+ },
1541
+ defaults: {
1542
+ durationSeconds: 5,
1543
+ aspectRatio: "16:9",
1544
+ cfgScale: 0.5,
1545
+ negativePrompt: NEGATIVE_PROMPT
1546
+ },
1547
+ usage: { ...VIDEO_USAGE, slug: "grok" },
1548
+ pricingKind: "video_per_second",
1549
+ display: {
1550
+ provider: "kuaishou",
1551
+ 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."
1552
+ },
1553
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1554
+ },
1555
+ {
1556
+ // trigger-workflows validates 5/10 only; Space Builder allows 3-15s (Kling30Input).
1557
+ id: "kling-3.0",
1558
+ aliases: ["kling-v3.0-pro", "kling-v3.0", "kling-3.0-pro"],
1559
+ label: "Kling 3.0",
1560
+ type: "video",
1561
+ adapter: "higgsfield",
1562
+ providerModelId: "kling-video/v3.0/pro/image-to-video",
1563
+ lifecycle: "active",
1564
+ exposure: "catalog",
1565
+ constraints: {
1566
+ aspectRatios: [...KLING_RATIOS],
1567
+ durations: { min: 3, max: 15 },
1568
+ requires: ["firstFrame"],
1569
+ supports: ["cfgScale", "negativePrompt", "lastFrame"]
1570
+ },
1571
+ defaults: {
1572
+ durationSeconds: 5,
1573
+ aspectRatio: "16:9",
1574
+ cfgScale: 0.5,
1575
+ negativePrompt: NEGATIVE_PROMPT
1576
+ },
1577
+ usage: { ...VIDEO_USAGE },
1578
+ pricingKind: "video_per_second",
1579
+ display: {
1580
+ provider: "kuaishou",
1581
+ 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."
1582
+ },
1583
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1584
+ },
1585
+ {
1586
+ // mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
1587
+ id: "kling-v3-omni-video",
1588
+ aliases: ["kwaivgi/kling-v3-omni-video", "kling-v3-omni"],
1589
+ label: "Kling V3 Omni",
1590
+ type: "video",
1591
+ adapter: "replicate",
1592
+ providerModelId: "kwaivgi/kling-v3-omni-video",
1593
+ lifecycle: "active",
1594
+ exposure: "catalog",
1595
+ constraints: {
1596
+ aspectRatios: [
1597
+ "1:1",
1598
+ "16:9",
1599
+ "9:16",
1600
+ "4:3",
1601
+ "3:4",
1602
+ "3:2",
1603
+ "2:3",
1604
+ "21:9",
1605
+ "4:5",
1606
+ "adaptive"
1607
+ ],
1608
+ resolutions: ["720p", "1080p"],
1609
+ durations: { min: 3, max: 15 },
1610
+ references: { images: 7 },
1611
+ supports: ["generateAudio", "lastFrame"]
1612
+ },
1613
+ defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
1614
+ usage: { unit: "compute_seconds", modality: "VIDEO" },
1615
+ pricingKind: "video_per_second",
1616
+ display: {
1617
+ provider: "kuaishou",
1618
+ 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."
1619
+ },
1620
+ capabilities: {}
1621
+ },
1622
+ {
1623
+ id: "minimax-h3",
1624
+ aliases: [],
1625
+ label: "MiniMax H3",
1626
+ type: "video",
1627
+ adapter: "fal",
1628
+ providerModelId: "minimax/h3",
1629
+ lifecycle: "active",
1630
+ exposure: "catalog",
1631
+ constraints: {
1632
+ aspectRatios: [...H3_RATIOS],
1633
+ resolutions: ["480p", "768p", "2k", "4k"],
1634
+ durations: { min: 5, max: 15 },
1635
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1636
+ },
1637
+ defaults: {
1638
+ durationSeconds: 5,
1639
+ resolution: "2k",
1640
+ aspectRatio: "16:9",
1641
+ promptExpansion: "balanced"
1642
+ },
1643
+ usage: { ...VIDEO_USAGE },
1644
+ pricingKind: "video_per_second",
1645
+ display: {
1646
+ provider: "minimax",
1647
+ 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."
1648
+ },
1649
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1650
+ },
1651
+ {
1652
+ id: "minimax-h3-max",
1653
+ aliases: [],
1654
+ label: "MiniMax H3 Max",
1655
+ type: "video",
1656
+ adapter: "fal",
1657
+ providerModelId: "minimax/h3-max",
1658
+ lifecycle: "active",
1659
+ exposure: "catalog",
1660
+ constraints: {
1661
+ aspectRatios: [...H3_RATIOS],
1662
+ resolutions: ["480p", "768p"],
1663
+ durations: { min: 5, max: 15 },
1664
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1665
+ },
1666
+ defaults: {
1667
+ durationSeconds: 5,
1668
+ resolution: "768p",
1669
+ aspectRatio: "16:9",
1670
+ promptExpansion: "balanced"
1671
+ },
1672
+ usage: { ...VIDEO_USAGE },
1673
+ pricingKind: "video_per_second",
1674
+ display: {
1675
+ provider: "minimax",
1676
+ description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
1677
+ },
1678
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1679
+ },
1680
+ {
1681
+ id: "minimax-h3-reference",
1682
+ aliases: [],
1683
+ label: "MiniMax H3 Reference",
1684
+ type: "video",
1685
+ adapter: "fal",
1686
+ providerModelId: "minimax/h3/reference-to-video",
1687
+ lifecycle: "active",
1688
+ exposure: "catalog",
1689
+ constraints: {
1690
+ aspectRatios: [...H3_REFERENCE_RATIOS],
1691
+ resolutions: ["480p", "768p", "2k", "4k"],
1692
+ durations: { min: 5, max: 15 },
1693
+ references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1694
+ supports: ["seed", "promptExpansion", "safetyChecker"]
1695
+ },
1696
+ defaults: {
1697
+ durationSeconds: 5,
1698
+ resolution: "2k",
1699
+ aspectRatio: "adaptive",
1700
+ promptExpansion: "balanced"
1701
+ },
1702
+ usage: { ...VIDEO_USAGE },
1703
+ pricingKind: "video_per_second",
1704
+ display: {
1705
+ provider: "minimax",
1706
+ 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."
1707
+ },
1708
+ capabilities: {}
1709
+ },
1710
+ {
1711
+ id: "minimax-h3-max-reference",
1712
+ aliases: [],
1713
+ label: "MiniMax H3 Max Reference",
1714
+ type: "video",
1715
+ adapter: "fal",
1716
+ providerModelId: "minimax/h3-max/reference-to-video",
1717
+ lifecycle: "active",
1718
+ exposure: "catalog",
1719
+ constraints: {
1720
+ aspectRatios: [...H3_REFERENCE_RATIOS],
1721
+ resolutions: ["480p", "768p"],
1722
+ durations: { min: 5, max: 15 },
1723
+ references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1724
+ supports: ["seed", "promptExpansion", "safetyChecker"]
1725
+ },
1726
+ defaults: {
1727
+ durationSeconds: 5,
1728
+ resolution: "768p",
1729
+ aspectRatio: "adaptive",
1730
+ promptExpansion: "balanced"
1731
+ },
1732
+ usage: { ...VIDEO_USAGE },
1733
+ pricingKind: "video_per_second",
1734
+ display: {
1735
+ provider: "minimax",
1736
+ 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."
1737
+ },
1738
+ capabilities: {}
1739
+ },
1740
+ {
1741
+ // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
1742
+ id: "kling-o1-v2v",
1743
+ aliases: [],
1744
+ label: "Kling O1 Video to Video",
1745
+ type: "video",
1746
+ adapter: "fal",
1747
+ providerModelId: "fal-ai/kling-video/o1/video-to-video/reference",
1748
+ lifecycle: "active",
1749
+ exposure: "internal",
1750
+ constraints: {
1751
+ aspectRatios: [...KLING_RATIOS],
1752
+ durations: { min: 3, max: 10 },
1753
+ requires: ["sourceVideo"],
1754
+ supports: []
1755
+ },
1756
+ defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1757
+ usage: { ...VIDEO_USAGE },
1758
+ pricingKind: "video_per_second",
1759
+ display: {
1760
+ provider: "kuaishou",
1761
+ 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."
1762
+ },
1763
+ capabilities: { acceptsSourceVideo: true }
1764
+ },
1765
+ {
1766
+ id: "hailuo-02",
1767
+ aliases: [],
1768
+ label: "Hailuo 02",
1769
+ type: "video",
1770
+ adapter: "replicate",
1771
+ providerModelId: "minimax/hailuo-02",
1772
+ lifecycle: "active",
1773
+ exposure: "internal",
1774
+ constraints: {
1775
+ resolutions: ["768p"],
1776
+ durations: [6, 10],
1777
+ supports: ["lastFrame"]
1778
+ },
1779
+ defaults: { durationSeconds: 6, resolution: "768p" },
1780
+ usage: { unit: "compute_seconds", modality: "VIDEO" },
1781
+ pricingKind: "video_per_second",
1782
+ display: {
1783
+ provider: "minimax",
1784
+ 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."
1785
+ },
1786
+ capabilities: {}
1787
+ },
1788
+ {
1789
+ id: "higgsfield-dop-preview",
1790
+ aliases: [],
1791
+ label: "Higgsfield DOP Preview",
1792
+ type: "video",
1793
+ adapter: "higgsfield",
1794
+ providerModelId: "dop-preview",
1795
+ lifecycle: "active",
1796
+ exposure: "internal",
1797
+ constraints: {
1798
+ requires: ["firstFrame"],
1799
+ supports: ["seed", "lastFrame"]
1800
+ },
1801
+ defaults: {},
1802
+ usage: { ...VIDEO_USAGE },
1803
+ pricingKind: "video_per_second",
1804
+ display: {
1805
+ provider: "higgsfield",
1806
+ 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."
1807
+ },
1808
+ capabilities: {}
1809
+ }
1810
+ ];
1811
+
1812
+ // src/catalog/models.ts
1813
+ var MODELS = [
1814
+ ...TEXT_MODELS,
1815
+ ...IMAGE_MODELS,
1816
+ ...VIDEO_MODELS,
1817
+ ...OTHER_MODELS
1818
+ ];
1819
+
1820
+ // src/resolve-options.ts
1821
+ var SIZE_ORDER = ["512", "1K", "2K", "4K"];
1822
+ var RESOLUTION_ORDER = ["360p", "480p", "720p", "768p", "1080p", "2k", "4k"];
1823
+ function ratioValue(r) {
1824
+ if (r === "adaptive") return 1;
1825
+ const [w, h] = r.split(":").map(Number);
1826
+ return w / h;
1827
+ }
1828
+ function orientation(r) {
1829
+ const v = ratioValue(r);
1830
+ return v > 1 ? "landscape" : v < 1 ? "portrait" : "square";
1831
+ }
1832
+ function nearestAspectRatio(requested, supported) {
1833
+ if (supported.includes(requested)) return requested;
1834
+ const target = requested === "adaptive" ? "1:1" : requested;
1835
+ const sameBucket = supported.filter(
1836
+ (s) => s !== "adaptive" && orientation(s) === orientation(target)
1837
+ );
1838
+ const pool = sameBucket.length > 0 ? sameBucket : supported.filter((s) => s !== "adaptive");
1839
+ const fallback = pool[0] ?? supported[0];
1840
+ if (!fallback) return target;
1841
+ const dist = (s) => Math.abs(Math.log(ratioValue(s)) - Math.log(ratioValue(target)));
1842
+ return pool.reduce((best, s) => dist(s) < dist(best) ? s : best, fallback);
1843
+ }
1844
+ function nearestLowerTier(requested, supported, order) {
1845
+ const idx = order.indexOf(requested);
1846
+ for (let i = idx; i >= 0; i--) {
1847
+ const candidate = order[i];
1848
+ if (candidate !== void 0 && supported.includes(candidate)) return candidate;
1849
+ }
1850
+ for (let i = idx + 1; i < order.length; i++) {
1851
+ const candidate = order[i];
1852
+ if (candidate !== void 0 && supported.includes(candidate)) return candidate;
1853
+ }
1854
+ return requested;
1855
+ }
1856
+ function resolveTier(field, code, requested, supported, order, model, onUnsupported, warnings) {
1857
+ if (requested === void 0 || !supported || supported.includes(requested)) return requested;
1858
+ if (onUnsupported === "error") {
1859
+ throw new ModelKitError({
1860
+ code: "unsupported_option",
1861
+ message: `${model.id} does not support ${field} "${requested}". Supported: ${supported.join(", ")}.`,
1862
+ model: model.id
1863
+ });
1864
+ }
1865
+ const to = nearestLowerTier(requested, supported, order);
1866
+ warnings.push({
1867
+ code,
1868
+ field,
1869
+ from: requested,
1870
+ to,
1871
+ message: `${field} ${requested} coerced to ${to} for ${model.id}`
1872
+ });
1873
+ return to;
1874
+ }
1875
+ function resolveDuration(requested, durations, model, onUnsupported, warnings) {
1876
+ if (requested === void 0 || !durations) return requested;
1877
+ const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
1878
+ if (inSet) return requested;
1879
+ if (onUnsupported === "error") {
1880
+ const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
1881
+ throw new ModelKitError({
1882
+ code: "unsupported_option",
1883
+ message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
1884
+ model: model.id
1885
+ });
1886
+ }
1887
+ const to = Array.isArray(durations) ? durations.reduce(
1888
+ (best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
1889
+ durations[0] ?? requested
1890
+ ) : Math.min(Math.max(requested, durations.min), durations.max);
1891
+ warnings.push({
1892
+ code: "duration_coerced",
1893
+ field: "durationSeconds",
1894
+ from: requested,
1895
+ to,
1896
+ message: `duration ${requested}s coerced to ${to}s for ${model.id}`
1897
+ });
1898
+ return to;
1899
+ }
1900
+ function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
1901
+ if (requested === void 0 || requested === "adaptive" || !supported) return requested;
1902
+ if (supported.includes(requested)) return requested;
1903
+ if (onUnsupported === "error") {
1904
+ throw new ModelKitError({
1905
+ code: "unsupported_option",
1906
+ message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
1907
+ model: model.id
1908
+ });
1909
+ }
1910
+ const to = nearestAspectRatio(requested, supported);
1911
+ warnings.push({
1912
+ code: "ratio_coerced",
1913
+ field: "aspectRatio",
1914
+ from: requested,
1915
+ to,
1916
+ message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
1917
+ });
1918
+ return to;
1919
+ }
1920
+ function compact(refs) {
1921
+ return (refs ?? []).filter((r) => Boolean(r));
1922
+ }
1923
+ function trim(field, refs, limit, model, warnings) {
1924
+ if (limit === void 0 || refs.length <= limit) return refs;
1925
+ warnings.push({
1926
+ code: "references_trimmed",
1927
+ field,
1928
+ from: refs.length,
1929
+ to: limit,
1930
+ message: `${field} trimmed from ${refs.length} to ${limit} for ${model.id}`
1931
+ });
1932
+ return refs.slice(0, limit);
1933
+ }
1934
+ function resolveImageOptions(model, request, onUnsupported = "error") {
1935
+ const warnings = [];
1936
+ const c = model.constraints;
1937
+ const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1938
+ const aspectRatio = resolveAspectRatio(
1939
+ merged.aspectRatio,
1940
+ c.aspectRatios,
1941
+ model,
1942
+ onUnsupported,
1943
+ warnings
1944
+ );
1945
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
1946
+ const size = resolveTier(
1947
+ "size",
1948
+ "size_coerced",
1949
+ merged.size,
1950
+ c.sizes,
1951
+ SIZE_ORDER,
1952
+ model,
1953
+ onUnsupported,
1954
+ warnings
1955
+ );
1956
+ if (size !== void 0) merged.size = size;
1957
+ const references = trim(
1958
+ "references",
1959
+ compact(merged.references),
1960
+ c.references?.images ?? c.references?.total,
1961
+ model,
1962
+ warnings
1963
+ );
1964
+ if (references.length > 0) merged.references = references;
1965
+ else delete merged.references;
1966
+ if (c.requires?.includes("references") && references.length === 0) {
1967
+ throw new ModelKitError({
1968
+ code: "missing_input",
1969
+ message: `${model.id} requires at least one reference image`,
1970
+ model: model.id
1971
+ });
1972
+ }
1973
+ dropUnsupported(merged, model, warnings, [
1974
+ "seed",
1975
+ "quality",
1976
+ "count",
1977
+ "outputFormat",
1978
+ "scaleFactor",
1979
+ "safetySettings",
1980
+ "temperature",
1981
+ "upscale"
1982
+ ]);
1983
+ return { request: merged, warnings };
1984
+ }
1985
+ function resolveVideoOptions(model, request, onUnsupported = "error") {
1986
+ const warnings = [];
1987
+ const c = model.constraints;
1988
+ const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
1989
+ for (const input of c.requires ?? []) {
1990
+ const present = input === "references" ? compact(merged.referenceImages).length + compact(merged.referenceVideos).length + compact(merged.referenceAudios).length > 0 : merged[input] !== void 0;
1991
+ if (!present)
1992
+ throw new ModelKitError({
1993
+ code: "missing_input",
1994
+ message: `${model.id} requires ${input}`,
1995
+ model: model.id
1996
+ });
1997
+ }
1998
+ if (merged.sourceVideo !== void 0 && !model.capabilities?.acceptsSourceVideo) {
1999
+ if (onUnsupported === "error") {
2000
+ throw new ModelKitError({
2001
+ code: "unsupported_option",
2002
+ message: `${model.id} does not take a source video`,
2003
+ model: model.id
2004
+ });
2005
+ }
2006
+ warnings.push({
2007
+ code: "option_ignored",
2008
+ field: "sourceVideo",
2009
+ message: `${model.id} does not take a source video; dropped`
2010
+ });
2011
+ delete merged.sourceVideo;
2012
+ }
2013
+ const hasFrames = merged.firstFrame !== void 0 || merged.lastFrame !== void 0;
2014
+ const hasRefs = compact(merged.referenceImages).length + compact(merged.referenceVideos).length + compact(merged.referenceAudios).length > 0;
2015
+ if (hasFrames && hasRefs && model.capabilities?.framesExcludeReferences) {
2016
+ if (onUnsupported === "error") {
2017
+ throw new ModelKitError({
2018
+ code: "unsupported_option",
2019
+ message: `${model.id} takes frames or references, not both`,
2020
+ model: model.id
2021
+ });
2022
+ }
2023
+ warnings.push({
2024
+ code: "option_ignored",
2025
+ field: "referenceImages",
2026
+ message: `${model.id} takes frames or references, not both; references dropped`
2027
+ });
2028
+ delete merged.referenceImages;
2029
+ delete merged.referenceVideos;
2030
+ delete merged.referenceAudios;
2031
+ }
2032
+ for (const input of c.ratioIgnoredWith ?? []) {
2033
+ if (merged[input] !== void 0 && merged.aspectRatio !== void 0) {
2034
+ if (request.aspectRatio !== void 0) {
2035
+ warnings.push({
2036
+ code: "ratio_dropped",
2037
+ field: "aspectRatio",
2038
+ from: merged.aspectRatio,
2039
+ message: `${model.id} ignores aspectRatio when ${input} is set`
2040
+ });
2041
+ }
2042
+ delete merged.aspectRatio;
2043
+ }
2044
+ }
2045
+ const aspectRatio = resolveAspectRatio(
2046
+ merged.aspectRatio,
2047
+ c.aspectRatios,
2048
+ model,
2049
+ onUnsupported,
2050
+ warnings
2051
+ );
2052
+ if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
2053
+ const resolution = resolveTier(
2054
+ "resolution",
2055
+ "resolution_coerced",
2056
+ merged.resolution,
2057
+ c.resolutions,
2058
+ RESOLUTION_ORDER,
2059
+ model,
2060
+ onUnsupported,
2061
+ warnings
2062
+ );
2063
+ if (resolution !== void 0) merged.resolution = resolution;
2064
+ const duration = resolveDuration(
2065
+ merged.durationSeconds,
2066
+ c.durations,
2067
+ model,
2068
+ onUnsupported,
2069
+ warnings
2070
+ );
2071
+ if (duration !== void 0) merged.durationSeconds = duration;
2072
+ const limits = c.references ?? {};
2073
+ let images = trim(
2074
+ "referenceImages",
2075
+ compact(merged.referenceImages),
2076
+ limits.images,
2077
+ model,
2078
+ warnings
2079
+ );
2080
+ let videos = trim(
2081
+ "referenceVideos",
2082
+ compact(merged.referenceVideos),
2083
+ limits.videos,
2084
+ model,
2085
+ warnings
2086
+ );
2087
+ let audios = trim(
2088
+ "referenceAudios",
2089
+ compact(merged.referenceAudios),
2090
+ limits.audios,
2091
+ model,
2092
+ warnings
2093
+ );
2094
+ if (limits.total !== void 0) {
2095
+ let over = images.length + videos.length + audios.length - limits.total;
2096
+ if (over > 0) {
2097
+ const cut = Math.min(over, audios.length);
2098
+ audios = trim("referenceAudios", audios, audios.length - cut, model, warnings);
2099
+ over -= cut;
2100
+ }
2101
+ if (over > 0) {
2102
+ const cut = Math.min(over, videos.length);
2103
+ videos = trim("referenceVideos", videos, videos.length - cut, model, warnings);
2104
+ over -= cut;
2105
+ }
2106
+ if (over > 0)
2107
+ images = trim("referenceImages", images, images.length - over, model, warnings);
2108
+ }
2109
+ if (limits.audioOnly === false && audios.length > 0 && images.length === 0 && videos.length === 0 && !merged.firstFrame && !merged.sourceVideo) {
2110
+ throw new ModelKitError({
2111
+ code: "missing_input",
2112
+ message: `${model.id} rejects audio-only references`,
2113
+ model: model.id
2114
+ });
2115
+ }
2116
+ setOrDelete(merged, "referenceImages", images);
2117
+ setOrDelete(merged, "referenceVideos", videos);
2118
+ setOrDelete(merged, "referenceAudios", audios);
2119
+ dropUnsupported(merged, model, warnings, [
2120
+ "seed",
2121
+ "negativePrompt",
2122
+ "cfgScale",
2123
+ "generateAudio",
2124
+ "promptExpansion",
2125
+ "lastFrame",
2126
+ "watermark",
2127
+ "safetyChecker"
2128
+ ]);
2129
+ return { request: merged, warnings };
2130
+ }
2131
+ function resolveAudioOptions(model, request, onUnsupported = "error") {
2132
+ const warnings = [];
2133
+ const c = model.constraints;
2134
+ const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
2135
+ for (const input of c.requires ?? []) {
2136
+ const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
2137
+ if (!present)
2138
+ throw new ModelKitError({
2139
+ code: "missing_input",
2140
+ message: `${model.id} requires ${input}`,
2141
+ model: model.id
2142
+ });
2143
+ }
2144
+ const duration = resolveDuration(
2145
+ merged.durationSeconds,
2146
+ c.durations,
2147
+ model,
2148
+ onUnsupported,
2149
+ warnings
2150
+ );
2151
+ if (duration !== void 0) merged.durationSeconds = duration;
2152
+ const references = trim(
2153
+ "references",
2154
+ compact(merged.references),
2155
+ c.references?.images ?? c.references?.total,
2156
+ model,
2157
+ warnings
2158
+ );
2159
+ if (references.length > 0) merged.references = references;
2160
+ else delete merged.references;
2161
+ dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
2162
+ return { request: merged, warnings };
2163
+ }
2164
+ function dropUnsupported(req, model, warnings, fields) {
2165
+ const supports = model.constraints.supports ?? [];
2166
+ for (const field of fields) {
2167
+ if (req[field] !== void 0 && !supports.includes(field)) {
2168
+ warnings.push({
2169
+ code: "option_ignored",
2170
+ field,
2171
+ from: req[field],
2172
+ message: `${model.id} does not support ${field}; ignored`
2173
+ });
2174
+ delete req[field];
2175
+ }
2176
+ }
2177
+ }
2178
+ function setOrDelete(req, field, refs) {
2179
+ if (refs.length > 0) req[field] = refs;
2180
+ else delete req[field];
2181
+ }
2182
+ function stripUndefined(obj) {
2183
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
2184
+ }
2185
+
2186
+ // src/catalog-entry.ts
2187
+ function resolveOptions(model, request, onUnsupported = "error") {
2188
+ switch (model.type) {
2189
+ case "image":
2190
+ case "upscale":
2191
+ case "bg-remove":
2192
+ return resolveImageOptions(model, request, onUnsupported);
2193
+ case "video":
2194
+ return resolveVideoOptions(model, request, onUnsupported);
2195
+ case "audio":
2196
+ return resolveAudioOptions(model, request, onUnsupported);
2197
+ default:
2198
+ throw new Error(`resolveOptions: unsupported model type "${model.type}"`);
2199
+ }
2200
+ }
2201
+ export {
2202
+ Catalog,
2203
+ IMAGE_MODELS,
2204
+ MODELS,
2205
+ ModelKitError,
2206
+ OTHER_MODELS,
2207
+ TEXT_MODELS,
2208
+ VIDEO_MODELS,
2209
+ isModelKitError,
2210
+ nearestAspectRatio,
2211
+ resolveAudioOptions,
2212
+ resolveImageOptions,
2213
+ resolveOptions,
2214
+ resolveVideoOptions
2215
+ };
2216
+ //# sourceMappingURL=catalog.js.map