@shop-os/modelkit 0.2.19 → 0.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/catalog.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var catalog_entry_exports = {};
22
22
  __export(catalog_entry_exports, {
23
23
  ADAPTER_IDS: () => ADAPTER_IDS,
24
+ AUDIO_OUTPUTS: () => AUDIO_OUTPUTS,
24
25
  Catalog: () => Catalog,
25
26
  CatalogModelSchema: () => CatalogModelSchema,
26
27
  CatalogModelSchemaBase: () => CatalogModelSchemaBase,
@@ -30,6 +31,7 @@ __export(catalog_entry_exports, {
30
31
  MODELS: () => MODELS,
31
32
  ModelKitError: () => ModelKitError,
32
33
  OTHER_MODELS: () => OTHER_MODELS,
34
+ REFERENCE_SYNTAXES: () => REFERENCE_SYNTAXES,
33
35
  SURFACES: () => SURFACES2,
34
36
  SurfaceSchema: () => SurfaceSchema,
35
37
  TEXT_MODELS: () => TEXT_MODELS,
@@ -42,7 +44,9 @@ __export(catalog_entry_exports, {
42
44
  liveState: () => liveState,
43
45
  nearestAspectRatio: () => nearestAspectRatio,
44
46
  normalizeExposure: () => normalizeExposure,
47
+ outputAudio: () => outputAudio,
45
48
  primeCatalog: () => primeCatalog,
49
+ promptConventions: () => promptConventions,
46
50
  resetLiveCatalog: () => resetLiveCatalog,
47
51
  resolveAudioOptions: () => resolveAudioOptions,
48
52
  resolveImageOptions: () => resolveImageOptions,
@@ -217,7 +221,9 @@ function geminiImage(id, label, aliases, sizes, display, exposure, references) {
217
221
  const constraints = {
218
222
  aspectRatios: [...GEMINI_RATIOS],
219
223
  sizes,
220
- supports: ["safetySettings", "temperature"]
224
+ supports: ["safetySettings", "temperature"],
225
+ // google-image sends MediaRef.label as a text part beside each reference.
226
+ prompt: { referenceSyntax: "caption" }
221
227
  };
222
228
  if (references !== void 0) constraints.references = references;
223
229
  const model = {
@@ -504,6 +510,7 @@ var IMAGE_MODELS = [
504
510
  constraints: {
505
511
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
506
512
  sizes: ["1K"],
513
+ references: { images: 8 },
507
514
  // flux-2-pro's job type always returns image/png; only the seed is forwarded.
508
515
  supports: ["seed"]
509
516
  },
@@ -1299,12 +1306,14 @@ var TEXT_MODELS = [
1299
1306
  var VIDEO_USAGE = { unit: "seconds" };
1300
1307
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
1301
1308
  var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
1309
+ var KLING_OMNI_RATIOS = ["16:9", "9:16", "1:1"];
1302
1310
  var OMNI_RATIOS = ["16:9", "9:16"];
1303
1311
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1304
1312
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1305
1313
  var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1306
1314
  var NEGATIVE_PROMPT = "blur, distort, and low quality";
1307
1315
  var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1316
+ var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
1308
1317
  var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
1309
1318
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1310
1319
  var VIDEO_MODELS = [
@@ -1325,9 +1334,14 @@ var VIDEO_MODELS = [
1325
1334
  constraints: {
1326
1335
  aspectRatios: [...OMNI_RATIOS],
1327
1336
  resolutions: ["720p", "1080p", "4k"],
1337
+ // Veo also takes 4 and 6, but must be 8 at 1080p/4k or with reference images;
1338
+ // [8] until the kit has a rule that forces it there (CHANGELOG 0.2.21).
1328
1339
  durations: [8],
1329
1340
  references: { images: 3 },
1330
- supports: ["lastFrame", "seed"]
1341
+ supports: ["lastFrame", "seed"],
1342
+ // 1,024 text tokens; 3,000 characters assumes ~2.9 characters per token.
1343
+ prompt: { referenceSyntax: "numbered", maxChars: 3e3 },
1344
+ audio: "always"
1331
1345
  },
1332
1346
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1333
1347
  usage: { ...VIDEO_USAGE, slug: "veo" },
@@ -1337,7 +1351,8 @@ var VIDEO_MODELS = [
1337
1351
  description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
1338
1352
  logo: GOOGLE_LOGO2
1339
1353
  },
1340
- capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1354
+ // Veo's lastFrame "must be used in combination with the image parameter".
1355
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES, lastFrameRequiresFirstFrame: true }
1341
1356
  },
1342
1357
  {
1343
1358
  id: "veo-3.1-fast",
@@ -1357,7 +1372,8 @@ var VIDEO_MODELS = [
1357
1372
  resolutions: ["720p", "1080p", "4k"],
1358
1373
  durations: [4, 6, 8],
1359
1374
  references: { images: 3 },
1360
- supports: ["lastFrame", "seed"]
1375
+ supports: ["lastFrame", "seed"],
1376
+ audio: "always"
1361
1377
  },
1362
1378
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1363
1379
  usage: { ...VIDEO_USAGE },
@@ -1385,7 +1401,8 @@ var VIDEO_MODELS = [
1385
1401
  aspectRatios: [...OMNI_RATIOS],
1386
1402
  resolutions: ["720p", "1080p"],
1387
1403
  durations: [4, 6, 8],
1388
- supports: ["lastFrame", "seed"]
1404
+ supports: ["lastFrame", "seed"],
1405
+ audio: "always"
1389
1406
  },
1390
1407
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1391
1408
  usage: { ...VIDEO_USAGE },
@@ -1419,7 +1436,10 @@ var VIDEO_MODELS = [
1419
1436
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1420
1437
  references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1421
1438
  sourceVideoSeconds: { max: 10 },
1422
- supports: []
1439
+ supports: [],
1440
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1441
+ prompt: { referenceSyntax: "caption" },
1442
+ audio: "always"
1423
1443
  },
1424
1444
  defaults: {},
1425
1445
  usage: { ...VIDEO_USAGE, slug: "gemini_omni" },
@@ -1452,8 +1472,12 @@ var VIDEO_MODELS = [
1452
1472
  // extension can upload a <= 10 s source with task "extend"; later ones
1453
1473
  // chain by `previousInteractionId` (the API rejects the id together
1454
1474
  // with a video task, so those calls carry the prompt alone).
1455
- supports: ["videoExtension"],
1456
- extension: { segmentSeconds: 10, maxTotalSeconds: 40 }
1475
+ // First-to-last-frame interpolation: `<LAST_FRAME>` goes with `<FIRST_FRAME>`.
1476
+ supports: ["videoExtension", "lastFrame"],
1477
+ extension: { segmentSeconds: 10, maxTotalSeconds: 40 },
1478
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1479
+ prompt: { referenceSyntax: "caption" },
1480
+ audio: "always"
1457
1481
  },
1458
1482
  defaults: {},
1459
1483
  usage: { ...VIDEO_USAGE },
@@ -1463,7 +1487,7 @@ var VIDEO_MODELS = [
1463
1487
  logo: GOOGLE_LOGO2,
1464
1488
  description: "Google Gemini Omni Flash 1.1 conversational video generation, editing and extension; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS, extendable to 40 seconds."
1465
1489
  },
1466
- capabilities: { acceptsSourceVideo: true }
1490
+ capabilities: { acceptsSourceVideo: true, lastFrameRequiresFirstFrame: true }
1467
1491
  },
1468
1492
  {
1469
1493
  // vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
@@ -1489,7 +1513,9 @@ var VIDEO_MODELS = [
1489
1513
  },
1490
1514
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1491
1515
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1492
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1516
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1517
+ supports: ["generateAudio", "lastFrame", "watermark"],
1518
+ audio: "optional"
1493
1519
  },
1494
1520
  defaults: {
1495
1521
  durationSeconds: 5,
@@ -1528,7 +1554,9 @@ var VIDEO_MODELS = [
1528
1554
  },
1529
1555
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1530
1556
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1531
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1557
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1558
+ supports: ["generateAudio", "lastFrame", "watermark"],
1559
+ audio: "optional"
1532
1560
  },
1533
1561
  defaults: {
1534
1562
  durationSeconds: 5,
@@ -1546,7 +1574,6 @@ var VIDEO_MODELS = [
1546
1574
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1547
1575
  },
1548
1576
  {
1549
- // generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
1550
1577
  // omni_reference_task_type edit/extend: adaptive ratio, edit sends duration -1.
1551
1578
  id: "seedance-2.5",
1552
1579
  aliases: ["seedance-2-5", "dreamina-seedance-2-5-260628"],
@@ -1568,13 +1595,15 @@ var VIDEO_MODELS = [
1568
1595
  },
1569
1596
  sourceVideoSeconds: { min: 2, max: 30, editMin: 4, inReferenceTotal: true },
1570
1597
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1571
- supports: ["generateAudio", "seed", "lastFrame", "watermark", "taskType"]
1598
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1599
+ supports: ["generateAudio", "lastFrame", "watermark", "taskType"],
1600
+ audio: "optional"
1572
1601
  },
1573
1602
  defaults: {
1574
1603
  durationSeconds: 5,
1575
1604
  resolution: "720p",
1576
1605
  aspectRatio: "16:9",
1577
- generateAudio: false
1606
+ generateAudio: true
1578
1607
  },
1579
1608
  usage: { ...VIDEO_USAGE },
1580
1609
  pricingKind: "video_per_second",
@@ -1586,7 +1615,6 @@ var VIDEO_MODELS = [
1586
1615
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1587
1616
  },
1588
1617
  {
1589
- // Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
1590
1618
  id: "grok-imagine",
1591
1619
  aliases: ["grok-imagine-video", "grokImagine"],
1592
1620
  label: "Grok Imagine",
@@ -1600,8 +1628,11 @@ var VIDEO_MODELS = [
1600
1628
  resolutions: ["480p", "720p"],
1601
1629
  durations: { min: 1, max: 15 },
1602
1630
  durationPresets: [4, 6, 8, 10],
1603
- references: { images: 5 },
1604
- supports: []
1631
+ // xAI: "A maximum of 7 reference images can be provided per request."
1632
+ references: { images: 7 },
1633
+ supports: [],
1634
+ // xAI can switch sound off (generate_audio); xai-video.ts never sends it.
1635
+ audio: "always"
1605
1636
  },
1606
1637
  // No resolution default: xAI picks its own unless the caller asks.
1607
1638
  defaults: { durationSeconds: 8, aspectRatio: "16:9" },
@@ -1623,15 +1654,16 @@ var VIDEO_MODELS = [
1623
1654
  providerModelId: "kling-video/v2.5-turbo/pro/image-to-video",
1624
1655
  lifecycle: "active",
1625
1656
  exposure: ["cowork", "space_builder"],
1657
+ // The endpoint has no aspect_ratio or last_image_url: the start image sets the framing.
1626
1658
  constraints: {
1627
- aspectRatios: [...KLING_RATIOS],
1628
1659
  durations: [5, 10],
1629
1660
  requires: ["firstFrame"],
1630
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1661
+ supports: ["cfgScale", "negativePrompt"],
1662
+ prompt: KLING_PROMPT,
1663
+ audio: "never"
1631
1664
  },
1632
1665
  defaults: {
1633
1666
  durationSeconds: 5,
1634
- aspectRatio: "16:9",
1635
1667
  cfgScale: 0.5,
1636
1668
  negativePrompt: NEGATIVE_PROMPT
1637
1669
  },
@@ -1640,7 +1672,7 @@ var VIDEO_MODELS = [
1640
1672
  display: {
1641
1673
  provider: "kuaishou",
1642
1674
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1643
- 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."
1675
+ description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt, 5- or 10-second clips."
1644
1676
  },
1645
1677
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1646
1678
  },
@@ -1654,17 +1686,18 @@ var VIDEO_MODELS = [
1654
1686
  providerModelId: "kling-video/v3.0/pro/image-to-video",
1655
1687
  lifecycle: "active",
1656
1688
  exposure: ["cowork", "space_builder"],
1689
+ // The endpoint has no aspect_ratio or negative_prompt; sound is "on"/"off" (default on).
1657
1690
  constraints: {
1658
- aspectRatios: [...KLING_RATIOS],
1659
1691
  durations: { min: 3, max: 15 },
1660
1692
  requires: ["firstFrame"],
1661
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1693
+ supports: ["cfgScale", "lastFrame", "generateAudio"],
1694
+ prompt: KLING_PROMPT,
1695
+ audio: "optional"
1662
1696
  },
1663
1697
  defaults: {
1664
1698
  durationSeconds: 5,
1665
- aspectRatio: "16:9",
1666
1699
  cfgScale: 0.5,
1667
- negativePrompt: NEGATIVE_PROMPT
1700
+ generateAudio: true
1668
1701
  },
1669
1702
  usage: { ...VIDEO_USAGE },
1670
1703
  pricingKind: "video_per_second",
@@ -1676,7 +1709,7 @@ var VIDEO_MODELS = [
1676
1709
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1677
1710
  },
1678
1711
  {
1679
- // mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
1712
+ // mode standard/pro/4k selects 720p/1080p/4K; the endpoint takes no separate resolution.
1680
1713
  // Replicate: "Max 7 [images] without video, 4 with video"; 4K does not support
1681
1714
  // reference_video. No `videos` limit yet: the adapter sends no reference video,
1682
1715
  // so `imagesWithVideo` stays dormant until one is wired through.
@@ -1689,21 +1722,25 @@ var VIDEO_MODELS = [
1689
1722
  lifecycle: "active",
1690
1723
  exposure: ["cowork", "space_builder"],
1691
1724
  constraints: {
1692
- aspectRatios: [...KLING_RATIOS],
1693
- resolutions: ["720p", "1080p"],
1725
+ aspectRatios: [...KLING_OMNI_RATIOS],
1726
+ resolutions: ["720p", "1080p", "4k"],
1694
1727
  durations: { min: 3, max: 15 },
1695
1728
  references: { images: 7, imagesWithVideo: 4 },
1696
- supports: ["generateAudio", "lastFrame"]
1729
+ supports: ["generateAudio", "lastFrame"],
1730
+ prompt: KLING_PROMPT,
1731
+ audio: "optional"
1697
1732
  },
1698
- defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
1733
+ defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: true, mode: "pro" },
1699
1734
  usage: { unit: "compute_seconds" },
1700
1735
  pricingKind: "video_per_second",
1701
1736
  display: {
1702
1737
  provider: "kuaishou",
1703
1738
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1704
- 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."
1705
- },
1706
- capabilities: {}
1739
+ 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 4K."
1740
+ }
1741
+ // end_image "Requires start_image", but no lastFrameRequiresFirstFrame: SpaceLab resolves
1742
+ // replicate rows in error mode, so the flag would refuse its end-frame-only nodes, which
1743
+ // the adapter sends as start_image.
1707
1744
  },
1708
1745
  {
1709
1746
  id: "minimax-h3",
@@ -1718,7 +1755,10 @@ var VIDEO_MODELS = [
1718
1755
  aspectRatios: [...H3_RATIOS],
1719
1756
  resolutions: ["480p", "768p", "2k", "4k"],
1720
1757
  durations: { min: 5, max: 15 },
1721
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1758
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1759
+ ratioIgnoredWith: ["firstFrame"],
1760
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1761
+ audio: "always"
1722
1762
  },
1723
1763
  defaults: {
1724
1764
  durationSeconds: 5,
@@ -1746,9 +1786,12 @@ var VIDEO_MODELS = [
1746
1786
  exposure: ["cowork", "space_builder"],
1747
1787
  constraints: {
1748
1788
  aspectRatios: [...H3_RATIOS],
1749
- resolutions: ["480p", "768p"],
1789
+ resolutions: ["480p", "768p", "1080p"],
1750
1790
  durations: { min: 5, max: 15 },
1751
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1791
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1792
+ ratioIgnoredWith: ["firstFrame"],
1793
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1794
+ audio: "always"
1752
1795
  },
1753
1796
  defaults: {
1754
1797
  durationSeconds: 5,
@@ -1761,7 +1804,7 @@ var VIDEO_MODELS = [
1761
1804
  display: {
1762
1805
  provider: "minimax",
1763
1806
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1764
- description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
1807
+ description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 1080p."
1765
1808
  },
1766
1809
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1767
1810
  },
@@ -1778,6 +1821,8 @@ var VIDEO_MODELS = [
1778
1821
  aspectRatios: [...H3_REFERENCE_RATIOS],
1779
1822
  resolutions: ["480p", "768p", "2k", "4k"],
1780
1823
  durations: { min: 5, max: 15 },
1824
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1825
+ ratioIgnoredWith: ["firstFrame"],
1781
1826
  references: {
1782
1827
  images: 9,
1783
1828
  videos: 3,
@@ -1786,7 +1831,8 @@ var VIDEO_MODELS = [
1786
1831
  audioOnly: false,
1787
1832
  videoSeconds: { min: 2, max: 15, total: 15 }
1788
1833
  },
1789
- supports: ["seed", "promptExpansion", "safetyChecker"]
1834
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1835
+ audio: "always"
1790
1836
  },
1791
1837
  defaults: {
1792
1838
  durationSeconds: 5,
@@ -1801,7 +1847,9 @@ var VIDEO_MODELS = [
1801
1847
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1802
1848
  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."
1803
1849
  },
1804
- capabilities: {}
1850
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1851
+ // references instead of the adapter silently dropping the frame.
1852
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1805
1853
  },
1806
1854
  {
1807
1855
  id: "minimax-h3-max-reference",
@@ -1814,8 +1862,10 @@ var VIDEO_MODELS = [
1814
1862
  exposure: ["cowork", "space_builder"],
1815
1863
  constraints: {
1816
1864
  aspectRatios: [...H3_REFERENCE_RATIOS],
1817
- resolutions: ["480p", "768p"],
1865
+ resolutions: ["480p", "768p", "1080p"],
1818
1866
  durations: { min: 5, max: 15 },
1867
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1868
+ ratioIgnoredWith: ["firstFrame"],
1819
1869
  references: {
1820
1870
  images: 9,
1821
1871
  videos: 3,
@@ -1824,7 +1874,8 @@ var VIDEO_MODELS = [
1824
1874
  audioOnly: false,
1825
1875
  videoSeconds: { min: 2, max: 15, total: 15 }
1826
1876
  },
1827
- supports: ["seed", "promptExpansion", "safetyChecker"]
1877
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1878
+ audio: "always"
1828
1879
  },
1829
1880
  defaults: {
1830
1881
  durationSeconds: 5,
@@ -1839,7 +1890,9 @@ var VIDEO_MODELS = [
1839
1890
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1840
1891
  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."
1841
1892
  },
1842
- capabilities: {}
1893
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1894
+ // references instead of the adapter silently dropping the frame.
1895
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1843
1896
  },
1844
1897
  {
1845
1898
  // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
@@ -1856,7 +1909,8 @@ var VIDEO_MODELS = [
1856
1909
  durations: { min: 3, max: 10 },
1857
1910
  requires: ["sourceVideo"],
1858
1911
  sourceVideoSeconds: { min: 3, max: 10.05 },
1859
- supports: []
1912
+ supports: [],
1913
+ audio: "never"
1860
1914
  },
1861
1915
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1862
1916
  usage: { ...VIDEO_USAGE },
@@ -1880,7 +1934,8 @@ var VIDEO_MODELS = [
1880
1934
  constraints: {
1881
1935
  resolutions: ["768p"],
1882
1936
  durations: [6, 10],
1883
- supports: ["lastFrame"]
1937
+ supports: ["lastFrame"],
1938
+ audio: "never"
1884
1939
  },
1885
1940
  defaults: { durationSeconds: 6, resolution: "768p" },
1886
1941
  usage: { unit: "compute_seconds" },
@@ -1903,7 +1958,8 @@ var VIDEO_MODELS = [
1903
1958
  exposure: [],
1904
1959
  constraints: {
1905
1960
  requires: ["firstFrame"],
1906
- supports: ["seed", "lastFrame"]
1961
+ supports: ["seed", "lastFrame"],
1962
+ audio: "never"
1907
1963
  },
1908
1964
  defaults: {},
1909
1965
  usage: { ...VIDEO_USAGE },
@@ -1925,7 +1981,7 @@ var MODELS = [
1925
1981
  ];
1926
1982
 
1927
1983
  // src/catalog/schema.ts
1928
- var import_zod2 = require("zod");
1984
+ var import_zod3 = require("zod");
1929
1985
 
1930
1986
  // src/catalog/collisions.ts
1931
1987
  function collisionIssues(rows) {
@@ -1972,8 +2028,61 @@ function collisionIssues(rows) {
1972
2028
  return issues;
1973
2029
  }
1974
2030
 
1975
- // src/catalog/input-spec.ts
2031
+ // src/catalog/conventions.ts
1976
2032
  var import_zod = require("zod");
2033
+ var AudioOutputSchema = import_zod.z.enum(["always", "optional", "never"]);
2034
+ var ReferenceSyntaxSchema = import_zod.z.enum(["numbered", "caption", "descriptive"]);
2035
+ var MaxCharsSchema = import_zod.z.number().int().positive();
2036
+ var PromptConventionsSchema = import_zod.z.strictObject({
2037
+ referenceSyntax: ReferenceSyntaxSchema,
2038
+ maxChars: MaxCharsSchema.optional()
2039
+ });
2040
+ var AUDIO_OUTPUTS = AudioOutputSchema.options;
2041
+ var REFERENCE_SYNTAXES = ReferenceSyntaxSchema.options;
2042
+ var ConstraintsReadView = import_zod.z.looseObject({
2043
+ audio: AudioOutputSchema.optional().catch(void 0),
2044
+ prompt: import_zod.z.looseObject({
2045
+ referenceSyntax: ReferenceSyntaxSchema.catch("numbered"),
2046
+ maxChars: MaxCharsSchema.optional().catch(void 0)
2047
+ }).optional().catch(void 0)
2048
+ });
2049
+ var DEFAULT_CONVENTIONS = { referenceSyntax: "numbered" };
2050
+ function outputAudio(row) {
2051
+ const view = ConstraintsReadView.safeParse(row.constraints);
2052
+ return view.success ? view.data.audio : void 0;
2053
+ }
2054
+ function promptConventions(row) {
2055
+ const view = ConstraintsReadView.safeParse(row.constraints);
2056
+ const prompt = view.success ? view.data.prompt : void 0;
2057
+ if (prompt === void 0) return { ...DEFAULT_CONVENTIONS };
2058
+ const result = { referenceSyntax: prompt.referenceSyntax };
2059
+ if (prompt.maxChars !== void 0) result.maxChars = prompt.maxChars;
2060
+ return result;
2061
+ }
2062
+ var RawConventionsView = import_zod.z.looseObject({
2063
+ audio: import_zod.z.unknown().optional(),
2064
+ prompt: import_zod.z.unknown().optional()
2065
+ });
2066
+ function normaliseConventions(row) {
2067
+ const view = RawConventionsView.safeParse(row.constraints);
2068
+ if (!view.success) return { row, invalidKeys: [] };
2069
+ const { audio, prompt } = view.data;
2070
+ const badAudio = audio !== void 0 && !AudioOutputSchema.safeParse(audio).success;
2071
+ const badPrompt = prompt !== void 0 && !PromptConventionsSchema.safeParse(prompt).success;
2072
+ if (!badAudio && !badPrompt) return { row, invalidKeys: [] };
2073
+ const invalidKeys = [];
2074
+ if (badAudio) invalidKeys.push("constraints.audio");
2075
+ if (badPrompt) invalidKeys.push("constraints.prompt");
2076
+ const entries = Object.entries(row.constraints).flatMap(([key, value]) => {
2077
+ if (key === "audio" && badAudio) return [];
2078
+ if (key === "prompt" && badPrompt) return [[key, promptConventions(row)]];
2079
+ return [[key, value]];
2080
+ });
2081
+ return { row: { ...row, constraints: Object.fromEntries(entries) }, invalidKeys };
2082
+ }
2083
+
2084
+ // src/catalog/input-spec.ts
2085
+ var import_zod2 = require("zod");
1977
2086
  var VIDEO_INPUT_SPEC_KEYS = [
1978
2087
  "prompt",
1979
2088
  "durationSeconds",
@@ -2012,8 +2121,8 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
2012
2121
  ...VIDEO_INPUT_SPEC_KEYS,
2013
2122
  ...AUDIO_INPUT_SPEC_KEYS
2014
2123
  ]);
2015
- var ProviderScalarSchema = import_zod.z.union([import_zod.z.string(), import_zod.z.number(), import_zod.z.boolean()]);
2016
- var FieldsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.string().min(1)).superRefine((fields, ctx) => {
2124
+ var ProviderScalarSchema = import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number(), import_zod2.z.boolean()]);
2125
+ var FieldsSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string().min(1)).superRefine((fields, ctx) => {
2017
2126
  const keys = Object.keys(fields);
2018
2127
  if (keys.length === 0) {
2019
2128
  ctx.addIssue({
@@ -2031,7 +2140,7 @@ var FieldsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.strin
2031
2140
  }
2032
2141
  }
2033
2142
  });
2034
- var ValuesSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
2143
+ var ValuesSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.record(import_zod2.z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
2035
2144
  for (const key of Object.keys(values)) {
2036
2145
  if (!ALL_KEY_SET.has(key)) {
2037
2146
  ctx.addIssue({
@@ -2041,8 +2150,8 @@ var ValuesSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.recor
2041
2150
  }
2042
2151
  }
2043
2152
  });
2044
- var StaticSchema = import_zod.z.record(import_zod.z.string(), ProviderScalarSchema);
2045
- var InputSpecSchema = import_zod.z.strictObject({
2153
+ var StaticSchema = import_zod2.z.record(import_zod2.z.string(), ProviderScalarSchema);
2154
+ var InputSpecSchema = import_zod2.z.strictObject({
2046
2155
  fields: FieldsSchema,
2047
2156
  values: ValuesSchema.optional(),
2048
2157
  static: StaticSchema.optional()
@@ -2146,16 +2255,16 @@ var ADAPTER_IDS = [
2146
2255
  "higgsfield",
2147
2256
  "xai-video"
2148
2257
  ];
2149
- var ModelTypeSchema = import_zod2.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2150
- var LifecycleSchema = import_zod2.z.enum(["active", "deprecated", "retired"]);
2151
- var SurfaceSchema = import_zod2.z.enum(["cowork", "space_builder"]);
2258
+ var ModelTypeSchema = import_zod3.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2259
+ var LifecycleSchema = import_zod3.z.enum(["active", "deprecated", "retired"]);
2260
+ var SurfaceSchema = import_zod3.z.enum(["cowork", "space_builder"]);
2152
2261
  var SURFACES2 = SurfaceSchema.options;
2153
- var ExposureSchema = import_zod2.z.preprocess(
2262
+ var ExposureSchema = import_zod3.z.preprocess(
2154
2263
  normalizeExposure,
2155
- import_zod2.z.array(SurfaceSchema)
2264
+ import_zod3.z.array(SurfaceSchema)
2156
2265
  );
2157
- var AdapterSchema = import_zod2.z.enum(ADAPTER_IDS);
2158
- var AspectRatioSchema = import_zod2.z.enum([
2266
+ var AdapterSchema = import_zod3.z.enum(ADAPTER_IDS);
2267
+ var AspectRatioSchema = import_zod3.z.enum([
2159
2268
  "1:1",
2160
2269
  "16:9",
2161
2270
  "9:16",
@@ -2170,12 +2279,12 @@ var AspectRatioSchema = import_zod2.z.enum([
2170
2279
  "97:30",
2171
2280
  "adaptive"
2172
2281
  ]);
2173
- var ImageSizeSchema = import_zod2.z.enum(["512", "1K", "2K", "4K"]);
2174
- var VideoResolutionSchema = import_zod2.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2175
- var ImageQualitySchema = import_zod2.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2176
- var OutputFormatSchema = import_zod2.z.enum(["png", "jpeg", "webp"]);
2177
- var RequiredInputSchema = import_zod2.z.enum(["firstFrame", "sourceVideo", "references"]);
2178
- var SupportedOptionSchema = import_zod2.z.enum([
2282
+ var ImageSizeSchema = import_zod3.z.enum(["512", "1K", "2K", "4K"]);
2283
+ var VideoResolutionSchema = import_zod3.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2284
+ var ImageQualitySchema = import_zod3.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2285
+ var OutputFormatSchema = import_zod3.z.enum(["png", "jpeg", "webp"]);
2286
+ var RequiredInputSchema = import_zod3.z.enum(["firstFrame", "sourceVideo", "references"]);
2287
+ var SupportedOptionSchema = import_zod3.z.enum([
2179
2288
  "seed",
2180
2289
  "quality",
2181
2290
  "negativePrompt",
@@ -2195,142 +2304,147 @@ var SupportedOptionSchema = import_zod2.z.enum([
2195
2304
  "videoExtension",
2196
2305
  "instrumental"
2197
2306
  ]);
2198
- var UsageUnitSchema = import_zod2.z.enum([
2307
+ var UsageUnitSchema = import_zod3.z.enum([
2199
2308
  "tokens",
2200
2309
  "images",
2201
2310
  "seconds",
2202
2311
  "reported_cost_usd",
2203
2312
  "compute_seconds"
2204
2313
  ]);
2205
- var PricingKindSchema = import_zod2.z.enum(["token", "image_size", "video_per_second", "flat"]);
2206
- var ProviderOptionValueSchema = import_zod2.z.lazy(
2207
- () => import_zod2.z.union([
2208
- import_zod2.z.string(),
2209
- import_zod2.z.number(),
2210
- import_zod2.z.boolean(),
2211
- import_zod2.z.array(ProviderOptionValueSchema),
2212
- import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema)
2314
+ var PricingKindSchema = import_zod3.z.enum(["token", "image_size", "video_per_second", "flat"]);
2315
+ var ProviderOptionValueSchema = import_zod3.z.lazy(
2316
+ () => import_zod3.z.union([
2317
+ import_zod3.z.string(),
2318
+ import_zod3.z.number(),
2319
+ import_zod3.z.boolean(),
2320
+ import_zod3.z.array(ProviderOptionValueSchema),
2321
+ import_zod3.z.record(import_zod3.z.string(), ProviderOptionValueSchema)
2213
2322
  ])
2214
2323
  );
2215
- var ProviderOptionsSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema));
2216
- var VideoSecondsLimitsSchema = import_zod2.z.looseObject({
2217
- min: import_zod2.z.number().optional(),
2218
- max: import_zod2.z.number().optional(),
2219
- total: import_zod2.z.number().optional(),
2220
- editMin: import_zod2.z.number().optional()
2324
+ var ProviderOptionsSchema = import_zod3.z.record(import_zod3.z.string(), import_zod3.z.record(import_zod3.z.string(), ProviderOptionValueSchema));
2325
+ var VideoSecondsLimitsSchema = import_zod3.z.looseObject({
2326
+ min: import_zod3.z.number().optional(),
2327
+ max: import_zod3.z.number().optional(),
2328
+ total: import_zod3.z.number().optional(),
2329
+ editMin: import_zod3.z.number().optional()
2221
2330
  });
2222
- var ReferenceLimitsSchema = import_zod2.z.looseObject({
2223
- images: import_zod2.z.number().optional(),
2224
- imagesWithVideo: import_zod2.z.number().optional(),
2225
- videos: import_zod2.z.number().optional(),
2226
- audios: import_zod2.z.number().optional(),
2227
- total: import_zod2.z.number().optional(),
2228
- audioOnly: import_zod2.z.boolean().optional(),
2331
+ var ReferenceLimitsSchema = import_zod3.z.looseObject({
2332
+ images: import_zod3.z.number().optional(),
2333
+ imagesWithVideo: import_zod3.z.number().optional(),
2334
+ videos: import_zod3.z.number().optional(),
2335
+ audios: import_zod3.z.number().optional(),
2336
+ total: import_zod3.z.number().optional(),
2337
+ audioOnly: import_zod3.z.boolean().optional(),
2229
2338
  videoSeconds: VideoSecondsLimitsSchema.optional()
2230
2339
  });
2231
- var ModelConstraintsSchema = import_zod2.z.looseObject({
2232
- aspectRatios: import_zod2.z.array(AspectRatioSchema).optional(),
2233
- sizes: import_zod2.z.array(ImageSizeSchema).optional(),
2234
- resolutions: import_zod2.z.array(VideoResolutionSchema).optional(),
2235
- durations: import_zod2.z.union([import_zod2.z.looseObject({ min: import_zod2.z.number(), max: import_zod2.z.number() }), import_zod2.z.array(import_zod2.z.number())]).optional(),
2236
- durationPresets: import_zod2.z.array(import_zod2.z.number()).optional(),
2237
- qualityOptions: import_zod2.z.array(import_zod2.z.string()).optional(),
2238
- exactSizes: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
2340
+ var ModelConstraintsSchema = import_zod3.z.looseObject({
2341
+ aspectRatios: import_zod3.z.array(AspectRatioSchema).optional(),
2342
+ sizes: import_zod3.z.array(ImageSizeSchema).optional(),
2343
+ resolutions: import_zod3.z.array(VideoResolutionSchema).optional(),
2344
+ durations: import_zod3.z.union([import_zod3.z.looseObject({ min: import_zod3.z.number(), max: import_zod3.z.number() }), import_zod3.z.array(import_zod3.z.number())]).optional(),
2345
+ durationPresets: import_zod3.z.array(import_zod3.z.number()).optional(),
2346
+ qualityOptions: import_zod3.z.array(import_zod3.z.string()).optional(),
2347
+ exactSizes: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string()).optional(),
2239
2348
  references: ReferenceLimitsSchema.optional(),
2240
- requires: import_zod2.z.array(RequiredInputSchema).optional(),
2241
- supports: import_zod2.z.array(SupportedOptionSchema).optional(),
2242
- ratioIgnoredWith: import_zod2.z.array(import_zod2.z.enum(["firstFrame", "sourceVideo"])).optional(),
2243
- sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: import_zod2.z.boolean().optional() }).optional(),
2244
- extension: import_zod2.z.looseObject({ segmentSeconds: import_zod2.z.number(), maxTotalSeconds: import_zod2.z.number() }).optional()
2349
+ requires: import_zod3.z.array(RequiredInputSchema).optional(),
2350
+ supports: import_zod3.z.array(SupportedOptionSchema).optional(),
2351
+ ratioIgnoredWith: import_zod3.z.array(import_zod3.z.enum(["firstFrame", "sourceVideo"])).optional(),
2352
+ sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: import_zod3.z.boolean().optional() }).optional(),
2353
+ extension: import_zod3.z.looseObject({ segmentSeconds: import_zod3.z.number(), maxTotalSeconds: import_zod3.z.number() }).optional(),
2354
+ // Loose on purpose: the read path keeps a row whose value is invalid (the accessors in
2355
+ // conventions.ts read it as "not set"); CatalogModelSchema below rejects it on write.
2356
+ audio: import_zod3.z.unknown().optional(),
2357
+ prompt: import_zod3.z.unknown().optional()
2245
2358
  });
2246
- var MediaRefSchema = import_zod2.z.union([
2247
- import_zod2.z.looseObject({
2248
- url: import_zod2.z.string(),
2249
- label: import_zod2.z.string().optional(),
2250
- durationSeconds: import_zod2.z.number().optional()
2359
+ var MediaRefSchema = import_zod3.z.union([
2360
+ import_zod3.z.looseObject({
2361
+ url: import_zod3.z.string(),
2362
+ label: import_zod3.z.string().optional(),
2363
+ durationSeconds: import_zod3.z.number().optional()
2251
2364
  }),
2252
- import_zod2.z.looseObject({
2253
- bytes: import_zod2.z.instanceof(Uint8Array),
2254
- mime: import_zod2.z.string(),
2255
- label: import_zod2.z.string().optional(),
2256
- durationSeconds: import_zod2.z.number().optional()
2365
+ import_zod3.z.looseObject({
2366
+ bytes: import_zod3.z.instanceof(Uint8Array),
2367
+ mime: import_zod3.z.string(),
2368
+ label: import_zod3.z.string().optional(),
2369
+ durationSeconds: import_zod3.z.number().optional()
2257
2370
  })
2258
2371
  ]);
2259
- var ImageSafetySettingSchema = import_zod2.z.looseObject({ category: import_zod2.z.string(), threshold: import_zod2.z.string() });
2260
- var UpscaleOptionsSchema = import_zod2.z.looseObject({
2261
- enhanceModel: import_zod2.z.string().optional(),
2262
- subjectDetection: import_zod2.z.string().optional(),
2263
- faceEnhancement: import_zod2.z.boolean().optional(),
2264
- faceEnhancementCreativity: import_zod2.z.number().optional(),
2265
- faceEnhancementStrength: import_zod2.z.number().optional()
2372
+ var ImageSafetySettingSchema = import_zod3.z.looseObject({ category: import_zod3.z.string(), threshold: import_zod3.z.string() });
2373
+ var UpscaleOptionsSchema = import_zod3.z.looseObject({
2374
+ enhanceModel: import_zod3.z.string().optional(),
2375
+ subjectDetection: import_zod3.z.string().optional(),
2376
+ faceEnhancement: import_zod3.z.boolean().optional(),
2377
+ faceEnhancementCreativity: import_zod3.z.number().optional(),
2378
+ faceEnhancementStrength: import_zod3.z.number().optional()
2266
2379
  });
2267
- var DefaultsSchema = import_zod2.z.looseObject({
2268
- references: import_zod2.z.array(MediaRefSchema).optional(),
2380
+ var DefaultsSchema = import_zod3.z.looseObject({
2381
+ references: import_zod3.z.array(MediaRefSchema).optional(),
2269
2382
  aspectRatio: AspectRatioSchema.optional(),
2270
2383
  size: ImageSizeSchema.optional(),
2271
- exactSize: import_zod2.z.string().optional(),
2384
+ exactSize: import_zod3.z.string().optional(),
2272
2385
  quality: ImageQualitySchema.optional(),
2273
- seed: import_zod2.z.number().optional(),
2274
- count: import_zod2.z.number().optional(),
2386
+ seed: import_zod3.z.number().optional(),
2387
+ count: import_zod3.z.number().optional(),
2275
2388
  outputFormat: OutputFormatSchema.optional(),
2276
- scaleFactor: import_zod2.z.number().optional(),
2277
- safetySettings: import_zod2.z.array(ImageSafetySettingSchema).optional(),
2278
- temperature: import_zod2.z.number().optional(),
2389
+ scaleFactor: import_zod3.z.number().optional(),
2390
+ safetySettings: import_zod3.z.array(ImageSafetySettingSchema).optional(),
2391
+ temperature: import_zod3.z.number().optional(),
2279
2392
  upscale: UpscaleOptionsSchema.optional(),
2280
2393
  firstFrame: MediaRefSchema.optional(),
2281
2394
  lastFrame: MediaRefSchema.optional(),
2282
2395
  sourceVideo: MediaRefSchema.optional(),
2283
- referenceImages: import_zod2.z.array(MediaRefSchema).optional(),
2284
- referenceVideos: import_zod2.z.array(MediaRefSchema).optional(),
2285
- referenceAudios: import_zod2.z.array(MediaRefSchema).optional(),
2396
+ referenceImages: import_zod3.z.array(MediaRefSchema).optional(),
2397
+ referenceVideos: import_zod3.z.array(MediaRefSchema).optional(),
2398
+ referenceAudios: import_zod3.z.array(MediaRefSchema).optional(),
2286
2399
  resolution: VideoResolutionSchema.optional(),
2287
- durationSeconds: import_zod2.z.number().optional(),
2288
- generateAudio: import_zod2.z.boolean().optional(),
2289
- negativePrompt: import_zod2.z.string().optional(),
2290
- cfgScale: import_zod2.z.number().optional(),
2291
- promptExpansion: import_zod2.z.enum(["fast", "balanced", "quality"]).optional(),
2292
- watermark: import_zod2.z.boolean().optional(),
2293
- safetyChecker: import_zod2.z.boolean().optional(),
2294
- taskType: import_zod2.z.enum(["reference", "edit", "extend"]).optional(),
2295
- mode: import_zod2.z.enum(["standard", "pro"]).optional(),
2296
- instrumental: import_zod2.z.boolean().optional()
2400
+ durationSeconds: import_zod3.z.number().optional(),
2401
+ generateAudio: import_zod3.z.boolean().optional(),
2402
+ negativePrompt: import_zod3.z.string().optional(),
2403
+ cfgScale: import_zod3.z.number().optional(),
2404
+ promptExpansion: import_zod3.z.enum(["fast", "balanced", "quality"]).optional(),
2405
+ watermark: import_zod3.z.boolean().optional(),
2406
+ safetyChecker: import_zod3.z.boolean().optional(),
2407
+ taskType: import_zod3.z.enum(["reference", "edit", "extend"]).optional(),
2408
+ mode: import_zod3.z.enum(["standard", "pro"]).optional(),
2409
+ instrumental: import_zod3.z.boolean().optional()
2297
2410
  });
2298
- var CatalogDisplaySchema = import_zod2.z.looseObject({
2299
- provider: import_zod2.z.string(),
2300
- description: import_zod2.z.string(),
2301
- logo: import_zod2.z.string().optional(),
2302
- costTier: import_zod2.z.union([import_zod2.z.literal(1), import_zod2.z.literal(2), import_zod2.z.literal(3)]).optional(),
2303
- recommended: import_zod2.z.boolean().optional(),
2304
- sortOrder: import_zod2.z.number().optional(),
2305
- chat: import_zod2.z.looseObject({
2411
+ var CatalogDisplaySchema = import_zod3.z.looseObject({
2412
+ provider: import_zod3.z.string(),
2413
+ description: import_zod3.z.string(),
2414
+ logo: import_zod3.z.string().optional(),
2415
+ costTier: import_zod3.z.union([import_zod3.z.literal(1), import_zod3.z.literal(2), import_zod3.z.literal(3)]).optional(),
2416
+ recommended: import_zod3.z.boolean().optional(),
2417
+ sortOrder: import_zod3.z.number().optional(),
2418
+ chat: import_zod3.z.looseObject({
2306
2419
  providerOptions: ProviderOptionsSchema.optional(),
2307
- temperature: import_zod2.z.number().optional()
2420
+ temperature: import_zod3.z.number().optional()
2308
2421
  }).optional()
2309
2422
  });
2310
- var CatalogCapabilitiesSchema = import_zod2.z.looseObject({
2311
- acceptsSourceVideo: import_zod2.z.boolean().optional(),
2312
- framesExcludeReferences: import_zod2.z.boolean().optional(),
2313
- reasoning: import_zod2.z.boolean().optional(),
2314
- vision: import_zod2.z.boolean().optional(),
2315
- contextWindow: import_zod2.z.number().optional()
2423
+ var CatalogCapabilitiesSchema = import_zod3.z.looseObject({
2424
+ acceptsSourceVideo: import_zod3.z.boolean().optional(),
2425
+ framesExcludeReferences: import_zod3.z.boolean().optional(),
2426
+ lastFrameRequiresFirstFrame: import_zod3.z.boolean().optional(),
2427
+ reasoning: import_zod3.z.boolean().optional(),
2428
+ vision: import_zod3.z.boolean().optional(),
2429
+ contextWindow: import_zod3.z.number().optional()
2316
2430
  });
2317
- var CatalogModelSchemaBase = import_zod2.z.looseObject({
2318
- id: import_zod2.z.string().min(1),
2319
- aliases: import_zod2.z.array(import_zod2.z.string()).default([]),
2320
- label: import_zod2.z.string().min(1),
2431
+ var CatalogModelSchemaBase = import_zod3.z.looseObject({
2432
+ id: import_zod3.z.string().min(1),
2433
+ aliases: import_zod3.z.array(import_zod3.z.string()).default([]),
2434
+ label: import_zod3.z.string().min(1),
2321
2435
  type: ModelTypeSchema,
2322
2436
  adapter: AdapterSchema,
2323
- providerModelId: import_zod2.z.string().min(1),
2437
+ providerModelId: import_zod3.z.string().min(1),
2324
2438
  lifecycle: LifecycleSchema,
2325
- replacedBy: import_zod2.z.string().optional(),
2439
+ replacedBy: import_zod3.z.string().optional(),
2326
2440
  exposure: ExposureSchema,
2327
2441
  constraints: ModelConstraintsSchema,
2328
2442
  defaults: DefaultsSchema,
2329
2443
  providerOptions: ProviderOptionsSchema.optional(),
2330
- usage: import_zod2.z.looseObject({
2444
+ usage: import_zod3.z.looseObject({
2331
2445
  unit: UsageUnitSchema,
2332
- slug: import_zod2.z.string().optional(),
2333
- providerLabel: import_zod2.z.string().optional()
2446
+ slug: import_zod3.z.string().optional(),
2447
+ providerLabel: import_zod3.z.string().optional()
2334
2448
  }),
2335
2449
  pricingKind: PricingKindSchema,
2336
2450
  display: CatalogDisplaySchema.optional(),
@@ -2381,9 +2495,30 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2381
2495
  }
2382
2496
  }
2383
2497
  }
2498
+ const audio = row.constraints.audio;
2499
+ if (audio !== void 0 && !AudioOutputSchema.safeParse(audio).success) {
2500
+ ctx.addIssue({
2501
+ code: "custom",
2502
+ path: ["constraints", "audio"],
2503
+ message: 'audio must be "always", "optional" or "never"'
2504
+ });
2505
+ }
2506
+ const prompt = row.constraints.prompt;
2507
+ if (prompt !== void 0) {
2508
+ const parsed = PromptConventionsSchema.safeParse(prompt);
2509
+ if (!parsed.success) {
2510
+ for (const issue of parsed.error.issues) {
2511
+ ctx.addIssue({
2512
+ code: "custom",
2513
+ path: ["constraints", "prompt", ...issue.path.map(String)],
2514
+ message: issue.message
2515
+ });
2516
+ }
2517
+ }
2518
+ }
2384
2519
  }
2385
2520
  );
2386
- var CatalogSchema = import_zod2.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2521
+ var CatalogSchema = import_zod3.z.array(CatalogModelSchemaBase.transform((row) => normaliseConventions(row).row)).superRefine((rows, ctx) => {
2387
2522
  for (const issue of collisionIssues(rows)) {
2388
2523
  ctx.addIssue({
2389
2524
  code: "custom",
@@ -2406,42 +2541,42 @@ var liveState = store[KEY] ??= {
2406
2541
  var liveCatalog = liveState.catalog;
2407
2542
 
2408
2543
  // src/json.ts
2409
- var import_zod3 = require("zod");
2410
- var JsonValueSchema = import_zod3.z.lazy(
2411
- () => import_zod3.z.union([
2412
- import_zod3.z.string(),
2413
- import_zod3.z.number(),
2414
- import_zod3.z.boolean(),
2415
- import_zod3.z.null(),
2416
- import_zod3.z.array(JsonValueSchema),
2417
- import_zod3.z.record(import_zod3.z.string(), JsonValueSchema)
2544
+ var import_zod4 = require("zod");
2545
+ var JsonValueSchema = import_zod4.z.lazy(
2546
+ () => import_zod4.z.union([
2547
+ import_zod4.z.string(),
2548
+ import_zod4.z.number(),
2549
+ import_zod4.z.boolean(),
2550
+ import_zod4.z.null(),
2551
+ import_zod4.z.array(JsonValueSchema),
2552
+ import_zod4.z.record(import_zod4.z.string(), JsonValueSchema)
2418
2553
  ])
2419
2554
  );
2420
- var JsonObjectSchema = import_zod3.z.record(import_zod3.z.string(), JsonValueSchema);
2421
- var thrownErrorSchema = import_zod3.z.object({
2422
- message: import_zod3.z.string().optional(),
2423
- status: import_zod3.z.number().optional(),
2424
- statusCode: import_zod3.z.number().optional(),
2425
- responseBody: import_zod3.z.string().optional()
2555
+ var JsonObjectSchema = import_zod4.z.record(import_zod4.z.string(), JsonValueSchema);
2556
+ var thrownErrorSchema = import_zod4.z.object({
2557
+ message: import_zod4.z.string().optional(),
2558
+ status: import_zod4.z.number().optional(),
2559
+ statusCode: import_zod4.z.number().optional(),
2560
+ responseBody: import_zod4.z.string().optional()
2426
2561
  });
2427
2562
 
2428
2563
  // src/catalog/load.ts
2429
- var import_zod4 = require("zod");
2564
+ var import_zod5 = require("zod");
2430
2565
  function rowCount() {
2431
2566
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2432
2567
  }
2433
2568
  function authHeaders(auth) {
2434
2569
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2435
2570
  }
2436
- var EnvelopeSchema = import_zod4.z.object({
2437
- rows: import_zod4.z.array(JsonValueSchema),
2438
- revision: import_zod4.z.string().optional()
2571
+ var EnvelopeSchema = import_zod5.z.object({
2572
+ rows: import_zod5.z.array(JsonValueSchema),
2573
+ revision: import_zod5.z.string().optional()
2439
2574
  });
2440
2575
  function dropReason(path, message) {
2441
2576
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
2442
2577
  }
2443
2578
  function rowId(raw) {
2444
- const parsed = import_zod4.z.object({ id: import_zod4.z.string().min(1) }).loose().safeParse(raw);
2579
+ const parsed = import_zod5.z.object({ id: import_zod5.z.string().min(1) }).loose().safeParse(raw);
2445
2580
  if (!parsed.success) return "?";
2446
2581
  return parsed.data.id;
2447
2582
  }
@@ -2469,7 +2604,13 @@ function quarantine(rawRows, logger) {
2469
2604
  );
2470
2605
  }
2471
2606
  }
2472
- valid.push(row);
2607
+ const normalised = normaliseConventions(row);
2608
+ if (normalised.invalidKeys.length > 0) {
2609
+ logger.warn(
2610
+ `[modelkit] catalog row ${row.id} has an invalid ${normalised.invalidKeys.join(", ")}; read as not set`
2611
+ );
2612
+ }
2613
+ valid.push(normalised.row);
2473
2614
  }
2474
2615
  let kept = valid;
2475
2616
  for (; ; ) {
@@ -2864,6 +3005,24 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
2864
3005
  });
2865
3006
  delete merged.sourceVideo;
2866
3007
  }
3008
+ if (merged.lastFrame !== void 0 && merged.firstFrame === void 0 && model.capabilities?.lastFrameRequiresFirstFrame) {
3009
+ if (onUnsupported === "error") {
3010
+ throw new ModelKitError({
3011
+ code: "missing_input",
3012
+ message: `${model.id} takes an end frame only together with a start frame`,
3013
+ model: model.id,
3014
+ retryable: false
3015
+ });
3016
+ }
3017
+ warnings.push({
3018
+ code: "option_ignored",
3019
+ field: "lastFrame",
3020
+ to: "firstFrame",
3021
+ message: `end frame used as start frame: ${model.id} needs a start frame with an end frame`
3022
+ });
3023
+ merged.firstFrame = merged.lastFrame;
3024
+ delete merged.lastFrame;
3025
+ }
2867
3026
  const hasFrames = merged.firstFrame !== void 0 || merged.lastFrame !== void 0;
2868
3027
  const hasRefs = compact(merged.referenceImages).length + compact(merged.referenceVideos).length + compact(merged.referenceAudios).length > 0;
2869
3028
  if (hasFrames && hasRefs && model.capabilities?.framesExcludeReferences) {