@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.js CHANGED
@@ -162,7 +162,9 @@ function geminiImage(id, label, aliases, sizes, display, exposure, references) {
162
162
  const constraints = {
163
163
  aspectRatios: [...GEMINI_RATIOS],
164
164
  sizes,
165
- supports: ["safetySettings", "temperature"]
165
+ supports: ["safetySettings", "temperature"],
166
+ // google-image sends MediaRef.label as a text part beside each reference.
167
+ prompt: { referenceSyntax: "caption" }
166
168
  };
167
169
  if (references !== void 0) constraints.references = references;
168
170
  const model = {
@@ -449,6 +451,7 @@ var IMAGE_MODELS = [
449
451
  constraints: {
450
452
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
451
453
  sizes: ["1K"],
454
+ references: { images: 8 },
452
455
  // flux-2-pro's job type always returns image/png; only the seed is forwarded.
453
456
  supports: ["seed"]
454
457
  },
@@ -1244,12 +1247,14 @@ var TEXT_MODELS = [
1244
1247
  var VIDEO_USAGE = { unit: "seconds" };
1245
1248
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
1246
1249
  var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
1250
+ var KLING_OMNI_RATIOS = ["16:9", "9:16", "1:1"];
1247
1251
  var OMNI_RATIOS = ["16:9", "9:16"];
1248
1252
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1249
1253
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1250
1254
  var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1251
1255
  var NEGATIVE_PROMPT = "blur, distort, and low quality";
1252
1256
  var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1257
+ var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
1253
1258
  var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
1254
1259
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1255
1260
  var VIDEO_MODELS = [
@@ -1270,9 +1275,14 @@ var VIDEO_MODELS = [
1270
1275
  constraints: {
1271
1276
  aspectRatios: [...OMNI_RATIOS],
1272
1277
  resolutions: ["720p", "1080p", "4k"],
1278
+ // Veo also takes 4 and 6, but must be 8 at 1080p/4k or with reference images;
1279
+ // [8] until the kit has a rule that forces it there (CHANGELOG 0.2.21).
1273
1280
  durations: [8],
1274
1281
  references: { images: 3 },
1275
- supports: ["lastFrame", "seed"]
1282
+ supports: ["lastFrame", "seed"],
1283
+ // 1,024 text tokens; 3,000 characters assumes ~2.9 characters per token.
1284
+ prompt: { referenceSyntax: "numbered", maxChars: 3e3 },
1285
+ audio: "always"
1276
1286
  },
1277
1287
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1278
1288
  usage: { ...VIDEO_USAGE, slug: "veo" },
@@ -1282,7 +1292,8 @@ var VIDEO_MODELS = [
1282
1292
  description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
1283
1293
  logo: GOOGLE_LOGO2
1284
1294
  },
1285
- capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1295
+ // Veo's lastFrame "must be used in combination with the image parameter".
1296
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES, lastFrameRequiresFirstFrame: true }
1286
1297
  },
1287
1298
  {
1288
1299
  id: "veo-3.1-fast",
@@ -1302,7 +1313,8 @@ var VIDEO_MODELS = [
1302
1313
  resolutions: ["720p", "1080p", "4k"],
1303
1314
  durations: [4, 6, 8],
1304
1315
  references: { images: 3 },
1305
- supports: ["lastFrame", "seed"]
1316
+ supports: ["lastFrame", "seed"],
1317
+ audio: "always"
1306
1318
  },
1307
1319
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1308
1320
  usage: { ...VIDEO_USAGE },
@@ -1330,7 +1342,8 @@ var VIDEO_MODELS = [
1330
1342
  aspectRatios: [...OMNI_RATIOS],
1331
1343
  resolutions: ["720p", "1080p"],
1332
1344
  durations: [4, 6, 8],
1333
- supports: ["lastFrame", "seed"]
1345
+ supports: ["lastFrame", "seed"],
1346
+ audio: "always"
1334
1347
  },
1335
1348
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1336
1349
  usage: { ...VIDEO_USAGE },
@@ -1364,7 +1377,10 @@ var VIDEO_MODELS = [
1364
1377
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1365
1378
  references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1366
1379
  sourceVideoSeconds: { max: 10 },
1367
- supports: []
1380
+ supports: [],
1381
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1382
+ prompt: { referenceSyntax: "caption" },
1383
+ audio: "always"
1368
1384
  },
1369
1385
  defaults: {},
1370
1386
  usage: { ...VIDEO_USAGE, slug: "gemini_omni" },
@@ -1397,8 +1413,12 @@ var VIDEO_MODELS = [
1397
1413
  // extension can upload a <= 10 s source with task "extend"; later ones
1398
1414
  // chain by `previousInteractionId` (the API rejects the id together
1399
1415
  // with a video task, so those calls carry the prompt alone).
1400
- supports: ["videoExtension"],
1401
- extension: { segmentSeconds: 10, maxTotalSeconds: 40 }
1416
+ // First-to-last-frame interpolation: `<LAST_FRAME>` goes with `<FIRST_FRAME>`.
1417
+ supports: ["videoExtension", "lastFrame"],
1418
+ extension: { segmentSeconds: 10, maxTotalSeconds: 40 },
1419
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1420
+ prompt: { referenceSyntax: "caption" },
1421
+ audio: "always"
1402
1422
  },
1403
1423
  defaults: {},
1404
1424
  usage: { ...VIDEO_USAGE },
@@ -1408,7 +1428,7 @@ var VIDEO_MODELS = [
1408
1428
  logo: GOOGLE_LOGO2,
1409
1429
  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."
1410
1430
  },
1411
- capabilities: { acceptsSourceVideo: true }
1431
+ capabilities: { acceptsSourceVideo: true, lastFrameRequiresFirstFrame: true }
1412
1432
  },
1413
1433
  {
1414
1434
  // vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
@@ -1434,7 +1454,9 @@ var VIDEO_MODELS = [
1434
1454
  },
1435
1455
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1436
1456
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1437
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1457
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1458
+ supports: ["generateAudio", "lastFrame", "watermark"],
1459
+ audio: "optional"
1438
1460
  },
1439
1461
  defaults: {
1440
1462
  durationSeconds: 5,
@@ -1473,7 +1495,9 @@ var VIDEO_MODELS = [
1473
1495
  },
1474
1496
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1475
1497
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1476
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1498
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1499
+ supports: ["generateAudio", "lastFrame", "watermark"],
1500
+ audio: "optional"
1477
1501
  },
1478
1502
  defaults: {
1479
1503
  durationSeconds: 5,
@@ -1491,7 +1515,6 @@ var VIDEO_MODELS = [
1491
1515
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1492
1516
  },
1493
1517
  {
1494
- // generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
1495
1518
  // omni_reference_task_type edit/extend: adaptive ratio, edit sends duration -1.
1496
1519
  id: "seedance-2.5",
1497
1520
  aliases: ["seedance-2-5", "dreamina-seedance-2-5-260628"],
@@ -1513,13 +1536,15 @@ var VIDEO_MODELS = [
1513
1536
  },
1514
1537
  sourceVideoSeconds: { min: 2, max: 30, editMin: 4, inReferenceTotal: true },
1515
1538
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1516
- supports: ["generateAudio", "seed", "lastFrame", "watermark", "taskType"]
1539
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1540
+ supports: ["generateAudio", "lastFrame", "watermark", "taskType"],
1541
+ audio: "optional"
1517
1542
  },
1518
1543
  defaults: {
1519
1544
  durationSeconds: 5,
1520
1545
  resolution: "720p",
1521
1546
  aspectRatio: "16:9",
1522
- generateAudio: false
1547
+ generateAudio: true
1523
1548
  },
1524
1549
  usage: { ...VIDEO_USAGE },
1525
1550
  pricingKind: "video_per_second",
@@ -1531,7 +1556,6 @@ var VIDEO_MODELS = [
1531
1556
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1532
1557
  },
1533
1558
  {
1534
- // Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
1535
1559
  id: "grok-imagine",
1536
1560
  aliases: ["grok-imagine-video", "grokImagine"],
1537
1561
  label: "Grok Imagine",
@@ -1545,8 +1569,11 @@ var VIDEO_MODELS = [
1545
1569
  resolutions: ["480p", "720p"],
1546
1570
  durations: { min: 1, max: 15 },
1547
1571
  durationPresets: [4, 6, 8, 10],
1548
- references: { images: 5 },
1549
- supports: []
1572
+ // xAI: "A maximum of 7 reference images can be provided per request."
1573
+ references: { images: 7 },
1574
+ supports: [],
1575
+ // xAI can switch sound off (generate_audio); xai-video.ts never sends it.
1576
+ audio: "always"
1550
1577
  },
1551
1578
  // No resolution default: xAI picks its own unless the caller asks.
1552
1579
  defaults: { durationSeconds: 8, aspectRatio: "16:9" },
@@ -1568,15 +1595,16 @@ var VIDEO_MODELS = [
1568
1595
  providerModelId: "kling-video/v2.5-turbo/pro/image-to-video",
1569
1596
  lifecycle: "active",
1570
1597
  exposure: ["cowork", "space_builder"],
1598
+ // The endpoint has no aspect_ratio or last_image_url: the start image sets the framing.
1571
1599
  constraints: {
1572
- aspectRatios: [...KLING_RATIOS],
1573
1600
  durations: [5, 10],
1574
1601
  requires: ["firstFrame"],
1575
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1602
+ supports: ["cfgScale", "negativePrompt"],
1603
+ prompt: KLING_PROMPT,
1604
+ audio: "never"
1576
1605
  },
1577
1606
  defaults: {
1578
1607
  durationSeconds: 5,
1579
- aspectRatio: "16:9",
1580
1608
  cfgScale: 0.5,
1581
1609
  negativePrompt: NEGATIVE_PROMPT
1582
1610
  },
@@ -1585,7 +1613,7 @@ var VIDEO_MODELS = [
1585
1613
  display: {
1586
1614
  provider: "kuaishou",
1587
1615
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1588
- 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."
1616
+ description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt, 5- or 10-second clips."
1589
1617
  },
1590
1618
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1591
1619
  },
@@ -1599,17 +1627,18 @@ var VIDEO_MODELS = [
1599
1627
  providerModelId: "kling-video/v3.0/pro/image-to-video",
1600
1628
  lifecycle: "active",
1601
1629
  exposure: ["cowork", "space_builder"],
1630
+ // The endpoint has no aspect_ratio or negative_prompt; sound is "on"/"off" (default on).
1602
1631
  constraints: {
1603
- aspectRatios: [...KLING_RATIOS],
1604
1632
  durations: { min: 3, max: 15 },
1605
1633
  requires: ["firstFrame"],
1606
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1634
+ supports: ["cfgScale", "lastFrame", "generateAudio"],
1635
+ prompt: KLING_PROMPT,
1636
+ audio: "optional"
1607
1637
  },
1608
1638
  defaults: {
1609
1639
  durationSeconds: 5,
1610
- aspectRatio: "16:9",
1611
1640
  cfgScale: 0.5,
1612
- negativePrompt: NEGATIVE_PROMPT
1641
+ generateAudio: true
1613
1642
  },
1614
1643
  usage: { ...VIDEO_USAGE },
1615
1644
  pricingKind: "video_per_second",
@@ -1621,7 +1650,7 @@ var VIDEO_MODELS = [
1621
1650
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1622
1651
  },
1623
1652
  {
1624
- // mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
1653
+ // mode standard/pro/4k selects 720p/1080p/4K; the endpoint takes no separate resolution.
1625
1654
  // Replicate: "Max 7 [images] without video, 4 with video"; 4K does not support
1626
1655
  // reference_video. No `videos` limit yet: the adapter sends no reference video,
1627
1656
  // so `imagesWithVideo` stays dormant until one is wired through.
@@ -1634,21 +1663,25 @@ var VIDEO_MODELS = [
1634
1663
  lifecycle: "active",
1635
1664
  exposure: ["cowork", "space_builder"],
1636
1665
  constraints: {
1637
- aspectRatios: [...KLING_RATIOS],
1638
- resolutions: ["720p", "1080p"],
1666
+ aspectRatios: [...KLING_OMNI_RATIOS],
1667
+ resolutions: ["720p", "1080p", "4k"],
1639
1668
  durations: { min: 3, max: 15 },
1640
1669
  references: { images: 7, imagesWithVideo: 4 },
1641
- supports: ["generateAudio", "lastFrame"]
1670
+ supports: ["generateAudio", "lastFrame"],
1671
+ prompt: KLING_PROMPT,
1672
+ audio: "optional"
1642
1673
  },
1643
- defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
1674
+ defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: true, mode: "pro" },
1644
1675
  usage: { unit: "compute_seconds" },
1645
1676
  pricingKind: "video_per_second",
1646
1677
  display: {
1647
1678
  provider: "kuaishou",
1648
1679
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1649
- 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."
1650
- },
1651
- capabilities: {}
1680
+ 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."
1681
+ }
1682
+ // end_image "Requires start_image", but no lastFrameRequiresFirstFrame: SpaceLab resolves
1683
+ // replicate rows in error mode, so the flag would refuse its end-frame-only nodes, which
1684
+ // the adapter sends as start_image.
1652
1685
  },
1653
1686
  {
1654
1687
  id: "minimax-h3",
@@ -1663,7 +1696,10 @@ var VIDEO_MODELS = [
1663
1696
  aspectRatios: [...H3_RATIOS],
1664
1697
  resolutions: ["480p", "768p", "2k", "4k"],
1665
1698
  durations: { min: 5, max: 15 },
1666
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1699
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1700
+ ratioIgnoredWith: ["firstFrame"],
1701
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1702
+ audio: "always"
1667
1703
  },
1668
1704
  defaults: {
1669
1705
  durationSeconds: 5,
@@ -1691,9 +1727,12 @@ var VIDEO_MODELS = [
1691
1727
  exposure: ["cowork", "space_builder"],
1692
1728
  constraints: {
1693
1729
  aspectRatios: [...H3_RATIOS],
1694
- resolutions: ["480p", "768p"],
1730
+ resolutions: ["480p", "768p", "1080p"],
1695
1731
  durations: { min: 5, max: 15 },
1696
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1732
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1733
+ ratioIgnoredWith: ["firstFrame"],
1734
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1735
+ audio: "always"
1697
1736
  },
1698
1737
  defaults: {
1699
1738
  durationSeconds: 5,
@@ -1706,7 +1745,7 @@ var VIDEO_MODELS = [
1706
1745
  display: {
1707
1746
  provider: "minimax",
1708
1747
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1709
- description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
1748
+ description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 1080p."
1710
1749
  },
1711
1750
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1712
1751
  },
@@ -1723,6 +1762,8 @@ var VIDEO_MODELS = [
1723
1762
  aspectRatios: [...H3_REFERENCE_RATIOS],
1724
1763
  resolutions: ["480p", "768p", "2k", "4k"],
1725
1764
  durations: { min: 5, max: 15 },
1765
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1766
+ ratioIgnoredWith: ["firstFrame"],
1726
1767
  references: {
1727
1768
  images: 9,
1728
1769
  videos: 3,
@@ -1731,7 +1772,8 @@ var VIDEO_MODELS = [
1731
1772
  audioOnly: false,
1732
1773
  videoSeconds: { min: 2, max: 15, total: 15 }
1733
1774
  },
1734
- supports: ["seed", "promptExpansion", "safetyChecker"]
1775
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1776
+ audio: "always"
1735
1777
  },
1736
1778
  defaults: {
1737
1779
  durationSeconds: 5,
@@ -1746,7 +1788,9 @@ var VIDEO_MODELS = [
1746
1788
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1747
1789
  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."
1748
1790
  },
1749
- capabilities: {}
1791
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1792
+ // references instead of the adapter silently dropping the frame.
1793
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1750
1794
  },
1751
1795
  {
1752
1796
  id: "minimax-h3-max-reference",
@@ -1759,8 +1803,10 @@ var VIDEO_MODELS = [
1759
1803
  exposure: ["cowork", "space_builder"],
1760
1804
  constraints: {
1761
1805
  aspectRatios: [...H3_REFERENCE_RATIOS],
1762
- resolutions: ["480p", "768p"],
1806
+ resolutions: ["480p", "768p", "1080p"],
1763
1807
  durations: { min: 5, max: 15 },
1808
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1809
+ ratioIgnoredWith: ["firstFrame"],
1764
1810
  references: {
1765
1811
  images: 9,
1766
1812
  videos: 3,
@@ -1769,7 +1815,8 @@ var VIDEO_MODELS = [
1769
1815
  audioOnly: false,
1770
1816
  videoSeconds: { min: 2, max: 15, total: 15 }
1771
1817
  },
1772
- supports: ["seed", "promptExpansion", "safetyChecker"]
1818
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1819
+ audio: "always"
1773
1820
  },
1774
1821
  defaults: {
1775
1822
  durationSeconds: 5,
@@ -1784,7 +1831,9 @@ var VIDEO_MODELS = [
1784
1831
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1785
1832
  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."
1786
1833
  },
1787
- capabilities: {}
1834
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1835
+ // references instead of the adapter silently dropping the frame.
1836
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1788
1837
  },
1789
1838
  {
1790
1839
  // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
@@ -1801,7 +1850,8 @@ var VIDEO_MODELS = [
1801
1850
  durations: { min: 3, max: 10 },
1802
1851
  requires: ["sourceVideo"],
1803
1852
  sourceVideoSeconds: { min: 3, max: 10.05 },
1804
- supports: []
1853
+ supports: [],
1854
+ audio: "never"
1805
1855
  },
1806
1856
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1807
1857
  usage: { ...VIDEO_USAGE },
@@ -1825,7 +1875,8 @@ var VIDEO_MODELS = [
1825
1875
  constraints: {
1826
1876
  resolutions: ["768p"],
1827
1877
  durations: [6, 10],
1828
- supports: ["lastFrame"]
1878
+ supports: ["lastFrame"],
1879
+ audio: "never"
1829
1880
  },
1830
1881
  defaults: { durationSeconds: 6, resolution: "768p" },
1831
1882
  usage: { unit: "compute_seconds" },
@@ -1848,7 +1899,8 @@ var VIDEO_MODELS = [
1848
1899
  exposure: [],
1849
1900
  constraints: {
1850
1901
  requires: ["firstFrame"],
1851
- supports: ["seed", "lastFrame"]
1902
+ supports: ["seed", "lastFrame"],
1903
+ audio: "never"
1852
1904
  },
1853
1905
  defaults: {},
1854
1906
  usage: { ...VIDEO_USAGE },
@@ -1870,7 +1922,7 @@ var MODELS = [
1870
1922
  ];
1871
1923
 
1872
1924
  // src/catalog/schema.ts
1873
- import { z as z2 } from "zod";
1925
+ import { z as z3 } from "zod";
1874
1926
 
1875
1927
  // src/catalog/collisions.ts
1876
1928
  function collisionIssues(rows) {
@@ -1917,8 +1969,61 @@ function collisionIssues(rows) {
1917
1969
  return issues;
1918
1970
  }
1919
1971
 
1920
- // src/catalog/input-spec.ts
1972
+ // src/catalog/conventions.ts
1921
1973
  import { z } from "zod";
1974
+ var AudioOutputSchema = z.enum(["always", "optional", "never"]);
1975
+ var ReferenceSyntaxSchema = z.enum(["numbered", "caption", "descriptive"]);
1976
+ var MaxCharsSchema = z.number().int().positive();
1977
+ var PromptConventionsSchema = z.strictObject({
1978
+ referenceSyntax: ReferenceSyntaxSchema,
1979
+ maxChars: MaxCharsSchema.optional()
1980
+ });
1981
+ var AUDIO_OUTPUTS = AudioOutputSchema.options;
1982
+ var REFERENCE_SYNTAXES = ReferenceSyntaxSchema.options;
1983
+ var ConstraintsReadView = z.looseObject({
1984
+ audio: AudioOutputSchema.optional().catch(void 0),
1985
+ prompt: z.looseObject({
1986
+ referenceSyntax: ReferenceSyntaxSchema.catch("numbered"),
1987
+ maxChars: MaxCharsSchema.optional().catch(void 0)
1988
+ }).optional().catch(void 0)
1989
+ });
1990
+ var DEFAULT_CONVENTIONS = { referenceSyntax: "numbered" };
1991
+ function outputAudio(row) {
1992
+ const view = ConstraintsReadView.safeParse(row.constraints);
1993
+ return view.success ? view.data.audio : void 0;
1994
+ }
1995
+ function promptConventions(row) {
1996
+ const view = ConstraintsReadView.safeParse(row.constraints);
1997
+ const prompt = view.success ? view.data.prompt : void 0;
1998
+ if (prompt === void 0) return { ...DEFAULT_CONVENTIONS };
1999
+ const result = { referenceSyntax: prompt.referenceSyntax };
2000
+ if (prompt.maxChars !== void 0) result.maxChars = prompt.maxChars;
2001
+ return result;
2002
+ }
2003
+ var RawConventionsView = z.looseObject({
2004
+ audio: z.unknown().optional(),
2005
+ prompt: z.unknown().optional()
2006
+ });
2007
+ function normaliseConventions(row) {
2008
+ const view = RawConventionsView.safeParse(row.constraints);
2009
+ if (!view.success) return { row, invalidKeys: [] };
2010
+ const { audio, prompt } = view.data;
2011
+ const badAudio = audio !== void 0 && !AudioOutputSchema.safeParse(audio).success;
2012
+ const badPrompt = prompt !== void 0 && !PromptConventionsSchema.safeParse(prompt).success;
2013
+ if (!badAudio && !badPrompt) return { row, invalidKeys: [] };
2014
+ const invalidKeys = [];
2015
+ if (badAudio) invalidKeys.push("constraints.audio");
2016
+ if (badPrompt) invalidKeys.push("constraints.prompt");
2017
+ const entries = Object.entries(row.constraints).flatMap(([key, value]) => {
2018
+ if (key === "audio" && badAudio) return [];
2019
+ if (key === "prompt" && badPrompt) return [[key, promptConventions(row)]];
2020
+ return [[key, value]];
2021
+ });
2022
+ return { row: { ...row, constraints: Object.fromEntries(entries) }, invalidKeys };
2023
+ }
2024
+
2025
+ // src/catalog/input-spec.ts
2026
+ import { z as z2 } from "zod";
1922
2027
  var VIDEO_INPUT_SPEC_KEYS = [
1923
2028
  "prompt",
1924
2029
  "durationSeconds",
@@ -1957,8 +2062,8 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
1957
2062
  ...VIDEO_INPUT_SPEC_KEYS,
1958
2063
  ...AUDIO_INPUT_SPEC_KEYS
1959
2064
  ]);
1960
- var ProviderScalarSchema = z.union([z.string(), z.number(), z.boolean()]);
1961
- var FieldsSchema = z.record(z.string(), z.string().min(1)).superRefine((fields, ctx) => {
2065
+ var ProviderScalarSchema = z2.union([z2.string(), z2.number(), z2.boolean()]);
2066
+ var FieldsSchema = z2.record(z2.string(), z2.string().min(1)).superRefine((fields, ctx) => {
1962
2067
  const keys = Object.keys(fields);
1963
2068
  if (keys.length === 0) {
1964
2069
  ctx.addIssue({
@@ -1976,7 +2081,7 @@ var FieldsSchema = z.record(z.string(), z.string().min(1)).superRefine((fields,
1976
2081
  }
1977
2082
  }
1978
2083
  });
1979
- var ValuesSchema = z.record(z.string(), z.record(z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
2084
+ var ValuesSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
1980
2085
  for (const key of Object.keys(values)) {
1981
2086
  if (!ALL_KEY_SET.has(key)) {
1982
2087
  ctx.addIssue({
@@ -1986,8 +2091,8 @@ var ValuesSchema = z.record(z.string(), z.record(z.string(), ProviderScalarSchem
1986
2091
  }
1987
2092
  }
1988
2093
  });
1989
- var StaticSchema = z.record(z.string(), ProviderScalarSchema);
1990
- var InputSpecSchema = z.strictObject({
2094
+ var StaticSchema = z2.record(z2.string(), ProviderScalarSchema);
2095
+ var InputSpecSchema = z2.strictObject({
1991
2096
  fields: FieldsSchema,
1992
2097
  values: ValuesSchema.optional(),
1993
2098
  static: StaticSchema.optional()
@@ -2091,16 +2196,16 @@ var ADAPTER_IDS = [
2091
2196
  "higgsfield",
2092
2197
  "xai-video"
2093
2198
  ];
2094
- var ModelTypeSchema = z2.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2095
- var LifecycleSchema = z2.enum(["active", "deprecated", "retired"]);
2096
- var SurfaceSchema = z2.enum(["cowork", "space_builder"]);
2199
+ var ModelTypeSchema = z3.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2200
+ var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
2201
+ var SurfaceSchema = z3.enum(["cowork", "space_builder"]);
2097
2202
  var SURFACES2 = SurfaceSchema.options;
2098
- var ExposureSchema = z2.preprocess(
2203
+ var ExposureSchema = z3.preprocess(
2099
2204
  normalizeExposure,
2100
- z2.array(SurfaceSchema)
2205
+ z3.array(SurfaceSchema)
2101
2206
  );
2102
- var AdapterSchema = z2.enum(ADAPTER_IDS);
2103
- var AspectRatioSchema = z2.enum([
2207
+ var AdapterSchema = z3.enum(ADAPTER_IDS);
2208
+ var AspectRatioSchema = z3.enum([
2104
2209
  "1:1",
2105
2210
  "16:9",
2106
2211
  "9:16",
@@ -2115,12 +2220,12 @@ var AspectRatioSchema = z2.enum([
2115
2220
  "97:30",
2116
2221
  "adaptive"
2117
2222
  ]);
2118
- var ImageSizeSchema = z2.enum(["512", "1K", "2K", "4K"]);
2119
- var VideoResolutionSchema = z2.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2120
- var ImageQualitySchema = z2.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2121
- var OutputFormatSchema = z2.enum(["png", "jpeg", "webp"]);
2122
- var RequiredInputSchema = z2.enum(["firstFrame", "sourceVideo", "references"]);
2123
- var SupportedOptionSchema = z2.enum([
2223
+ var ImageSizeSchema = z3.enum(["512", "1K", "2K", "4K"]);
2224
+ var VideoResolutionSchema = z3.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2225
+ var ImageQualitySchema = z3.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2226
+ var OutputFormatSchema = z3.enum(["png", "jpeg", "webp"]);
2227
+ var RequiredInputSchema = z3.enum(["firstFrame", "sourceVideo", "references"]);
2228
+ var SupportedOptionSchema = z3.enum([
2124
2229
  "seed",
2125
2230
  "quality",
2126
2231
  "negativePrompt",
@@ -2140,142 +2245,147 @@ var SupportedOptionSchema = z2.enum([
2140
2245
  "videoExtension",
2141
2246
  "instrumental"
2142
2247
  ]);
2143
- var UsageUnitSchema = z2.enum([
2248
+ var UsageUnitSchema = z3.enum([
2144
2249
  "tokens",
2145
2250
  "images",
2146
2251
  "seconds",
2147
2252
  "reported_cost_usd",
2148
2253
  "compute_seconds"
2149
2254
  ]);
2150
- var PricingKindSchema = z2.enum(["token", "image_size", "video_per_second", "flat"]);
2151
- var ProviderOptionValueSchema = z2.lazy(
2152
- () => z2.union([
2153
- z2.string(),
2154
- z2.number(),
2155
- z2.boolean(),
2156
- z2.array(ProviderOptionValueSchema),
2157
- z2.record(z2.string(), ProviderOptionValueSchema)
2255
+ var PricingKindSchema = z3.enum(["token", "image_size", "video_per_second", "flat"]);
2256
+ var ProviderOptionValueSchema = z3.lazy(
2257
+ () => z3.union([
2258
+ z3.string(),
2259
+ z3.number(),
2260
+ z3.boolean(),
2261
+ z3.array(ProviderOptionValueSchema),
2262
+ z3.record(z3.string(), ProviderOptionValueSchema)
2158
2263
  ])
2159
2264
  );
2160
- var ProviderOptionsSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderOptionValueSchema));
2161
- var VideoSecondsLimitsSchema = z2.looseObject({
2162
- min: z2.number().optional(),
2163
- max: z2.number().optional(),
2164
- total: z2.number().optional(),
2165
- editMin: z2.number().optional()
2265
+ var ProviderOptionsSchema = z3.record(z3.string(), z3.record(z3.string(), ProviderOptionValueSchema));
2266
+ var VideoSecondsLimitsSchema = z3.looseObject({
2267
+ min: z3.number().optional(),
2268
+ max: z3.number().optional(),
2269
+ total: z3.number().optional(),
2270
+ editMin: z3.number().optional()
2166
2271
  });
2167
- var ReferenceLimitsSchema = z2.looseObject({
2168
- images: z2.number().optional(),
2169
- imagesWithVideo: z2.number().optional(),
2170
- videos: z2.number().optional(),
2171
- audios: z2.number().optional(),
2172
- total: z2.number().optional(),
2173
- audioOnly: z2.boolean().optional(),
2272
+ var ReferenceLimitsSchema = z3.looseObject({
2273
+ images: z3.number().optional(),
2274
+ imagesWithVideo: z3.number().optional(),
2275
+ videos: z3.number().optional(),
2276
+ audios: z3.number().optional(),
2277
+ total: z3.number().optional(),
2278
+ audioOnly: z3.boolean().optional(),
2174
2279
  videoSeconds: VideoSecondsLimitsSchema.optional()
2175
2280
  });
2176
- var ModelConstraintsSchema = z2.looseObject({
2177
- aspectRatios: z2.array(AspectRatioSchema).optional(),
2178
- sizes: z2.array(ImageSizeSchema).optional(),
2179
- resolutions: z2.array(VideoResolutionSchema).optional(),
2180
- durations: z2.union([z2.looseObject({ min: z2.number(), max: z2.number() }), z2.array(z2.number())]).optional(),
2181
- durationPresets: z2.array(z2.number()).optional(),
2182
- qualityOptions: z2.array(z2.string()).optional(),
2183
- exactSizes: z2.record(z2.string(), z2.string()).optional(),
2281
+ var ModelConstraintsSchema = z3.looseObject({
2282
+ aspectRatios: z3.array(AspectRatioSchema).optional(),
2283
+ sizes: z3.array(ImageSizeSchema).optional(),
2284
+ resolutions: z3.array(VideoResolutionSchema).optional(),
2285
+ durations: z3.union([z3.looseObject({ min: z3.number(), max: z3.number() }), z3.array(z3.number())]).optional(),
2286
+ durationPresets: z3.array(z3.number()).optional(),
2287
+ qualityOptions: z3.array(z3.string()).optional(),
2288
+ exactSizes: z3.record(z3.string(), z3.string()).optional(),
2184
2289
  references: ReferenceLimitsSchema.optional(),
2185
- requires: z2.array(RequiredInputSchema).optional(),
2186
- supports: z2.array(SupportedOptionSchema).optional(),
2187
- ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional(),
2188
- sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z2.boolean().optional() }).optional(),
2189
- extension: z2.looseObject({ segmentSeconds: z2.number(), maxTotalSeconds: z2.number() }).optional()
2290
+ requires: z3.array(RequiredInputSchema).optional(),
2291
+ supports: z3.array(SupportedOptionSchema).optional(),
2292
+ ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
2293
+ sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
2294
+ extension: z3.looseObject({ segmentSeconds: z3.number(), maxTotalSeconds: z3.number() }).optional(),
2295
+ // Loose on purpose: the read path keeps a row whose value is invalid (the accessors in
2296
+ // conventions.ts read it as "not set"); CatalogModelSchema below rejects it on write.
2297
+ audio: z3.unknown().optional(),
2298
+ prompt: z3.unknown().optional()
2190
2299
  });
2191
- var MediaRefSchema = z2.union([
2192
- z2.looseObject({
2193
- url: z2.string(),
2194
- label: z2.string().optional(),
2195
- durationSeconds: z2.number().optional()
2300
+ var MediaRefSchema = z3.union([
2301
+ z3.looseObject({
2302
+ url: z3.string(),
2303
+ label: z3.string().optional(),
2304
+ durationSeconds: z3.number().optional()
2196
2305
  }),
2197
- z2.looseObject({
2198
- bytes: z2.instanceof(Uint8Array),
2199
- mime: z2.string(),
2200
- label: z2.string().optional(),
2201
- durationSeconds: z2.number().optional()
2306
+ z3.looseObject({
2307
+ bytes: z3.instanceof(Uint8Array),
2308
+ mime: z3.string(),
2309
+ label: z3.string().optional(),
2310
+ durationSeconds: z3.number().optional()
2202
2311
  })
2203
2312
  ]);
2204
- var ImageSafetySettingSchema = z2.looseObject({ category: z2.string(), threshold: z2.string() });
2205
- var UpscaleOptionsSchema = z2.looseObject({
2206
- enhanceModel: z2.string().optional(),
2207
- subjectDetection: z2.string().optional(),
2208
- faceEnhancement: z2.boolean().optional(),
2209
- faceEnhancementCreativity: z2.number().optional(),
2210
- faceEnhancementStrength: z2.number().optional()
2313
+ var ImageSafetySettingSchema = z3.looseObject({ category: z3.string(), threshold: z3.string() });
2314
+ var UpscaleOptionsSchema = z3.looseObject({
2315
+ enhanceModel: z3.string().optional(),
2316
+ subjectDetection: z3.string().optional(),
2317
+ faceEnhancement: z3.boolean().optional(),
2318
+ faceEnhancementCreativity: z3.number().optional(),
2319
+ faceEnhancementStrength: z3.number().optional()
2211
2320
  });
2212
- var DefaultsSchema = z2.looseObject({
2213
- references: z2.array(MediaRefSchema).optional(),
2321
+ var DefaultsSchema = z3.looseObject({
2322
+ references: z3.array(MediaRefSchema).optional(),
2214
2323
  aspectRatio: AspectRatioSchema.optional(),
2215
2324
  size: ImageSizeSchema.optional(),
2216
- exactSize: z2.string().optional(),
2325
+ exactSize: z3.string().optional(),
2217
2326
  quality: ImageQualitySchema.optional(),
2218
- seed: z2.number().optional(),
2219
- count: z2.number().optional(),
2327
+ seed: z3.number().optional(),
2328
+ count: z3.number().optional(),
2220
2329
  outputFormat: OutputFormatSchema.optional(),
2221
- scaleFactor: z2.number().optional(),
2222
- safetySettings: z2.array(ImageSafetySettingSchema).optional(),
2223
- temperature: z2.number().optional(),
2330
+ scaleFactor: z3.number().optional(),
2331
+ safetySettings: z3.array(ImageSafetySettingSchema).optional(),
2332
+ temperature: z3.number().optional(),
2224
2333
  upscale: UpscaleOptionsSchema.optional(),
2225
2334
  firstFrame: MediaRefSchema.optional(),
2226
2335
  lastFrame: MediaRefSchema.optional(),
2227
2336
  sourceVideo: MediaRefSchema.optional(),
2228
- referenceImages: z2.array(MediaRefSchema).optional(),
2229
- referenceVideos: z2.array(MediaRefSchema).optional(),
2230
- referenceAudios: z2.array(MediaRefSchema).optional(),
2337
+ referenceImages: z3.array(MediaRefSchema).optional(),
2338
+ referenceVideos: z3.array(MediaRefSchema).optional(),
2339
+ referenceAudios: z3.array(MediaRefSchema).optional(),
2231
2340
  resolution: VideoResolutionSchema.optional(),
2232
- durationSeconds: z2.number().optional(),
2233
- generateAudio: z2.boolean().optional(),
2234
- negativePrompt: z2.string().optional(),
2235
- cfgScale: z2.number().optional(),
2236
- promptExpansion: z2.enum(["fast", "balanced", "quality"]).optional(),
2237
- watermark: z2.boolean().optional(),
2238
- safetyChecker: z2.boolean().optional(),
2239
- taskType: z2.enum(["reference", "edit", "extend"]).optional(),
2240
- mode: z2.enum(["standard", "pro"]).optional(),
2241
- instrumental: z2.boolean().optional()
2341
+ durationSeconds: z3.number().optional(),
2342
+ generateAudio: z3.boolean().optional(),
2343
+ negativePrompt: z3.string().optional(),
2344
+ cfgScale: z3.number().optional(),
2345
+ promptExpansion: z3.enum(["fast", "balanced", "quality"]).optional(),
2346
+ watermark: z3.boolean().optional(),
2347
+ safetyChecker: z3.boolean().optional(),
2348
+ taskType: z3.enum(["reference", "edit", "extend"]).optional(),
2349
+ mode: z3.enum(["standard", "pro"]).optional(),
2350
+ instrumental: z3.boolean().optional()
2242
2351
  });
2243
- var CatalogDisplaySchema = z2.looseObject({
2244
- provider: z2.string(),
2245
- description: z2.string(),
2246
- logo: z2.string().optional(),
2247
- costTier: z2.union([z2.literal(1), z2.literal(2), z2.literal(3)]).optional(),
2248
- recommended: z2.boolean().optional(),
2249
- sortOrder: z2.number().optional(),
2250
- chat: z2.looseObject({
2352
+ var CatalogDisplaySchema = z3.looseObject({
2353
+ provider: z3.string(),
2354
+ description: z3.string(),
2355
+ logo: z3.string().optional(),
2356
+ costTier: z3.union([z3.literal(1), z3.literal(2), z3.literal(3)]).optional(),
2357
+ recommended: z3.boolean().optional(),
2358
+ sortOrder: z3.number().optional(),
2359
+ chat: z3.looseObject({
2251
2360
  providerOptions: ProviderOptionsSchema.optional(),
2252
- temperature: z2.number().optional()
2361
+ temperature: z3.number().optional()
2253
2362
  }).optional()
2254
2363
  });
2255
- var CatalogCapabilitiesSchema = z2.looseObject({
2256
- acceptsSourceVideo: z2.boolean().optional(),
2257
- framesExcludeReferences: z2.boolean().optional(),
2258
- reasoning: z2.boolean().optional(),
2259
- vision: z2.boolean().optional(),
2260
- contextWindow: z2.number().optional()
2364
+ var CatalogCapabilitiesSchema = z3.looseObject({
2365
+ acceptsSourceVideo: z3.boolean().optional(),
2366
+ framesExcludeReferences: z3.boolean().optional(),
2367
+ lastFrameRequiresFirstFrame: z3.boolean().optional(),
2368
+ reasoning: z3.boolean().optional(),
2369
+ vision: z3.boolean().optional(),
2370
+ contextWindow: z3.number().optional()
2261
2371
  });
2262
- var CatalogModelSchemaBase = z2.looseObject({
2263
- id: z2.string().min(1),
2264
- aliases: z2.array(z2.string()).default([]),
2265
- label: z2.string().min(1),
2372
+ var CatalogModelSchemaBase = z3.looseObject({
2373
+ id: z3.string().min(1),
2374
+ aliases: z3.array(z3.string()).default([]),
2375
+ label: z3.string().min(1),
2266
2376
  type: ModelTypeSchema,
2267
2377
  adapter: AdapterSchema,
2268
- providerModelId: z2.string().min(1),
2378
+ providerModelId: z3.string().min(1),
2269
2379
  lifecycle: LifecycleSchema,
2270
- replacedBy: z2.string().optional(),
2380
+ replacedBy: z3.string().optional(),
2271
2381
  exposure: ExposureSchema,
2272
2382
  constraints: ModelConstraintsSchema,
2273
2383
  defaults: DefaultsSchema,
2274
2384
  providerOptions: ProviderOptionsSchema.optional(),
2275
- usage: z2.looseObject({
2385
+ usage: z3.looseObject({
2276
2386
  unit: UsageUnitSchema,
2277
- slug: z2.string().optional(),
2278
- providerLabel: z2.string().optional()
2387
+ slug: z3.string().optional(),
2388
+ providerLabel: z3.string().optional()
2279
2389
  }),
2280
2390
  pricingKind: PricingKindSchema,
2281
2391
  display: CatalogDisplaySchema.optional(),
@@ -2326,9 +2436,30 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2326
2436
  }
2327
2437
  }
2328
2438
  }
2439
+ const audio = row.constraints.audio;
2440
+ if (audio !== void 0 && !AudioOutputSchema.safeParse(audio).success) {
2441
+ ctx.addIssue({
2442
+ code: "custom",
2443
+ path: ["constraints", "audio"],
2444
+ message: 'audio must be "always", "optional" or "never"'
2445
+ });
2446
+ }
2447
+ const prompt = row.constraints.prompt;
2448
+ if (prompt !== void 0) {
2449
+ const parsed = PromptConventionsSchema.safeParse(prompt);
2450
+ if (!parsed.success) {
2451
+ for (const issue of parsed.error.issues) {
2452
+ ctx.addIssue({
2453
+ code: "custom",
2454
+ path: ["constraints", "prompt", ...issue.path.map(String)],
2455
+ message: issue.message
2456
+ });
2457
+ }
2458
+ }
2459
+ }
2329
2460
  }
2330
2461
  );
2331
- var CatalogSchema = z2.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2462
+ var CatalogSchema = z3.array(CatalogModelSchemaBase.transform((row) => normaliseConventions(row).row)).superRefine((rows, ctx) => {
2332
2463
  for (const issue of collisionIssues(rows)) {
2333
2464
  ctx.addIssue({
2334
2465
  code: "custom",
@@ -2351,42 +2482,42 @@ var liveState = store[KEY] ??= {
2351
2482
  var liveCatalog = liveState.catalog;
2352
2483
 
2353
2484
  // src/json.ts
2354
- import { z as z3 } from "zod";
2355
- var JsonValueSchema = z3.lazy(
2356
- () => z3.union([
2357
- z3.string(),
2358
- z3.number(),
2359
- z3.boolean(),
2360
- z3.null(),
2361
- z3.array(JsonValueSchema),
2362
- z3.record(z3.string(), JsonValueSchema)
2485
+ import { z as z4 } from "zod";
2486
+ var JsonValueSchema = z4.lazy(
2487
+ () => z4.union([
2488
+ z4.string(),
2489
+ z4.number(),
2490
+ z4.boolean(),
2491
+ z4.null(),
2492
+ z4.array(JsonValueSchema),
2493
+ z4.record(z4.string(), JsonValueSchema)
2363
2494
  ])
2364
2495
  );
2365
- var JsonObjectSchema = z3.record(z3.string(), JsonValueSchema);
2366
- var thrownErrorSchema = z3.object({
2367
- message: z3.string().optional(),
2368
- status: z3.number().optional(),
2369
- statusCode: z3.number().optional(),
2370
- responseBody: z3.string().optional()
2496
+ var JsonObjectSchema = z4.record(z4.string(), JsonValueSchema);
2497
+ var thrownErrorSchema = z4.object({
2498
+ message: z4.string().optional(),
2499
+ status: z4.number().optional(),
2500
+ statusCode: z4.number().optional(),
2501
+ responseBody: z4.string().optional()
2371
2502
  });
2372
2503
 
2373
2504
  // src/catalog/load.ts
2374
- import { z as z4 } from "zod";
2505
+ import { z as z5 } from "zod";
2375
2506
  function rowCount() {
2376
2507
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2377
2508
  }
2378
2509
  function authHeaders(auth) {
2379
2510
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2380
2511
  }
2381
- var EnvelopeSchema = z4.object({
2382
- rows: z4.array(JsonValueSchema),
2383
- revision: z4.string().optional()
2512
+ var EnvelopeSchema = z5.object({
2513
+ rows: z5.array(JsonValueSchema),
2514
+ revision: z5.string().optional()
2384
2515
  });
2385
2516
  function dropReason(path, message) {
2386
2517
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
2387
2518
  }
2388
2519
  function rowId(raw) {
2389
- const parsed = z4.object({ id: z4.string().min(1) }).loose().safeParse(raw);
2520
+ const parsed = z5.object({ id: z5.string().min(1) }).loose().safeParse(raw);
2390
2521
  if (!parsed.success) return "?";
2391
2522
  return parsed.data.id;
2392
2523
  }
@@ -2414,7 +2545,13 @@ function quarantine(rawRows, logger) {
2414
2545
  );
2415
2546
  }
2416
2547
  }
2417
- valid.push(row);
2548
+ const normalised = normaliseConventions(row);
2549
+ if (normalised.invalidKeys.length > 0) {
2550
+ logger.warn(
2551
+ `[modelkit] catalog row ${row.id} has an invalid ${normalised.invalidKeys.join(", ")}; read as not set`
2552
+ );
2553
+ }
2554
+ valid.push(normalised.row);
2418
2555
  }
2419
2556
  let kept = valid;
2420
2557
  for (; ; ) {
@@ -2809,6 +2946,24 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
2809
2946
  });
2810
2947
  delete merged.sourceVideo;
2811
2948
  }
2949
+ if (merged.lastFrame !== void 0 && merged.firstFrame === void 0 && model.capabilities?.lastFrameRequiresFirstFrame) {
2950
+ if (onUnsupported === "error") {
2951
+ throw new ModelKitError({
2952
+ code: "missing_input",
2953
+ message: `${model.id} takes an end frame only together with a start frame`,
2954
+ model: model.id,
2955
+ retryable: false
2956
+ });
2957
+ }
2958
+ warnings.push({
2959
+ code: "option_ignored",
2960
+ field: "lastFrame",
2961
+ to: "firstFrame",
2962
+ message: `end frame used as start frame: ${model.id} needs a start frame with an end frame`
2963
+ });
2964
+ merged.firstFrame = merged.lastFrame;
2965
+ delete merged.lastFrame;
2966
+ }
2812
2967
  const hasFrames = merged.firstFrame !== void 0 || merged.lastFrame !== void 0;
2813
2968
  const hasRefs = compact(merged.referenceImages).length + compact(merged.referenceVideos).length + compact(merged.referenceAudios).length > 0;
2814
2969
  if (hasFrames && hasRefs && model.capabilities?.framesExcludeReferences) {
@@ -3028,6 +3183,7 @@ function resolveOptions(model, request, onUnsupported = "error") {
3028
3183
  }
3029
3184
  export {
3030
3185
  ADAPTER_IDS,
3186
+ AUDIO_OUTPUTS,
3031
3187
  Catalog,
3032
3188
  CatalogModelSchema,
3033
3189
  CatalogModelSchemaBase,
@@ -3037,6 +3193,7 @@ export {
3037
3193
  MODELS,
3038
3194
  ModelKitError,
3039
3195
  OTHER_MODELS,
3196
+ REFERENCE_SYNTAXES,
3040
3197
  SURFACES2 as SURFACES,
3041
3198
  SurfaceSchema,
3042
3199
  TEXT_MODELS,
@@ -3049,7 +3206,9 @@ export {
3049
3206
  liveState,
3050
3207
  nearestAspectRatio,
3051
3208
  normalizeExposure,
3209
+ outputAudio,
3052
3210
  primeCatalog,
3211
+ promptConventions,
3053
3212
  resetLiveCatalog,
3054
3213
  resolveAudioOptions,
3055
3214
  resolveImageOptions,