@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/index.js CHANGED
@@ -173,7 +173,9 @@ function geminiImage(id, label, aliases, sizes, display, exposure, references) {
173
173
  const constraints = {
174
174
  aspectRatios: [...GEMINI_RATIOS],
175
175
  sizes,
176
- supports: ["safetySettings", "temperature"]
176
+ supports: ["safetySettings", "temperature"],
177
+ // google-image sends MediaRef.label as a text part beside each reference.
178
+ prompt: { referenceSyntax: "caption" }
177
179
  };
178
180
  if (references !== void 0) constraints.references = references;
179
181
  const model = {
@@ -460,6 +462,7 @@ var IMAGE_MODELS = [
460
462
  constraints: {
461
463
  aspectRatios: ["1:1", "2:3", "3:2", "16:9", "9:16", "4:3", "3:4", "4:5", "5:4", "21:9"],
462
464
  sizes: ["1K"],
465
+ references: { images: 8 },
463
466
  // flux-2-pro's job type always returns image/png; only the seed is forwarded.
464
467
  supports: ["seed"]
465
468
  },
@@ -1255,12 +1258,14 @@ var TEXT_MODELS = [
1255
1258
  var VIDEO_USAGE = { unit: "seconds" };
1256
1259
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
1257
1260
  var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
1261
+ var KLING_OMNI_RATIOS = ["16:9", "9:16", "1:1"];
1258
1262
  var OMNI_RATIOS = ["16:9", "9:16"];
1259
1263
  var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
1260
1264
  var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
1261
1265
  var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
1262
1266
  var NEGATIVE_PROMPT = "blur, distort, and low quality";
1263
1267
  var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
1268
+ var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
1264
1269
  var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
1265
1270
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
1266
1271
  var VIDEO_MODELS = [
@@ -1281,9 +1286,14 @@ var VIDEO_MODELS = [
1281
1286
  constraints: {
1282
1287
  aspectRatios: [...OMNI_RATIOS],
1283
1288
  resolutions: ["720p", "1080p", "4k"],
1289
+ // Veo also takes 4 and 6, but must be 8 at 1080p/4k or with reference images;
1290
+ // [8] until the kit has a rule that forces it there (CHANGELOG 0.2.21).
1284
1291
  durations: [8],
1285
1292
  references: { images: 3 },
1286
- supports: ["lastFrame", "seed"]
1293
+ supports: ["lastFrame", "seed"],
1294
+ // 1,024 text tokens; 3,000 characters assumes ~2.9 characters per token.
1295
+ prompt: { referenceSyntax: "numbered", maxChars: 3e3 },
1296
+ audio: "always"
1287
1297
  },
1288
1298
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1289
1299
  usage: { ...VIDEO_USAGE, slug: "veo" },
@@ -1293,7 +1303,8 @@ var VIDEO_MODELS = [
1293
1303
  description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
1294
1304
  logo: GOOGLE_LOGO2
1295
1305
  },
1296
- capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1306
+ // Veo's lastFrame "must be used in combination with the image parameter".
1307
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES, lastFrameRequiresFirstFrame: true }
1297
1308
  },
1298
1309
  {
1299
1310
  id: "veo-3.1-fast",
@@ -1313,7 +1324,8 @@ var VIDEO_MODELS = [
1313
1324
  resolutions: ["720p", "1080p", "4k"],
1314
1325
  durations: [4, 6, 8],
1315
1326
  references: { images: 3 },
1316
- supports: ["lastFrame", "seed"]
1327
+ supports: ["lastFrame", "seed"],
1328
+ audio: "always"
1317
1329
  },
1318
1330
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1319
1331
  usage: { ...VIDEO_USAGE },
@@ -1341,7 +1353,8 @@ var VIDEO_MODELS = [
1341
1353
  aspectRatios: [...OMNI_RATIOS],
1342
1354
  resolutions: ["720p", "1080p"],
1343
1355
  durations: [4, 6, 8],
1344
- supports: ["lastFrame", "seed"]
1356
+ supports: ["lastFrame", "seed"],
1357
+ audio: "always"
1345
1358
  },
1346
1359
  defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
1347
1360
  usage: { ...VIDEO_USAGE },
@@ -1375,7 +1388,10 @@ var VIDEO_MODELS = [
1375
1388
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1376
1389
  references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1377
1390
  sourceVideoSeconds: { max: 10 },
1378
- supports: []
1391
+ supports: [],
1392
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1393
+ prompt: { referenceSyntax: "caption" },
1394
+ audio: "always"
1379
1395
  },
1380
1396
  defaults: {},
1381
1397
  usage: { ...VIDEO_USAGE, slug: "gemini_omni" },
@@ -1408,8 +1424,12 @@ var VIDEO_MODELS = [
1408
1424
  // extension can upload a <= 10 s source with task "extend"; later ones
1409
1425
  // chain by `previousInteractionId` (the API rejects the id together
1410
1426
  // with a video task, so those calls carry the prompt alone).
1411
- supports: ["videoExtension"],
1412
- extension: { segmentSeconds: 10, maxTotalSeconds: 40 }
1427
+ // First-to-last-frame interpolation: `<LAST_FRAME>` goes with `<FIRST_FRAME>`.
1428
+ supports: ["videoExtension", "lastFrame"],
1429
+ extension: { segmentSeconds: 10, maxTotalSeconds: 40 },
1430
+ // generateOmniVideo sends MediaRef.label as a text part beside each image.
1431
+ prompt: { referenceSyntax: "caption" },
1432
+ audio: "always"
1413
1433
  },
1414
1434
  defaults: {},
1415
1435
  usage: { ...VIDEO_USAGE },
@@ -1419,7 +1439,7 @@ var VIDEO_MODELS = [
1419
1439
  logo: GOOGLE_LOGO2,
1420
1440
  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."
1421
1441
  },
1422
- capabilities: { acceptsSourceVideo: true }
1442
+ capabilities: { acceptsSourceVideo: true, lastFrameRequiresFirstFrame: true }
1423
1443
  },
1424
1444
  {
1425
1445
  // vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
@@ -1445,7 +1465,9 @@ var VIDEO_MODELS = [
1445
1465
  },
1446
1466
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1447
1467
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1448
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1468
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1469
+ supports: ["generateAudio", "lastFrame", "watermark"],
1470
+ audio: "optional"
1449
1471
  },
1450
1472
  defaults: {
1451
1473
  durationSeconds: 5,
@@ -1484,7 +1506,9 @@ var VIDEO_MODELS = [
1484
1506
  },
1485
1507
  sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1486
1508
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1487
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1509
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1510
+ supports: ["generateAudio", "lastFrame", "watermark"],
1511
+ audio: "optional"
1488
1512
  },
1489
1513
  defaults: {
1490
1514
  durationSeconds: 5,
@@ -1502,7 +1526,6 @@ var VIDEO_MODELS = [
1502
1526
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1503
1527
  },
1504
1528
  {
1505
- // generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
1506
1529
  // omni_reference_task_type edit/extend: adaptive ratio, edit sends duration -1.
1507
1530
  id: "seedance-2.5",
1508
1531
  aliases: ["seedance-2-5", "dreamina-seedance-2-5-260628"],
@@ -1524,13 +1547,15 @@ var VIDEO_MODELS = [
1524
1547
  },
1525
1548
  sourceVideoSeconds: { min: 2, max: 30, editMin: 4, inReferenceTotal: true },
1526
1549
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1527
- supports: ["generateAudio", "seed", "lastFrame", "watermark", "taskType"]
1550
+ // No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
1551
+ supports: ["generateAudio", "lastFrame", "watermark", "taskType"],
1552
+ audio: "optional"
1528
1553
  },
1529
1554
  defaults: {
1530
1555
  durationSeconds: 5,
1531
1556
  resolution: "720p",
1532
1557
  aspectRatio: "16:9",
1533
- generateAudio: false
1558
+ generateAudio: true
1534
1559
  },
1535
1560
  usage: { ...VIDEO_USAGE },
1536
1561
  pricingKind: "video_per_second",
@@ -1542,7 +1567,6 @@ var VIDEO_MODELS = [
1542
1567
  capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
1543
1568
  },
1544
1569
  {
1545
- // Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
1546
1570
  id: "grok-imagine",
1547
1571
  aliases: ["grok-imagine-video", "grokImagine"],
1548
1572
  label: "Grok Imagine",
@@ -1556,8 +1580,11 @@ var VIDEO_MODELS = [
1556
1580
  resolutions: ["480p", "720p"],
1557
1581
  durations: { min: 1, max: 15 },
1558
1582
  durationPresets: [4, 6, 8, 10],
1559
- references: { images: 5 },
1560
- supports: []
1583
+ // xAI: "A maximum of 7 reference images can be provided per request."
1584
+ references: { images: 7 },
1585
+ supports: [],
1586
+ // xAI can switch sound off (generate_audio); xai-video.ts never sends it.
1587
+ audio: "always"
1561
1588
  },
1562
1589
  // No resolution default: xAI picks its own unless the caller asks.
1563
1590
  defaults: { durationSeconds: 8, aspectRatio: "16:9" },
@@ -1579,15 +1606,16 @@ var VIDEO_MODELS = [
1579
1606
  providerModelId: "kling-video/v2.5-turbo/pro/image-to-video",
1580
1607
  lifecycle: "active",
1581
1608
  exposure: ["cowork", "space_builder"],
1609
+ // The endpoint has no aspect_ratio or last_image_url: the start image sets the framing.
1582
1610
  constraints: {
1583
- aspectRatios: [...KLING_RATIOS],
1584
1611
  durations: [5, 10],
1585
1612
  requires: ["firstFrame"],
1586
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1613
+ supports: ["cfgScale", "negativePrompt"],
1614
+ prompt: KLING_PROMPT,
1615
+ audio: "never"
1587
1616
  },
1588
1617
  defaults: {
1589
1618
  durationSeconds: 5,
1590
- aspectRatio: "16:9",
1591
1619
  cfgScale: 0.5,
1592
1620
  negativePrompt: NEGATIVE_PROMPT
1593
1621
  },
@@ -1596,7 +1624,7 @@ var VIDEO_MODELS = [
1596
1624
  display: {
1597
1625
  provider: "kuaishou",
1598
1626
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1599
- 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."
1627
+ description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt, 5- or 10-second clips."
1600
1628
  },
1601
1629
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1602
1630
  },
@@ -1610,17 +1638,18 @@ var VIDEO_MODELS = [
1610
1638
  providerModelId: "kling-video/v3.0/pro/image-to-video",
1611
1639
  lifecycle: "active",
1612
1640
  exposure: ["cowork", "space_builder"],
1641
+ // The endpoint has no aspect_ratio or negative_prompt; sound is "on"/"off" (default on).
1613
1642
  constraints: {
1614
- aspectRatios: [...KLING_RATIOS],
1615
1643
  durations: { min: 3, max: 15 },
1616
1644
  requires: ["firstFrame"],
1617
- supports: ["cfgScale", "negativePrompt", "lastFrame"]
1645
+ supports: ["cfgScale", "lastFrame", "generateAudio"],
1646
+ prompt: KLING_PROMPT,
1647
+ audio: "optional"
1618
1648
  },
1619
1649
  defaults: {
1620
1650
  durationSeconds: 5,
1621
- aspectRatio: "16:9",
1622
1651
  cfgScale: 0.5,
1623
- negativePrompt: NEGATIVE_PROMPT
1652
+ generateAudio: true
1624
1653
  },
1625
1654
  usage: { ...VIDEO_USAGE },
1626
1655
  pricingKind: "video_per_second",
@@ -1632,7 +1661,7 @@ var VIDEO_MODELS = [
1632
1661
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1633
1662
  },
1634
1663
  {
1635
- // mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
1664
+ // mode standard/pro/4k selects 720p/1080p/4K; the endpoint takes no separate resolution.
1636
1665
  // Replicate: "Max 7 [images] without video, 4 with video"; 4K does not support
1637
1666
  // reference_video. No `videos` limit yet: the adapter sends no reference video,
1638
1667
  // so `imagesWithVideo` stays dormant until one is wired through.
@@ -1645,21 +1674,25 @@ var VIDEO_MODELS = [
1645
1674
  lifecycle: "active",
1646
1675
  exposure: ["cowork", "space_builder"],
1647
1676
  constraints: {
1648
- aspectRatios: [...KLING_RATIOS],
1649
- resolutions: ["720p", "1080p"],
1677
+ aspectRatios: [...KLING_OMNI_RATIOS],
1678
+ resolutions: ["720p", "1080p", "4k"],
1650
1679
  durations: { min: 3, max: 15 },
1651
1680
  references: { images: 7, imagesWithVideo: 4 },
1652
- supports: ["generateAudio", "lastFrame"]
1681
+ supports: ["generateAudio", "lastFrame"],
1682
+ prompt: KLING_PROMPT,
1683
+ audio: "optional"
1653
1684
  },
1654
- defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
1685
+ defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: true, mode: "pro" },
1655
1686
  usage: { unit: "compute_seconds" },
1656
1687
  pricingKind: "video_per_second",
1657
1688
  display: {
1658
1689
  provider: "kuaishou",
1659
1690
  logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1660
- 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."
1661
- },
1662
- capabilities: {}
1691
+ 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."
1692
+ }
1693
+ // end_image "Requires start_image", but no lastFrameRequiresFirstFrame: SpaceLab resolves
1694
+ // replicate rows in error mode, so the flag would refuse its end-frame-only nodes, which
1695
+ // the adapter sends as start_image.
1663
1696
  },
1664
1697
  {
1665
1698
  id: "minimax-h3",
@@ -1674,7 +1707,10 @@ var VIDEO_MODELS = [
1674
1707
  aspectRatios: [...H3_RATIOS],
1675
1708
  resolutions: ["480p", "768p", "2k", "4k"],
1676
1709
  durations: { min: 5, max: 15 },
1677
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1710
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1711
+ ratioIgnoredWith: ["firstFrame"],
1712
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1713
+ audio: "always"
1678
1714
  },
1679
1715
  defaults: {
1680
1716
  durationSeconds: 5,
@@ -1702,9 +1738,12 @@ var VIDEO_MODELS = [
1702
1738
  exposure: ["cowork", "space_builder"],
1703
1739
  constraints: {
1704
1740
  aspectRatios: [...H3_RATIOS],
1705
- resolutions: ["480p", "768p"],
1741
+ resolutions: ["480p", "768p", "1080p"],
1706
1742
  durations: { min: 5, max: 15 },
1707
- supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
1743
+ // fal's image-to-video endpoint has no aspect_ratio; the frame sets it.
1744
+ ratioIgnoredWith: ["firstFrame"],
1745
+ supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"],
1746
+ audio: "always"
1708
1747
  },
1709
1748
  defaults: {
1710
1749
  durationSeconds: 5,
@@ -1717,7 +1756,7 @@ var VIDEO_MODELS = [
1717
1756
  display: {
1718
1757
  provider: "minimax",
1719
1758
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1720
- description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
1759
+ description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 1080p."
1721
1760
  },
1722
1761
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1723
1762
  },
@@ -1734,6 +1773,8 @@ var VIDEO_MODELS = [
1734
1773
  aspectRatios: [...H3_REFERENCE_RATIOS],
1735
1774
  resolutions: ["480p", "768p", "2k", "4k"],
1736
1775
  durations: { min: 5, max: 15 },
1776
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1777
+ ratioIgnoredWith: ["firstFrame"],
1737
1778
  references: {
1738
1779
  images: 9,
1739
1780
  videos: 3,
@@ -1742,7 +1783,8 @@ var VIDEO_MODELS = [
1742
1783
  audioOnly: false,
1743
1784
  videoSeconds: { min: 2, max: 15, total: 15 }
1744
1785
  },
1745
- supports: ["seed", "promptExpansion", "safetyChecker"]
1786
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1787
+ audio: "always"
1746
1788
  },
1747
1789
  defaults: {
1748
1790
  durationSeconds: 5,
@@ -1757,7 +1799,9 @@ var VIDEO_MODELS = [
1757
1799
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1758
1800
  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."
1759
1801
  },
1760
- capabilities: {}
1802
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1803
+ // references instead of the adapter silently dropping the frame.
1804
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1761
1805
  },
1762
1806
  {
1763
1807
  id: "minimax-h3-max-reference",
@@ -1770,8 +1814,10 @@ var VIDEO_MODELS = [
1770
1814
  exposure: ["cowork", "space_builder"],
1771
1815
  constraints: {
1772
1816
  aspectRatios: [...H3_REFERENCE_RATIOS],
1773
- resolutions: ["480p", "768p"],
1817
+ resolutions: ["480p", "768p", "1080p"],
1774
1818
  durations: { min: 5, max: 15 },
1819
+ // A start frame routes to image-to-video, which has no aspect_ratio.
1820
+ ratioIgnoredWith: ["firstFrame"],
1775
1821
  references: {
1776
1822
  images: 9,
1777
1823
  videos: 3,
@@ -1780,7 +1826,8 @@ var VIDEO_MODELS = [
1780
1826
  audioOnly: false,
1781
1827
  videoSeconds: { min: 2, max: 15, total: 15 }
1782
1828
  },
1783
- supports: ["seed", "promptExpansion", "safetyChecker"]
1829
+ supports: ["seed", "promptExpansion", "safetyChecker"],
1830
+ audio: "always"
1784
1831
  },
1785
1832
  defaults: {
1786
1833
  durationSeconds: 5,
@@ -1795,7 +1842,9 @@ var VIDEO_MODELS = [
1795
1842
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1796
1843
  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."
1797
1844
  },
1798
- capabilities: {}
1845
+ // fal's reference-to-video endpoint never reads a frame; the resolver must drop the
1846
+ // references instead of the adapter silently dropping the frame.
1847
+ capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
1799
1848
  },
1800
1849
  {
1801
1850
  // Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
@@ -1812,7 +1861,8 @@ var VIDEO_MODELS = [
1812
1861
  durations: { min: 3, max: 10 },
1813
1862
  requires: ["sourceVideo"],
1814
1863
  sourceVideoSeconds: { min: 3, max: 10.05 },
1815
- supports: []
1864
+ supports: [],
1865
+ audio: "never"
1816
1866
  },
1817
1867
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
1818
1868
  usage: { ...VIDEO_USAGE },
@@ -1836,7 +1886,8 @@ var VIDEO_MODELS = [
1836
1886
  constraints: {
1837
1887
  resolutions: ["768p"],
1838
1888
  durations: [6, 10],
1839
- supports: ["lastFrame"]
1889
+ supports: ["lastFrame"],
1890
+ audio: "never"
1840
1891
  },
1841
1892
  defaults: { durationSeconds: 6, resolution: "768p" },
1842
1893
  usage: { unit: "compute_seconds" },
@@ -1859,7 +1910,8 @@ var VIDEO_MODELS = [
1859
1910
  exposure: [],
1860
1911
  constraints: {
1861
1912
  requires: ["firstFrame"],
1862
- supports: ["seed", "lastFrame"]
1913
+ supports: ["seed", "lastFrame"],
1914
+ audio: "never"
1863
1915
  },
1864
1916
  defaults: {},
1865
1917
  usage: { ...VIDEO_USAGE },
@@ -1881,7 +1933,7 @@ var MODELS = [
1881
1933
  ];
1882
1934
 
1883
1935
  // src/catalog/schema.ts
1884
- import { z as z2 } from "zod";
1936
+ import { z as z3 } from "zod";
1885
1937
 
1886
1938
  // src/catalog/collisions.ts
1887
1939
  function collisionIssues(rows) {
@@ -1928,8 +1980,57 @@ function collisionIssues(rows) {
1928
1980
  return issues;
1929
1981
  }
1930
1982
 
1931
- // src/catalog/input-spec.ts
1983
+ // src/catalog/conventions.ts
1932
1984
  import { z } from "zod";
1985
+ var AudioOutputSchema = z.enum(["always", "optional", "never"]);
1986
+ var ReferenceSyntaxSchema = z.enum(["numbered", "caption", "descriptive"]);
1987
+ var MaxCharsSchema = z.number().int().positive();
1988
+ var PromptConventionsSchema = z.strictObject({
1989
+ referenceSyntax: ReferenceSyntaxSchema,
1990
+ maxChars: MaxCharsSchema.optional()
1991
+ });
1992
+ var AUDIO_OUTPUTS = AudioOutputSchema.options;
1993
+ var REFERENCE_SYNTAXES = ReferenceSyntaxSchema.options;
1994
+ var ConstraintsReadView = z.looseObject({
1995
+ audio: AudioOutputSchema.optional().catch(void 0),
1996
+ prompt: z.looseObject({
1997
+ referenceSyntax: ReferenceSyntaxSchema.catch("numbered"),
1998
+ maxChars: MaxCharsSchema.optional().catch(void 0)
1999
+ }).optional().catch(void 0)
2000
+ });
2001
+ var DEFAULT_CONVENTIONS = { referenceSyntax: "numbered" };
2002
+ function promptConventions(row) {
2003
+ const view = ConstraintsReadView.safeParse(row.constraints);
2004
+ const prompt = view.success ? view.data.prompt : void 0;
2005
+ if (prompt === void 0) return { ...DEFAULT_CONVENTIONS };
2006
+ const result = { referenceSyntax: prompt.referenceSyntax };
2007
+ if (prompt.maxChars !== void 0) result.maxChars = prompt.maxChars;
2008
+ return result;
2009
+ }
2010
+ var RawConventionsView = z.looseObject({
2011
+ audio: z.unknown().optional(),
2012
+ prompt: z.unknown().optional()
2013
+ });
2014
+ function normaliseConventions(row) {
2015
+ const view = RawConventionsView.safeParse(row.constraints);
2016
+ if (!view.success) return { row, invalidKeys: [] };
2017
+ const { audio, prompt } = view.data;
2018
+ const badAudio = audio !== void 0 && !AudioOutputSchema.safeParse(audio).success;
2019
+ const badPrompt = prompt !== void 0 && !PromptConventionsSchema.safeParse(prompt).success;
2020
+ if (!badAudio && !badPrompt) return { row, invalidKeys: [] };
2021
+ const invalidKeys = [];
2022
+ if (badAudio) invalidKeys.push("constraints.audio");
2023
+ if (badPrompt) invalidKeys.push("constraints.prompt");
2024
+ const entries = Object.entries(row.constraints).flatMap(([key, value]) => {
2025
+ if (key === "audio" && badAudio) return [];
2026
+ if (key === "prompt" && badPrompt) return [[key, promptConventions(row)]];
2027
+ return [[key, value]];
2028
+ });
2029
+ return { row: { ...row, constraints: Object.fromEntries(entries) }, invalidKeys };
2030
+ }
2031
+
2032
+ // src/catalog/input-spec.ts
2033
+ import { z as z2 } from "zod";
1933
2034
  var VIDEO_INPUT_SPEC_KEYS = [
1934
2035
  "prompt",
1935
2036
  "durationSeconds",
@@ -1968,8 +2069,8 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
1968
2069
  ...VIDEO_INPUT_SPEC_KEYS,
1969
2070
  ...AUDIO_INPUT_SPEC_KEYS
1970
2071
  ]);
1971
- var ProviderScalarSchema = z.union([z.string(), z.number(), z.boolean()]);
1972
- var FieldsSchema = z.record(z.string(), z.string().min(1)).superRefine((fields, ctx) => {
2072
+ var ProviderScalarSchema = z2.union([z2.string(), z2.number(), z2.boolean()]);
2073
+ var FieldsSchema = z2.record(z2.string(), z2.string().min(1)).superRefine((fields, ctx) => {
1973
2074
  const keys = Object.keys(fields);
1974
2075
  if (keys.length === 0) {
1975
2076
  ctx.addIssue({
@@ -1987,7 +2088,7 @@ var FieldsSchema = z.record(z.string(), z.string().min(1)).superRefine((fields,
1987
2088
  }
1988
2089
  }
1989
2090
  });
1990
- var ValuesSchema = z.record(z.string(), z.record(z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
2091
+ var ValuesSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
1991
2092
  for (const key of Object.keys(values)) {
1992
2093
  if (!ALL_KEY_SET.has(key)) {
1993
2094
  ctx.addIssue({
@@ -1997,8 +2098,8 @@ var ValuesSchema = z.record(z.string(), z.record(z.string(), ProviderScalarSchem
1997
2098
  }
1998
2099
  }
1999
2100
  });
2000
- var StaticSchema = z.record(z.string(), ProviderScalarSchema);
2001
- var InputSpecSchema = z.strictObject({
2101
+ var StaticSchema = z2.record(z2.string(), ProviderScalarSchema);
2102
+ var InputSpecSchema = z2.strictObject({
2002
2103
  fields: FieldsSchema,
2003
2104
  values: ValuesSchema.optional(),
2004
2105
  static: StaticSchema.optional()
@@ -2105,16 +2206,16 @@ var ADAPTER_IDS = [
2105
2206
  "higgsfield",
2106
2207
  "xai-video"
2107
2208
  ];
2108
- var ModelTypeSchema = z2.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2109
- var LifecycleSchema = z2.enum(["active", "deprecated", "retired"]);
2110
- var SurfaceSchema = z2.enum(["cowork", "space_builder"]);
2209
+ var ModelTypeSchema = z3.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2210
+ var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
2211
+ var SurfaceSchema = z3.enum(["cowork", "space_builder"]);
2111
2212
  var SURFACES2 = SurfaceSchema.options;
2112
- var ExposureSchema = z2.preprocess(
2213
+ var ExposureSchema = z3.preprocess(
2113
2214
  normalizeExposure,
2114
- z2.array(SurfaceSchema)
2215
+ z3.array(SurfaceSchema)
2115
2216
  );
2116
- var AdapterSchema = z2.enum(ADAPTER_IDS);
2117
- var AspectRatioSchema = z2.enum([
2217
+ var AdapterSchema = z3.enum(ADAPTER_IDS);
2218
+ var AspectRatioSchema = z3.enum([
2118
2219
  "1:1",
2119
2220
  "16:9",
2120
2221
  "9:16",
@@ -2129,12 +2230,12 @@ var AspectRatioSchema = z2.enum([
2129
2230
  "97:30",
2130
2231
  "adaptive"
2131
2232
  ]);
2132
- var ImageSizeSchema = z2.enum(["512", "1K", "2K", "4K"]);
2133
- var VideoResolutionSchema = z2.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2134
- var ImageQualitySchema = z2.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2135
- var OutputFormatSchema = z2.enum(["png", "jpeg", "webp"]);
2136
- var RequiredInputSchema = z2.enum(["firstFrame", "sourceVideo", "references"]);
2137
- var SupportedOptionSchema = z2.enum([
2233
+ var ImageSizeSchema = z3.enum(["512", "1K", "2K", "4K"]);
2234
+ var VideoResolutionSchema = z3.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2235
+ var ImageQualitySchema = z3.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2236
+ var OutputFormatSchema = z3.enum(["png", "jpeg", "webp"]);
2237
+ var RequiredInputSchema = z3.enum(["firstFrame", "sourceVideo", "references"]);
2238
+ var SupportedOptionSchema = z3.enum([
2138
2239
  "seed",
2139
2240
  "quality",
2140
2241
  "negativePrompt",
@@ -2154,142 +2255,147 @@ var SupportedOptionSchema = z2.enum([
2154
2255
  "videoExtension",
2155
2256
  "instrumental"
2156
2257
  ]);
2157
- var UsageUnitSchema = z2.enum([
2258
+ var UsageUnitSchema = z3.enum([
2158
2259
  "tokens",
2159
2260
  "images",
2160
2261
  "seconds",
2161
2262
  "reported_cost_usd",
2162
2263
  "compute_seconds"
2163
2264
  ]);
2164
- var PricingKindSchema = z2.enum(["token", "image_size", "video_per_second", "flat"]);
2165
- var ProviderOptionValueSchema = z2.lazy(
2166
- () => z2.union([
2167
- z2.string(),
2168
- z2.number(),
2169
- z2.boolean(),
2170
- z2.array(ProviderOptionValueSchema),
2171
- z2.record(z2.string(), ProviderOptionValueSchema)
2265
+ var PricingKindSchema = z3.enum(["token", "image_size", "video_per_second", "flat"]);
2266
+ var ProviderOptionValueSchema = z3.lazy(
2267
+ () => z3.union([
2268
+ z3.string(),
2269
+ z3.number(),
2270
+ z3.boolean(),
2271
+ z3.array(ProviderOptionValueSchema),
2272
+ z3.record(z3.string(), ProviderOptionValueSchema)
2172
2273
  ])
2173
2274
  );
2174
- var ProviderOptionsSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderOptionValueSchema));
2175
- var VideoSecondsLimitsSchema = z2.looseObject({
2176
- min: z2.number().optional(),
2177
- max: z2.number().optional(),
2178
- total: z2.number().optional(),
2179
- editMin: z2.number().optional()
2275
+ var ProviderOptionsSchema = z3.record(z3.string(), z3.record(z3.string(), ProviderOptionValueSchema));
2276
+ var VideoSecondsLimitsSchema = z3.looseObject({
2277
+ min: z3.number().optional(),
2278
+ max: z3.number().optional(),
2279
+ total: z3.number().optional(),
2280
+ editMin: z3.number().optional()
2180
2281
  });
2181
- var ReferenceLimitsSchema = z2.looseObject({
2182
- images: z2.number().optional(),
2183
- imagesWithVideo: z2.number().optional(),
2184
- videos: z2.number().optional(),
2185
- audios: z2.number().optional(),
2186
- total: z2.number().optional(),
2187
- audioOnly: z2.boolean().optional(),
2282
+ var ReferenceLimitsSchema = z3.looseObject({
2283
+ images: z3.number().optional(),
2284
+ imagesWithVideo: z3.number().optional(),
2285
+ videos: z3.number().optional(),
2286
+ audios: z3.number().optional(),
2287
+ total: z3.number().optional(),
2288
+ audioOnly: z3.boolean().optional(),
2188
2289
  videoSeconds: VideoSecondsLimitsSchema.optional()
2189
2290
  });
2190
- var ModelConstraintsSchema = z2.looseObject({
2191
- aspectRatios: z2.array(AspectRatioSchema).optional(),
2192
- sizes: z2.array(ImageSizeSchema).optional(),
2193
- resolutions: z2.array(VideoResolutionSchema).optional(),
2194
- durations: z2.union([z2.looseObject({ min: z2.number(), max: z2.number() }), z2.array(z2.number())]).optional(),
2195
- durationPresets: z2.array(z2.number()).optional(),
2196
- qualityOptions: z2.array(z2.string()).optional(),
2197
- exactSizes: z2.record(z2.string(), z2.string()).optional(),
2291
+ var ModelConstraintsSchema = z3.looseObject({
2292
+ aspectRatios: z3.array(AspectRatioSchema).optional(),
2293
+ sizes: z3.array(ImageSizeSchema).optional(),
2294
+ resolutions: z3.array(VideoResolutionSchema).optional(),
2295
+ durations: z3.union([z3.looseObject({ min: z3.number(), max: z3.number() }), z3.array(z3.number())]).optional(),
2296
+ durationPresets: z3.array(z3.number()).optional(),
2297
+ qualityOptions: z3.array(z3.string()).optional(),
2298
+ exactSizes: z3.record(z3.string(), z3.string()).optional(),
2198
2299
  references: ReferenceLimitsSchema.optional(),
2199
- requires: z2.array(RequiredInputSchema).optional(),
2200
- supports: z2.array(SupportedOptionSchema).optional(),
2201
- ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional(),
2202
- sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z2.boolean().optional() }).optional(),
2203
- extension: z2.looseObject({ segmentSeconds: z2.number(), maxTotalSeconds: z2.number() }).optional()
2300
+ requires: z3.array(RequiredInputSchema).optional(),
2301
+ supports: z3.array(SupportedOptionSchema).optional(),
2302
+ ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
2303
+ sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
2304
+ extension: z3.looseObject({ segmentSeconds: z3.number(), maxTotalSeconds: z3.number() }).optional(),
2305
+ // Loose on purpose: the read path keeps a row whose value is invalid (the accessors in
2306
+ // conventions.ts read it as "not set"); CatalogModelSchema below rejects it on write.
2307
+ audio: z3.unknown().optional(),
2308
+ prompt: z3.unknown().optional()
2204
2309
  });
2205
- var MediaRefSchema = z2.union([
2206
- z2.looseObject({
2207
- url: z2.string(),
2208
- label: z2.string().optional(),
2209
- durationSeconds: z2.number().optional()
2310
+ var MediaRefSchema = z3.union([
2311
+ z3.looseObject({
2312
+ url: z3.string(),
2313
+ label: z3.string().optional(),
2314
+ durationSeconds: z3.number().optional()
2210
2315
  }),
2211
- z2.looseObject({
2212
- bytes: z2.instanceof(Uint8Array),
2213
- mime: z2.string(),
2214
- label: z2.string().optional(),
2215
- durationSeconds: z2.number().optional()
2316
+ z3.looseObject({
2317
+ bytes: z3.instanceof(Uint8Array),
2318
+ mime: z3.string(),
2319
+ label: z3.string().optional(),
2320
+ durationSeconds: z3.number().optional()
2216
2321
  })
2217
2322
  ]);
2218
- var ImageSafetySettingSchema = z2.looseObject({ category: z2.string(), threshold: z2.string() });
2219
- var UpscaleOptionsSchema = z2.looseObject({
2220
- enhanceModel: z2.string().optional(),
2221
- subjectDetection: z2.string().optional(),
2222
- faceEnhancement: z2.boolean().optional(),
2223
- faceEnhancementCreativity: z2.number().optional(),
2224
- faceEnhancementStrength: z2.number().optional()
2323
+ var ImageSafetySettingSchema = z3.looseObject({ category: z3.string(), threshold: z3.string() });
2324
+ var UpscaleOptionsSchema = z3.looseObject({
2325
+ enhanceModel: z3.string().optional(),
2326
+ subjectDetection: z3.string().optional(),
2327
+ faceEnhancement: z3.boolean().optional(),
2328
+ faceEnhancementCreativity: z3.number().optional(),
2329
+ faceEnhancementStrength: z3.number().optional()
2225
2330
  });
2226
- var DefaultsSchema = z2.looseObject({
2227
- references: z2.array(MediaRefSchema).optional(),
2331
+ var DefaultsSchema = z3.looseObject({
2332
+ references: z3.array(MediaRefSchema).optional(),
2228
2333
  aspectRatio: AspectRatioSchema.optional(),
2229
2334
  size: ImageSizeSchema.optional(),
2230
- exactSize: z2.string().optional(),
2335
+ exactSize: z3.string().optional(),
2231
2336
  quality: ImageQualitySchema.optional(),
2232
- seed: z2.number().optional(),
2233
- count: z2.number().optional(),
2337
+ seed: z3.number().optional(),
2338
+ count: z3.number().optional(),
2234
2339
  outputFormat: OutputFormatSchema.optional(),
2235
- scaleFactor: z2.number().optional(),
2236
- safetySettings: z2.array(ImageSafetySettingSchema).optional(),
2237
- temperature: z2.number().optional(),
2340
+ scaleFactor: z3.number().optional(),
2341
+ safetySettings: z3.array(ImageSafetySettingSchema).optional(),
2342
+ temperature: z3.number().optional(),
2238
2343
  upscale: UpscaleOptionsSchema.optional(),
2239
2344
  firstFrame: MediaRefSchema.optional(),
2240
2345
  lastFrame: MediaRefSchema.optional(),
2241
2346
  sourceVideo: MediaRefSchema.optional(),
2242
- referenceImages: z2.array(MediaRefSchema).optional(),
2243
- referenceVideos: z2.array(MediaRefSchema).optional(),
2244
- referenceAudios: z2.array(MediaRefSchema).optional(),
2347
+ referenceImages: z3.array(MediaRefSchema).optional(),
2348
+ referenceVideos: z3.array(MediaRefSchema).optional(),
2349
+ referenceAudios: z3.array(MediaRefSchema).optional(),
2245
2350
  resolution: VideoResolutionSchema.optional(),
2246
- durationSeconds: z2.number().optional(),
2247
- generateAudio: z2.boolean().optional(),
2248
- negativePrompt: z2.string().optional(),
2249
- cfgScale: z2.number().optional(),
2250
- promptExpansion: z2.enum(["fast", "balanced", "quality"]).optional(),
2251
- watermark: z2.boolean().optional(),
2252
- safetyChecker: z2.boolean().optional(),
2253
- taskType: z2.enum(["reference", "edit", "extend"]).optional(),
2254
- mode: z2.enum(["standard", "pro"]).optional(),
2255
- instrumental: z2.boolean().optional()
2351
+ durationSeconds: z3.number().optional(),
2352
+ generateAudio: z3.boolean().optional(),
2353
+ negativePrompt: z3.string().optional(),
2354
+ cfgScale: z3.number().optional(),
2355
+ promptExpansion: z3.enum(["fast", "balanced", "quality"]).optional(),
2356
+ watermark: z3.boolean().optional(),
2357
+ safetyChecker: z3.boolean().optional(),
2358
+ taskType: z3.enum(["reference", "edit", "extend"]).optional(),
2359
+ mode: z3.enum(["standard", "pro"]).optional(),
2360
+ instrumental: z3.boolean().optional()
2256
2361
  });
2257
- var CatalogDisplaySchema = z2.looseObject({
2258
- provider: z2.string(),
2259
- description: z2.string(),
2260
- logo: z2.string().optional(),
2261
- costTier: z2.union([z2.literal(1), z2.literal(2), z2.literal(3)]).optional(),
2262
- recommended: z2.boolean().optional(),
2263
- sortOrder: z2.number().optional(),
2264
- chat: z2.looseObject({
2362
+ var CatalogDisplaySchema = z3.looseObject({
2363
+ provider: z3.string(),
2364
+ description: z3.string(),
2365
+ logo: z3.string().optional(),
2366
+ costTier: z3.union([z3.literal(1), z3.literal(2), z3.literal(3)]).optional(),
2367
+ recommended: z3.boolean().optional(),
2368
+ sortOrder: z3.number().optional(),
2369
+ chat: z3.looseObject({
2265
2370
  providerOptions: ProviderOptionsSchema.optional(),
2266
- temperature: z2.number().optional()
2371
+ temperature: z3.number().optional()
2267
2372
  }).optional()
2268
2373
  });
2269
- var CatalogCapabilitiesSchema = z2.looseObject({
2270
- acceptsSourceVideo: z2.boolean().optional(),
2271
- framesExcludeReferences: z2.boolean().optional(),
2272
- reasoning: z2.boolean().optional(),
2273
- vision: z2.boolean().optional(),
2274
- contextWindow: z2.number().optional()
2374
+ var CatalogCapabilitiesSchema = z3.looseObject({
2375
+ acceptsSourceVideo: z3.boolean().optional(),
2376
+ framesExcludeReferences: z3.boolean().optional(),
2377
+ lastFrameRequiresFirstFrame: z3.boolean().optional(),
2378
+ reasoning: z3.boolean().optional(),
2379
+ vision: z3.boolean().optional(),
2380
+ contextWindow: z3.number().optional()
2275
2381
  });
2276
- var CatalogModelSchemaBase = z2.looseObject({
2277
- id: z2.string().min(1),
2278
- aliases: z2.array(z2.string()).default([]),
2279
- label: z2.string().min(1),
2382
+ var CatalogModelSchemaBase = z3.looseObject({
2383
+ id: z3.string().min(1),
2384
+ aliases: z3.array(z3.string()).default([]),
2385
+ label: z3.string().min(1),
2280
2386
  type: ModelTypeSchema,
2281
2387
  adapter: AdapterSchema,
2282
- providerModelId: z2.string().min(1),
2388
+ providerModelId: z3.string().min(1),
2283
2389
  lifecycle: LifecycleSchema,
2284
- replacedBy: z2.string().optional(),
2390
+ replacedBy: z3.string().optional(),
2285
2391
  exposure: ExposureSchema,
2286
2392
  constraints: ModelConstraintsSchema,
2287
2393
  defaults: DefaultsSchema,
2288
2394
  providerOptions: ProviderOptionsSchema.optional(),
2289
- usage: z2.looseObject({
2395
+ usage: z3.looseObject({
2290
2396
  unit: UsageUnitSchema,
2291
- slug: z2.string().optional(),
2292
- providerLabel: z2.string().optional()
2397
+ slug: z3.string().optional(),
2398
+ providerLabel: z3.string().optional()
2293
2399
  }),
2294
2400
  pricingKind: PricingKindSchema,
2295
2401
  display: CatalogDisplaySchema.optional(),
@@ -2340,9 +2446,30 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2340
2446
  }
2341
2447
  }
2342
2448
  }
2449
+ const audio = row.constraints.audio;
2450
+ if (audio !== void 0 && !AudioOutputSchema.safeParse(audio).success) {
2451
+ ctx.addIssue({
2452
+ code: "custom",
2453
+ path: ["constraints", "audio"],
2454
+ message: 'audio must be "always", "optional" or "never"'
2455
+ });
2456
+ }
2457
+ const prompt = row.constraints.prompt;
2458
+ if (prompt !== void 0) {
2459
+ const parsed = PromptConventionsSchema.safeParse(prompt);
2460
+ if (!parsed.success) {
2461
+ for (const issue of parsed.error.issues) {
2462
+ ctx.addIssue({
2463
+ code: "custom",
2464
+ path: ["constraints", "prompt", ...issue.path.map(String)],
2465
+ message: issue.message
2466
+ });
2467
+ }
2468
+ }
2469
+ }
2343
2470
  }
2344
2471
  );
2345
- var CatalogSchema = z2.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2472
+ var CatalogSchema = z3.array(CatalogModelSchemaBase.transform((row) => normaliseConventions(row).row)).superRefine((rows, ctx) => {
2346
2473
  for (const issue of collisionIssues(rows)) {
2347
2474
  ctx.addIssue({
2348
2475
  code: "custom",
@@ -2363,7 +2490,7 @@ import { createXai } from "@ai-sdk/xai";
2363
2490
  import { createDeepSeek } from "@ai-sdk/deepseek";
2364
2491
  import { createMoonshotAI } from "@ai-sdk/moonshotai";
2365
2492
  import { extractReasoningMiddleware, wrapLanguageModel } from "ai";
2366
- import { z as z3 } from "zod";
2493
+ import { z as z4 } from "zod";
2367
2494
  var TEXT_PROVIDERS = [
2368
2495
  "openai",
2369
2496
  "anthropic",
@@ -2374,7 +2501,7 @@ var TEXT_PROVIDERS = [
2374
2501
  "moonshot",
2375
2502
  "minimax"
2376
2503
  ];
2377
- var textProviderSchema = z3.enum(TEXT_PROVIDERS);
2504
+ var textProviderSchema = z4.enum(TEXT_PROVIDERS);
2378
2505
  function isTextProvider(value) {
2379
2506
  return textProviderSchema.safeParse(value).success;
2380
2507
  }
@@ -2667,24 +2794,24 @@ var aiSdkTextAdapter = {
2667
2794
  };
2668
2795
 
2669
2796
  // src/adapters/ark.ts
2670
- import { z as z6 } from "zod";
2797
+ import { z as z7 } from "zod";
2671
2798
 
2672
2799
  // src/retry.ts
2673
- import { z as z5 } from "zod";
2800
+ import { z as z6 } from "zod";
2674
2801
 
2675
2802
  // src/json.ts
2676
- import { z as z4 } from "zod";
2677
- var JsonValueSchema = z4.lazy(
2678
- () => z4.union([
2679
- z4.string(),
2680
- z4.number(),
2681
- z4.boolean(),
2682
- z4.null(),
2683
- z4.array(JsonValueSchema),
2684
- z4.record(z4.string(), JsonValueSchema)
2803
+ import { z as z5 } from "zod";
2804
+ var JsonValueSchema = z5.lazy(
2805
+ () => z5.union([
2806
+ z5.string(),
2807
+ z5.number(),
2808
+ z5.boolean(),
2809
+ z5.null(),
2810
+ z5.array(JsonValueSchema),
2811
+ z5.record(z5.string(), JsonValueSchema)
2685
2812
  ])
2686
2813
  );
2687
- var JsonObjectSchema = z4.record(z4.string(), JsonValueSchema);
2814
+ var JsonObjectSchema = z5.record(z5.string(), JsonValueSchema);
2688
2815
  async function readErrorBody(res) {
2689
2816
  const text2 = await res.text().catch(() => "");
2690
2817
  try {
@@ -2693,11 +2820,11 @@ async function readErrorBody(res) {
2693
2820
  return text2;
2694
2821
  }
2695
2822
  }
2696
- var thrownErrorSchema = z4.object({
2697
- message: z4.string().optional(),
2698
- status: z4.number().optional(),
2699
- statusCode: z4.number().optional(),
2700
- responseBody: z4.string().optional()
2823
+ var thrownErrorSchema = z5.object({
2824
+ message: z5.string().optional(),
2825
+ status: z5.number().optional(),
2826
+ statusCode: z5.number().optional(),
2827
+ responseBody: z5.string().optional()
2701
2828
  });
2702
2829
  function describeThrown(cause) {
2703
2830
  const parsed = thrownErrorSchema.safeParse(cause);
@@ -2708,7 +2835,7 @@ function describeThrown(cause) {
2708
2835
  }
2709
2836
 
2710
2837
  // src/retry.ts
2711
- var textBody = z5.string();
2838
+ var textBody = z6.string();
2712
2839
  function classifyHttpError(status, body, provider, model) {
2713
2840
  const asText = textBody.safeParse(body);
2714
2841
  const text2 = asText.success ? asText.data : JSON.stringify(body);
@@ -2967,7 +3094,7 @@ function arkKey(ctx) {
2967
3094
  return key;
2968
3095
  }
2969
3096
  function throwArkError(status, body, model) {
2970
- const parsed = z6.string().safeParse(body);
3097
+ const parsed = z7.string().safeParse(body);
2971
3098
  const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
2972
3099
  if (/sensitive.?content|human.?face/i.test(text2)) {
2973
3100
  const init = {
@@ -3005,13 +3132,13 @@ function sniffedImageMime(bytes) {
3005
3132
  return "image/webp";
3006
3133
  return "image/jpeg";
3007
3134
  }
3008
- var SeedreamImageSchema = z6.object({
3009
- url: z6.string().optional(),
3010
- b64_json: z6.string().optional()
3135
+ var SeedreamImageSchema = z7.object({
3136
+ url: z7.string().optional(),
3137
+ b64_json: z7.string().optional()
3011
3138
  });
3012
- var SeedreamResponseSchema = z6.object({
3013
- data: z6.array(SeedreamImageSchema).optional(),
3014
- error: z6.object({ message: z6.string().optional(), code: z6.string().optional() }).optional()
3139
+ var SeedreamResponseSchema = z7.object({
3140
+ data: z7.array(SeedreamImageSchema).optional(),
3141
+ error: z7.object({ message: z7.string().optional(), code: z7.string().optional() }).optional()
3015
3142
  });
3016
3143
  function fetchInitFor(ctx, init) {
3017
3144
  if (ctx.signal !== void 0) init.signal = ctx.signal;
@@ -3093,21 +3220,21 @@ async function generateSeedreamImage(req, ctx) {
3093
3220
  if (req.quality !== void 0) usage2.imageQuality = req.quality;
3094
3221
  return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
3095
3222
  }
3096
- var SeedanceUsageSchema = z6.object({
3097
- total_tokens: z6.number().optional(),
3098
- completion_tokens: z6.number().optional()
3223
+ var SeedanceUsageSchema = z7.object({
3224
+ total_tokens: z7.number().optional(),
3225
+ completion_tokens: z7.number().optional()
3099
3226
  });
3100
- var SeedanceResponseSchema = z6.object({
3101
- id: z6.string().optional(),
3102
- status: z6.string().optional(),
3103
- content: z6.object({ video_url: z6.string().optional() }).optional(),
3227
+ var SeedanceResponseSchema = z7.object({
3228
+ id: z7.string().optional(),
3229
+ status: z7.string().optional(),
3230
+ content: z7.object({ video_url: z7.string().optional() }).optional(),
3104
3231
  usage: SeedanceUsageSchema.optional(),
3105
- duration: z6.number().optional(),
3106
- framespersecond: z6.number().optional(),
3107
- resolution: z6.string().optional(),
3108
- error: z6.union([z6.string(), z6.object({ message: z6.string().optional() })]).optional()
3232
+ duration: z7.number().optional(),
3233
+ framespersecond: z7.number().optional(),
3234
+ resolution: z7.string().optional(),
3235
+ error: z7.union([z7.string(), z7.object({ message: z7.string().optional() })]).optional()
3109
3236
  });
3110
- var SeedanceErrorMessageSchema = z6.object({ message: z6.string().optional() });
3237
+ var SeedanceErrorMessageSchema = z7.object({ message: z7.string().optional() });
3111
3238
  function seedanceUsage(ctx, req, duration) {
3112
3239
  const usage2 = {
3113
3240
  model: ctx.model.id,
@@ -3121,7 +3248,7 @@ function seedanceUsage(ctx, req, duration) {
3121
3248
  return usage2;
3122
3249
  }
3123
3250
  function seedanceErrorMessage(error, status) {
3124
- const asString = z6.string().safeParse(error);
3251
+ const asString = z7.string().safeParse(error);
3125
3252
  if (asString.success) return asString.data;
3126
3253
  const asObject = SeedanceErrorMessageSchema.safeParse(error);
3127
3254
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
@@ -3294,18 +3421,18 @@ async function generateSeedanceVideo(req, ctx) {
3294
3421
  }
3295
3422
 
3296
3423
  // src/adapters/fal.ts
3297
- import { z as z8 } from "zod";
3424
+ import { z as z9 } from "zod";
3298
3425
  import { createFalClient } from "@fal-ai/client";
3299
3426
 
3300
3427
  // src/adapters/fal-http.ts
3301
- import { z as z7 } from "zod";
3302
- var queueUrl = z7.url().refine((value) => new URL(value).origin === "https://queue.fal.run");
3303
- var submissionSchema = z7.object({
3304
- request_id: z7.string(),
3428
+ import { z as z8 } from "zod";
3429
+ var queueUrl = z8.url().refine((value) => new URL(value).origin === "https://queue.fal.run");
3430
+ var submissionSchema = z8.object({
3431
+ request_id: z8.string(),
3305
3432
  status_url: queueUrl,
3306
3433
  response_url: queueUrl
3307
3434
  });
3308
- var statusSchema = z7.object({ status: z7.string() });
3435
+ var statusSchema = z8.object({ status: z8.string() });
3309
3436
  function createFalHttpClient(opts) {
3310
3437
  const jobs = /* @__PURE__ */ new Map();
3311
3438
  async function request(url, input, signal) {
@@ -3389,7 +3516,7 @@ var KLING_O1_ENDPOINT = "fal-ai/kling-video/o1/video-to-video/reference";
3389
3516
  var FAL_QUEUE_HOST = "https://queue.fal.run";
3390
3517
  var PASSTHROUGH_POLL_MS = 2e3;
3391
3518
  var PASSTHROUGH_MAX_WAIT_MS = 18e4;
3392
- var falSubscribePayloadSchema = z8.object({ data: JsonValueSchema });
3519
+ var falSubscribePayloadSchema = z9.object({ data: JsonValueSchema });
3393
3520
  function defaultCreateFalClient(opts) {
3394
3521
  if (opts.maxRetries !== void 0)
3395
3522
  return createFalHttpClient({
@@ -3445,7 +3572,7 @@ function createFalAdapter(deps = defaultDeps) {
3445
3572
  };
3446
3573
  }
3447
3574
  var falAdapter = createFalAdapter();
3448
- var falDetailSchema = z8.object({ detail: JsonValueSchema });
3575
+ var falDetailSchema = z9.object({ detail: JsonValueSchema });
3449
3576
  function liftDetail(body) {
3450
3577
  const parsed = falDetailSchema.safeParse(body);
3451
3578
  const detail = parsed.success ? parsed.data.detail : void 0;
@@ -3454,11 +3581,11 @@ function liftDetail(body) {
3454
3581
  function falError(status, body, model) {
3455
3582
  return classifyHttpError(status, liftDetail(body), "fal", model);
3456
3583
  }
3457
- var falSdkThrownSchema = z8.object({
3458
- status: z8.number().optional(),
3459
- statusCode: z8.number().optional(),
3584
+ var falSdkThrownSchema = z9.object({
3585
+ status: z9.number().optional(),
3586
+ statusCode: z9.number().optional(),
3460
3587
  body: JsonValueSchema.optional(),
3461
- message: z8.string().optional()
3588
+ message: z9.string().optional()
3462
3589
  });
3463
3590
  function falSdkError(cause, model) {
3464
3591
  const parsed = falSdkThrownSchema.safeParse(cause);
@@ -3506,12 +3633,12 @@ async function gatewayFetch(cfg, fetchImpl, targetUrl, init) {
3506
3633
  if (init.body !== void 0) request.body = init.body;
3507
3634
  return fetchImpl(cfg.baseUrl, request);
3508
3635
  }
3509
- var falQueueSubmitSchema = z8.object({
3510
- request_id: z8.string(),
3511
- status_url: z8.string(),
3512
- response_url: z8.string()
3636
+ var falQueueSubmitSchema = z9.object({
3637
+ request_id: z9.string(),
3638
+ status_url: z9.string(),
3639
+ response_url: z9.string()
3513
3640
  });
3514
- var falQueueStatusSchema = z8.object({ status: z8.string() });
3641
+ var falQueueStatusSchema = z9.object({ status: z9.string() });
3515
3642
  async function passthroughRequest(ctx, endpoint, input) {
3516
3643
  const cfg = gatewayConfig(ctx);
3517
3644
  const submitRes = await gatewayFetch(cfg, ctx.fetch, `${FAL_QUEUE_HOST}/${endpoint}`, {
@@ -3644,11 +3771,11 @@ async function decodeImage(ctx, url, contentType) {
3644
3771
  const mime = res.headers.get("content-type") ?? contentType ?? "image/png";
3645
3772
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
3646
3773
  }
3647
- var museImageResultSchema = z8.object({
3648
- images: z8.array(
3649
- z8.object({
3650
- url: z8.string().optional(),
3651
- content_type: z8.string().nullable().optional()
3774
+ var museImageResultSchema = z9.object({
3775
+ images: z9.array(
3776
+ z9.object({
3777
+ url: z9.string().optional(),
3778
+ content_type: z9.string().nullable().optional()
3652
3779
  })
3653
3780
  ).optional()
3654
3781
  });
@@ -3752,8 +3879,8 @@ function klingO1Input(req) {
3752
3879
  if (refs.length > 0) input.image_urls = refs;
3753
3880
  return input;
3754
3881
  }
3755
- var falVideoResultSchema = z8.object({
3756
- video: z8.object({ url: z8.string().optional() }).optional()
3882
+ var falVideoResultSchema = z9.object({
3883
+ video: z9.object({ url: z9.string().optional() }).optional()
3757
3884
  });
3758
3885
  function extractVideoUrl(result, endpoint, model) {
3759
3886
  const parsed = falVideoResultSchema.safeParse(result);
@@ -3954,13 +4081,13 @@ async function passthroughVideoJob(ctx, req, endpoint, input) {
3954
4081
  }
3955
4082
 
3956
4083
  // src/adapters/google-genai.ts
3957
- import { z as z10 } from "zod";
4084
+ import { z as z11 } from "zod";
3958
4085
  import {
3959
4086
  GoogleGenAI
3960
4087
  } from "@google/genai";
3961
4088
 
3962
4089
  // src/adapters/google-files.ts
3963
- import { z as z9 } from "zod";
4090
+ import { z as z10 } from "zod";
3964
4091
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
3965
4092
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
3966
4093
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -3970,17 +4097,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
3970
4097
  "binary/octet-stream",
3971
4098
  "application/binary"
3972
4099
  ]);
3973
- var uploadedFileSchema = z9.object({
3974
- file: z9.object({
3975
- uri: z9.string().optional(),
3976
- name: z9.string().optional(),
3977
- state: z9.string().optional(),
3978
- mimeType: z9.string().optional()
4100
+ var uploadedFileSchema = z10.object({
4101
+ file: z10.object({
4102
+ uri: z10.string().optional(),
4103
+ name: z10.string().optional(),
4104
+ state: z10.string().optional(),
4105
+ mimeType: z10.string().optional()
3979
4106
  }).optional()
3980
4107
  });
3981
- var fileStateSchema = z9.object({
3982
- state: z9.string().optional(),
3983
- error: z9.object({ message: z9.string().optional() }).optional()
4108
+ var fileStateSchema = z10.object({
4109
+ state: z10.string().optional(),
4110
+ error: z10.object({ message: z10.string().optional() }).optional()
3984
4111
  });
3985
4112
  function resolveMime(declared, fallback) {
3986
4113
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -4197,7 +4324,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
4197
4324
  var RESULT_TIMEOUT_MS2 = 15 * 60 * 1e3;
4198
4325
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
4199
4326
  var MEDIA_PART_INLINE_LIMIT_BYTES = 20 * 1024 * 1024;
4200
- var errorTextSchema = z10.string();
4327
+ var errorTextSchema = z11.string();
4201
4328
  function isGoogleGenaiVideoKnown(providerModelId) {
4202
4329
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
4203
4330
  }
@@ -4472,7 +4599,12 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4472
4599
  const extend = req.taskType === "extend";
4473
4600
  const previousId = extend ? req.previousInteractionId : void 0;
4474
4601
  const chained = previousId !== void 0;
4475
- for (const field of ["referenceImages", "referenceVideos", "firstFrame"]) {
4602
+ for (const field of [
4603
+ "referenceImages",
4604
+ "referenceVideos",
4605
+ "firstFrame",
4606
+ "lastFrame"
4607
+ ]) {
4476
4608
  const value = req[field];
4477
4609
  if (!chained || value === void 0 || Array.isArray(value) && value.length === 0)
4478
4610
  continue;
@@ -4486,6 +4618,14 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4486
4618
  const images = chained ? [] : req.referenceImages ?? [];
4487
4619
  const videos = chained ? [] : req.referenceVideos ?? [];
4488
4620
  const firstFrame = chained ? void 0 : req.firstFrame;
4621
+ const lastFrame = firstFrame ? req.lastFrame : void 0;
4622
+ if (!chained && req.lastFrame !== void 0 && lastFrame === void 0) {
4623
+ ctx.warnings.push({
4624
+ code: "option_ignored",
4625
+ field: "lastFrame",
4626
+ message: `${modelId} takes an end frame only with a start frame; lastFrame ignored`
4627
+ });
4628
+ }
4489
4629
  if (extend && !chained && req.sourceVideo === void 0) {
4490
4630
  throw new ModelKitError({
4491
4631
  code: "missing_input",
@@ -4570,27 +4710,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4570
4710
  mime_type: media.mime
4571
4711
  });
4572
4712
  }
4573
- if (firstFrame) {
4574
- if (firstFrame.label !== void 0)
4575
- parts.push({ type: "text", text: firstFrame.label });
4576
- const media = await resolveMedia(
4577
- firstFrame,
4578
- ctx.fetch,
4579
- ctx.signal,
4580
- "image/png",
4581
- modelId
4582
- );
4583
- if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
4584
- parts.push({
4585
- type: "image",
4586
- uri: await uploadOne("image", media.bytes, media.mime),
4587
- mime_type: media.mime
4588
- });
4589
- } else {
4590
- parts.push({ type: "image", data: toBase64(media.bytes), mime_type: media.mime });
4591
- }
4592
- }
4593
- for (const ref of images) {
4713
+ const pushImage = async (ref) => {
4594
4714
  if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
4595
4715
  const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
4596
4716
  if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
@@ -4602,8 +4722,12 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4602
4722
  } else {
4603
4723
  parts.push({ type: "image", data: toBase64(media.bytes), mime_type: media.mime });
4604
4724
  }
4605
- }
4606
- parts.push({ type: "text", text: req.prompt });
4725
+ };
4726
+ if (firstFrame) await pushImage(firstFrame);
4727
+ if (lastFrame) await pushImage(lastFrame);
4728
+ for (const ref of images) await pushImage(ref);
4729
+ const prompt = lastFrame ? `<FIRST_FRAME> <LAST_FRAME> ${req.prompt}` : req.prompt;
4730
+ parts.push({ type: "text", text: prompt });
4607
4731
  try {
4608
4732
  interaction = await withRetry(async () => {
4609
4733
  try {
@@ -4806,15 +4930,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
4806
4930
  // src/adapters/google-image.ts
4807
4931
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
4808
4932
  import { generateText } from "ai";
4809
- import { z as z11 } from "zod";
4933
+ import { z as z12 } from "zod";
4810
4934
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
4811
4935
  var defaultGoogleImageDeps = {
4812
4936
  createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
4813
4937
  runTextGeneration: (opts) => generateText(opts)
4814
4938
  };
4815
- var causeChainNodeSchema = z11.object({
4816
- message: z11.string().optional(),
4817
- cause: z11.unknown().optional()
4939
+ var causeChainNodeSchema = z12.object({
4940
+ message: z12.string().optional(),
4941
+ cause: z12.unknown().optional()
4818
4942
  });
4819
4943
  function extractBlockReason(cause) {
4820
4944
  let current = cause;
@@ -4934,7 +5058,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
4934
5058
  var googleImageAdapter = createGoogleImageAdapter();
4935
5059
 
4936
5060
  // src/adapters/higgsfield.ts
4937
- import { z as z12 } from "zod";
5061
+ import { z as z13 } from "zod";
4938
5062
 
4939
5063
  // src/adapters/higgsfield-motions.ts
4940
5064
  var MOTION_MAP = {
@@ -5133,14 +5257,34 @@ function videoUsage3(ctx, req, duration) {
5133
5257
  if (req.durationSeconds !== void 0) event.durationSeconds = req.durationSeconds;
5134
5258
  return event;
5135
5259
  }
5136
- var klingCreateSchema = z12.object({ status_url: z12.string() });
5137
- var klingStatusSchema = z12.object({
5138
- status: z12.string().optional(),
5139
- video: z12.object({ url: z12.string().optional() }).optional(),
5260
+ var KLING_ENDPOINT_FIELDS = /* @__PURE__ */ new Map([
5261
+ [
5262
+ "kling-video/v2.5-turbo/pro/image-to-video",
5263
+ { aspectRatio: false, negativePrompt: true, lastFrame: false, sound: false }
5264
+ ],
5265
+ [
5266
+ "kling-video/v3.0/pro/image-to-video",
5267
+ { aspectRatio: false, negativePrompt: false, lastFrame: true, sound: true }
5268
+ ]
5269
+ ]);
5270
+ var UNLISTED_KLING_FIELDS = {
5271
+ aspectRatio: true,
5272
+ negativePrompt: true,
5273
+ lastFrame: true,
5274
+ sound: false
5275
+ };
5276
+ function klingEndpointFields(providerModelId) {
5277
+ const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
5278
+ return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
5279
+ }
5280
+ var klingCreateSchema = z13.object({ status_url: z13.string() });
5281
+ var klingStatusSchema = z13.object({
5282
+ status: z13.string().optional(),
5283
+ video: z13.object({ url: z13.string().optional() }).optional(),
5140
5284
  error: JsonValueSchema.optional()
5141
5285
  });
5142
- var errorMessageSchema = z12.object({ message: z12.string().optional() });
5143
- var textValueSchema = z12.string();
5286
+ var errorMessageSchema = z13.object({ message: z13.string().optional() });
5287
+ var textValueSchema = z13.string();
5144
5288
  function klingErrorDetail(error) {
5145
5289
  if (error === void 0) return "unknown_error";
5146
5290
  const asText = textValueSchema.safeParse(error);
@@ -5167,6 +5311,13 @@ async function createRequest(ctx, url, init) {
5167
5311
  }
5168
5312
  return res;
5169
5313
  }
5314
+ function ignoreKlingField(ctx, field) {
5315
+ ctx.warnings.push({
5316
+ code: "option_ignored",
5317
+ field,
5318
+ message: `${ctx.model.id}: the Higgsfield endpoint has no ${field} input; ignored`
5319
+ });
5320
+ }
5170
5321
  async function generateKlingVideo(req, ctx) {
5171
5322
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
5172
5323
  if (!firstFrame) {
@@ -5178,16 +5329,29 @@ async function generateKlingVideo(req, ctx) {
5178
5329
  retryable: false
5179
5330
  });
5180
5331
  }
5332
+ const fields = klingEndpointFields(ctx.model.providerModelId);
5181
5333
  const body = {
5182
5334
  prompt: req.prompt.trim(),
5183
5335
  image_url: firstFrame,
5184
- cfg_scale: req.cfgScale ?? 0.5,
5185
- negative_prompt: req.negativePrompt ?? DEFAULT_NEGATIVE_PROMPT
5336
+ cfg_scale: req.cfgScale ?? 0.5
5186
5337
  };
5338
+ if (fields.negativePrompt) {
5339
+ body.negative_prompt = req.negativePrompt ?? DEFAULT_NEGATIVE_PROMPT;
5340
+ } else if (req.negativePrompt !== void 0) {
5341
+ ignoreKlingField(ctx, "negativePrompt");
5342
+ }
5187
5343
  if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
5188
- if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
5189
- body.aspect_ratio = req.aspectRatio;
5190
- if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
5344
+ if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
5345
+ if (fields.aspectRatio) body.aspect_ratio = req.aspectRatio;
5346
+ else ignoreKlingField(ctx, "aspectRatio");
5347
+ }
5348
+ if (req.lastFrame) {
5349
+ if (fields.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
5350
+ else ignoreKlingField(ctx, "lastFrame");
5351
+ }
5352
+ if (fields.sound && req.generateAudio !== void 0) {
5353
+ body.sound = req.generateAudio ? "on" : "off";
5354
+ }
5191
5355
  const endpoint = klingEndpoint(ctx.model.providerModelId, ctx.model.id);
5192
5356
  const retryOptions = mediaRetryOptions(ctx.call, ctx.signal);
5193
5357
  const createRes = await withRetry(
@@ -5276,8 +5440,8 @@ async function generateKlingVideo(req, ctx) {
5276
5440
  }
5277
5441
  };
5278
5442
  }
5279
- var dopMotionOptionsSchema = z12.object({
5280
- modelkit: z12.object({ motion: z12.string().optional() }).optional()
5443
+ var dopMotionOptionsSchema = z13.object({
5444
+ modelkit: z13.object({ motion: z13.string().optional() }).optional()
5281
5445
  });
5282
5446
  function dopMotionId(ctx) {
5283
5447
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -5293,7 +5457,7 @@ function dopMotionId(ctx) {
5293
5457
  });
5294
5458
  return id;
5295
5459
  }
5296
- var jsonRecordSchema = z12.record(z12.string(), JsonValueSchema);
5460
+ var jsonRecordSchema = z13.record(z13.string(), JsonValueSchema);
5297
5461
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
5298
5462
  var DOP_NESTED_KEYS = ["video", "result", "results"];
5299
5463
  function dopUrl(body) {
@@ -5321,8 +5485,8 @@ function dopUrl(body) {
5321
5485
  }
5322
5486
  return void 0;
5323
5487
  }
5324
- var dopCreateSchema = z12.object({ id: z12.string() });
5325
- var dopStatusSchema = z12.object({ status: z12.string().optional() });
5488
+ var dopCreateSchema = z13.object({ id: z13.string() });
5489
+ var dopStatusSchema = z13.object({ status: z13.string().optional() });
5326
5490
  async function generateDopVideo(req, ctx) {
5327
5491
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
5328
5492
  if (!firstFrame) {
@@ -5450,7 +5614,7 @@ var higgsfieldAdapter = {
5450
5614
 
5451
5615
  // src/adapters/openai-image.ts
5452
5616
  import OpenAI from "openai";
5453
- import { z as z13 } from "zod";
5617
+ import { z as z14 } from "zod";
5454
5618
  var MAX_EDIT_REFERENCES = 16;
5455
5619
  function aspectRatioToSize(ratio, tier) {
5456
5620
  const TIER_LONG_EDGE = {
@@ -5533,9 +5697,9 @@ function toProviderError2(cause, ctx) {
5533
5697
  ctx.model.id
5534
5698
  );
5535
5699
  }
5536
- var openaiUsageSchema = z13.object({
5537
- input_tokens: z13.number().optional(),
5538
- output_tokens: z13.number().optional()
5700
+ var openaiUsageSchema = z14.object({
5701
+ input_tokens: z14.number().optional(),
5702
+ output_tokens: z14.number().optional()
5539
5703
  });
5540
5704
  var openaiImageAdapter = {
5541
5705
  id: "openai-image",
@@ -5946,13 +6110,13 @@ var prodiaAdapter = {
5946
6110
  import Replicate from "replicate";
5947
6111
 
5948
6112
  // src/adapters/replicate-http.ts
5949
- import { z as z14 } from "zod";
5950
- var predictionSchema = z14.object({
5951
- id: z14.string(),
5952
- status: z14.string(),
6113
+ import { z as z15 } from "zod";
6114
+ var predictionSchema = z15.object({
6115
+ id: z15.string(),
6116
+ status: z15.string(),
5953
6117
  output: JsonValueSchema.optional(),
5954
6118
  error: JsonValueSchema.optional(),
5955
- metrics: z14.object({ predict_time: z14.number().optional() }).optional()
6119
+ metrics: z15.object({ predict_time: z15.number().optional() }).optional()
5956
6120
  });
5957
6121
  function createReplicateHttpClient(opts) {
5958
6122
  async function request(path, body, signal) {
@@ -6003,7 +6167,7 @@ function createReplicateHttpClient(opts) {
6003
6167
  }
6004
6168
 
6005
6169
  // src/adapters/replicate.ts
6006
- import { z as z15 } from "zod";
6170
+ import { z as z16 } from "zod";
6007
6171
 
6008
6172
  // src/adapters/input-spec-mapper.ts
6009
6173
  function canonicalValue(req, key) {
@@ -6078,8 +6242,8 @@ function route(providerModelId) {
6078
6242
  if (!providerModelId.includes("/")) return { version: providerModelId };
6079
6243
  return { model: providerModelId };
6080
6244
  }
6081
- var replicateResponseStatusSchema = z15.object({
6082
- response: z15.object({ status: z15.number() }).partial()
6245
+ var replicateResponseStatusSchema = z16.object({
6246
+ response: z16.object({ status: z16.number() }).partial()
6083
6247
  });
6084
6248
  function replicateError(cause, ctx) {
6085
6249
  if (isModelKitError(cause)) return cause;
@@ -6106,7 +6270,7 @@ function isUrlFn(value) {
6106
6270
  function extractOutputUrl(output) {
6107
6271
  const root = Array.isArray(output) ? output[0] : output;
6108
6272
  if (root === void 0) throw noOutput();
6109
- const asString = z15.string().safeParse(root);
6273
+ const asString = z16.string().safeParse(root);
6110
6274
  if (asString.success && asString.data) return asString.data;
6111
6275
  if (root instanceof URL) return root.href;
6112
6276
  if (isObjectOutput(root)) {
@@ -6115,15 +6279,15 @@ function extractOutputUrl(output) {
6115
6279
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
6116
6280
  const called = urlValue();
6117
6281
  if (called instanceof URL) return called.href;
6118
- const calledString = z15.string().safeParse(called);
6282
+ const calledString = z16.string().safeParse(called);
6119
6283
  if (calledString.success && calledString.data) return calledString.data;
6120
6284
  } else {
6121
- const direct = z15.string().safeParse(urlValue);
6285
+ const direct = z16.string().safeParse(urlValue);
6122
6286
  if (direct.success && direct.data) return direct.data;
6123
6287
  }
6124
6288
  }
6125
6289
  if ("default" in root) {
6126
- const fallback = z15.string().safeParse(root.default);
6290
+ const fallback = z16.string().safeParse(root.default);
6127
6291
  if (fallback.success && fallback.data) return fallback.data;
6128
6292
  }
6129
6293
  }
@@ -6184,7 +6348,7 @@ async function runPrediction(ctx, input, deps) {
6184
6348
  }
6185
6349
  return void 0;
6186
6350
  }, pollOpts);
6187
- const predictTime = z15.number().safeParse(done.metrics?.predict_time);
6351
+ const predictTime = z16.number().safeParse(done.metrics?.predict_time);
6188
6352
  if (done.output === void 0) throw noOutput();
6189
6353
  return {
6190
6354
  url: extractOutputUrl(done.output),
@@ -6489,24 +6653,22 @@ function klingInput(req) {
6489
6653
  return input;
6490
6654
  }
6491
6655
  function klingOmniMode(req) {
6656
+ if (req.resolution === "4k") return "4k";
6492
6657
  if (req.resolution === "1080p") return "pro";
6493
6658
  if (req.resolution === "720p") return "standard";
6494
6659
  return req.mode ?? "standard";
6495
6660
  }
6496
6661
  function klingOmniInput(req) {
6497
- const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
6498
- if (req.lastFrame) images.push(refToUrl(req.lastFrame));
6499
6662
  const input = {
6500
6663
  prompt: req.prompt,
6501
6664
  duration: req.durationSeconds ?? 10,
6502
6665
  mode: klingOmniMode(req),
6503
6666
  generate_audio: req.generateAudio ?? false
6504
6667
  };
6505
- const startImage = images[0];
6506
- if (startImage !== void 0) {
6507
- input.start_image = startImage;
6508
- const endImage = images[1];
6509
- if (endImage !== void 0) input.end_image = endImage;
6668
+ const start = req.firstFrame ?? req.lastFrame;
6669
+ if (start) {
6670
+ input.start_image = refToUrl(start);
6671
+ if (req.firstFrame && req.lastFrame) input.end_image = refToUrl(req.lastFrame);
6510
6672
  } else if (req.aspectRatio !== "adaptive") {
6511
6673
  input.aspect_ratio = req.aspectRatio ?? "16:9";
6512
6674
  }
@@ -6569,7 +6731,7 @@ async function generateReplicateVideo(req, ctx, deps) {
6569
6731
  throw replicateError(cause, ctx);
6570
6732
  }
6571
6733
  if (current.status === "succeeded") {
6572
- const predictTime = z15.number().safeParse(current.metrics?.predict_time);
6734
+ const predictTime = z16.number().safeParse(current.metrics?.predict_time);
6573
6735
  if (current.output === void 0) throw noOutput();
6574
6736
  return {
6575
6737
  url: extractOutputUrl(current.output),
@@ -6710,7 +6872,7 @@ async function generateReplicateAudio(req, ctx, deps) {
6710
6872
  // src/adapters/xai-video.ts
6711
6873
  import { experimental_generateVideo } from "ai";
6712
6874
  import { createXai as createXai2 } from "@ai-sdk/xai";
6713
- import { z as z16 } from "zod";
6875
+ import { z as z17 } from "zod";
6714
6876
  var POLL_INTERVAL_MS2 = 1e4;
6715
6877
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
6716
6878
  var defaultXaiDeps = {
@@ -6723,8 +6885,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
6723
6885
  };
6724
6886
  }
6725
6887
  var xaiVideoAdapter = createXaiVideoAdapter();
6726
- var xaiResponseStatusSchema = z16.object({
6727
- response: z16.object({ status: z16.number() }).partial()
6888
+ var xaiResponseStatusSchema = z17.object({
6889
+ response: z17.object({ status: z17.number() }).partial()
6728
6890
  });
6729
6891
  function xaiError(cause, ctx) {
6730
6892
  const info = describeThrown(cause);
@@ -6732,12 +6894,12 @@ function xaiError(cause, ctx) {
6732
6894
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
6733
6895
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
6734
6896
  }
6735
- var xaiMetaSchema = z16.object({
6897
+ var xaiMetaSchema = z17.object({
6736
6898
  videoUrl: JsonValueSchema.optional(),
6737
6899
  costInUsdTicks: JsonValueSchema.optional(),
6738
6900
  duration: JsonValueSchema.optional()
6739
6901
  });
6740
- var xaiProviderMetadataSchema = z16.object({ xai: xaiMetaSchema });
6902
+ var xaiProviderMetadataSchema = z17.object({ xai: xaiMetaSchema });
6741
6903
  function metaOf(result) {
6742
6904
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
6743
6905
  if (!parsed.success) return {};
@@ -6754,7 +6916,7 @@ async function generateXaiVideo(req, ctx, deps) {
6754
6916
  retryable: false
6755
6917
  });
6756
6918
  }
6757
- const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 5);
6919
+ const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
6758
6920
  const xaiOptions = {
6759
6921
  pollIntervalMs: POLL_INTERVAL_MS2,
6760
6922
  pollTimeoutMs: POLL_TIMEOUT_MS2
@@ -6845,7 +7007,7 @@ async function mapResult(ctx, req, result) {
6845
7007
  };
6846
7008
  }
6847
7009
  const meta = metaOf(result);
6848
- const videoUrl = z16.string().safeParse(meta.videoUrl);
7010
+ const videoUrl = z17.string().safeParse(meta.videoUrl);
6849
7011
  if (videoUrl.success && videoUrl.data) {
6850
7012
  const res = await ctx.fetch(videoUrl.data);
6851
7013
  if (!res.ok) {
@@ -6868,7 +7030,7 @@ async function mapResult(ctx, req, result) {
6868
7030
  });
6869
7031
  }
6870
7032
  function usage(ctx, req, meta) {
6871
- const costTicks = z16.number().safeParse(meta.costInUsdTicks);
7033
+ const costTicks = z17.number().safeParse(meta.costInUsdTicks);
6872
7034
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
6873
7035
  const event = {
6874
7036
  model: ctx.model.id,
@@ -7001,22 +7163,22 @@ var liveState = store[KEY] ??= {
7001
7163
  var liveCatalog = liveState.catalog;
7002
7164
 
7003
7165
  // src/catalog/load.ts
7004
- import { z as z17 } from "zod";
7166
+ import { z as z18 } from "zod";
7005
7167
  function rowCount() {
7006
7168
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
7007
7169
  }
7008
7170
  function authHeaders(auth) {
7009
7171
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
7010
7172
  }
7011
- var EnvelopeSchema = z17.object({
7012
- rows: z17.array(JsonValueSchema),
7013
- revision: z17.string().optional()
7173
+ var EnvelopeSchema = z18.object({
7174
+ rows: z18.array(JsonValueSchema),
7175
+ revision: z18.string().optional()
7014
7176
  });
7015
7177
  function dropReason(path, message) {
7016
7178
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
7017
7179
  }
7018
7180
  function rowId(raw) {
7019
- const parsed = z17.object({ id: z17.string().min(1) }).loose().safeParse(raw);
7181
+ const parsed = z18.object({ id: z18.string().min(1) }).loose().safeParse(raw);
7020
7182
  if (!parsed.success) return "?";
7021
7183
  return parsed.data.id;
7022
7184
  }
@@ -7044,7 +7206,13 @@ function quarantine(rawRows, logger) {
7044
7206
  );
7045
7207
  }
7046
7208
  }
7047
- valid.push(row);
7209
+ const normalised = normaliseConventions(row);
7210
+ if (normalised.invalidKeys.length > 0) {
7211
+ logger.warn(
7212
+ `[modelkit] catalog row ${row.id} has an invalid ${normalised.invalidKeys.join(", ")}; read as not set`
7213
+ );
7214
+ }
7215
+ valid.push(normalised.row);
7048
7216
  }
7049
7217
  let kept = valid;
7050
7218
  for (; ; ) {
@@ -7462,6 +7630,24 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
7462
7630
  });
7463
7631
  delete merged.sourceVideo;
7464
7632
  }
7633
+ if (merged.lastFrame !== void 0 && merged.firstFrame === void 0 && model.capabilities?.lastFrameRequiresFirstFrame) {
7634
+ if (onUnsupported === "error") {
7635
+ throw new ModelKitError({
7636
+ code: "missing_input",
7637
+ message: `${model.id} takes an end frame only together with a start frame`,
7638
+ model: model.id,
7639
+ retryable: false
7640
+ });
7641
+ }
7642
+ warnings.push({
7643
+ code: "option_ignored",
7644
+ field: "lastFrame",
7645
+ to: "firstFrame",
7646
+ message: `end frame used as start frame: ${model.id} needs a start frame with an end frame`
7647
+ });
7648
+ merged.firstFrame = merged.lastFrame;
7649
+ delete merged.lastFrame;
7650
+ }
7465
7651
  const hasFrames = merged.firstFrame !== void 0 || merged.lastFrame !== void 0;
7466
7652
  const hasRefs = compact(merged.referenceImages).length + compact(merged.referenceVideos).length + compact(merged.referenceAudios).length > 0;
7467
7653
  if (hasFrames && hasRefs && model.capabilities?.framesExcludeReferences) {
@@ -7844,7 +8030,7 @@ import {
7844
8030
  streamObject as aiStreamObject2,
7845
8031
  streamText as aiStreamText2
7846
8032
  } from "ai";
7847
- import { z as z18 } from "zod";
8033
+ import { z as z19 } from "zod";
7848
8034
 
7849
8035
  // src/generated-image.ts
7850
8036
  function toGeneratedImage(image) {
@@ -7919,10 +8105,10 @@ function textAbortOptions(sdk, context) {
7919
8105
  if (abortSignal) return { abortSignal };
7920
8106
  return {};
7921
8107
  }
7922
- var catalogId = z18.string();
7923
- var exactSize = z18.templateLiteral([z18.number(), "x", z18.number()]);
7924
- var sdkRatio = z18.templateLiteral([z18.number(), ":", z18.number()]);
7925
- var sizeTier = z18.enum(["512", "1K", "2K", "4K"]);
8108
+ var catalogId = z19.string();
8109
+ var exactSize = z19.templateLiteral([z19.number(), "x", z19.number()]);
8110
+ var sdkRatio = z19.templateLiteral([z19.number(), ":", z19.number()]);
8111
+ var sizeTier = z19.enum(["512", "1K", "2K", "4K"]);
7926
8112
  function isCatalogId(model) {
7927
8113
  return catalogId.safeParse(model).success;
7928
8114
  }