@shop-os/modelkit 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -70,6 +70,7 @@ __export(index_exports, {
70
70
  falAdapter: () => falAdapter,
71
71
  falWebhookBodySchema: () => falWebhookBodySchema,
72
72
  fileCatalogCache: () => fileCatalogCache,
73
+ fishAdapter: () => fishAdapter,
73
74
  generateAudio: () => generateAudio,
74
75
  generateImage: () => generateImage,
75
76
  generateObject: () => generateObject,
@@ -122,6 +123,8 @@ __export(index_exports, {
122
123
  resolveTranscriptionOptions: () => resolveTranscriptionOptions,
123
124
  resolveVideoOptions: () => resolveVideoOptions,
124
125
  resolveVoiceChangeOptions: () => resolveVoiceChangeOptions,
126
+ resolveVoiceCloneOptions: () => resolveVoiceCloneOptions,
127
+ resolveVoiceDesignOptions: () => resolveVoiceDesignOptions,
125
128
  shouldRetry: () => shouldRetry,
126
129
  sleep: () => sleep,
127
130
  sortCatalogRows: () => sortCatalogRows,
@@ -1368,6 +1371,303 @@ var VEED_SUBTITLES = {
1368
1371
  }
1369
1372
  };
1370
1373
 
1374
+ // src/catalog/voices-fish.ts
1375
+ var FISH_VOICES = [
1376
+ {
1377
+ id: "933563129e564b19a115bedd57b7406a",
1378
+ name: "Sarah",
1379
+ gender: "female",
1380
+ languages: ["en"],
1381
+ description: "An engaged speaker.",
1382
+ previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
1383
+ },
1384
+ {
1385
+ id: "bf322df2096a46f18c579d0baa36f41d",
1386
+ name: "Adrian",
1387
+ gender: "male",
1388
+ languages: ["en"],
1389
+ description: "A steady and reliable narrator.",
1390
+ previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
1391
+ },
1392
+ {
1393
+ id: "536d3a5e000945adb7038665781a4aca",
1394
+ name: "Ethan",
1395
+ gender: "male",
1396
+ languages: ["en"],
1397
+ description: "A curious explainer.",
1398
+ previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
1399
+ },
1400
+ {
1401
+ id: "b347db033a6549378b48d00acb0d06cd",
1402
+ name: "Selene",
1403
+ gender: "female",
1404
+ languages: ["en"],
1405
+ description: "A meditative female voice.",
1406
+ previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
1407
+ },
1408
+ {
1409
+ id: "9a9cf47702da476aa4629e2506d4a857",
1410
+ name: "Hannah",
1411
+ gender: "female",
1412
+ languages: ["en"],
1413
+ description: "A conversation specialist.",
1414
+ previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
1415
+ },
1416
+ {
1417
+ id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
1418
+ name: "Jordan",
1419
+ gender: "male",
1420
+ languages: ["en"],
1421
+ description: "A motivational speaker.",
1422
+ previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
1423
+ },
1424
+ {
1425
+ id: "e3cd384158934cc9a01029cd7d278634",
1426
+ name: "Laura",
1427
+ gender: "female",
1428
+ languages: ["en"],
1429
+ description: "A confident female narrator.",
1430
+ previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
1431
+ },
1432
+ {
1433
+ id: "f3a2b90078d54a65af4b95f63bc7798e",
1434
+ name: "Sheila",
1435
+ gender: "female",
1436
+ accent: "american",
1437
+ languages: ["en"],
1438
+ description: "A young American English woman's voice.",
1439
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
1440
+ },
1441
+ {
1442
+ id: "0db6e93af420470b9d9b9a886dbaa954",
1443
+ name: "Kai",
1444
+ gender: "male",
1445
+ languages: ["en"],
1446
+ description: "A friendly English man's voice for companion apps and everyday conversation.",
1447
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
1448
+ },
1449
+ {
1450
+ id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
1451
+ name: "Freya",
1452
+ gender: "female",
1453
+ accent: "british",
1454
+ languages: ["en"],
1455
+ description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
1456
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
1457
+ },
1458
+ {
1459
+ id: "2f64e528a4f2406691925ab1e0ed5b7f",
1460
+ name: "Ananya",
1461
+ gender: "female",
1462
+ languages: ["hi"],
1463
+ description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
1464
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
1465
+ },
1466
+ {
1467
+ id: "cefd91a07b99468f9148e2580990082d",
1468
+ name: "Arjun",
1469
+ gender: "male",
1470
+ languages: ["hi"],
1471
+ description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
1472
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
1473
+ },
1474
+ {
1475
+ id: "3f065d660212478a9c697fa965b4d098",
1476
+ name: "Carmen",
1477
+ gender: "female",
1478
+ languages: ["es"],
1479
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1480
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
1481
+ },
1482
+ {
1483
+ id: "ec0718028a2445fb9be8e8bfb56a0150",
1484
+ name: "Rodrigo",
1485
+ gender: "male",
1486
+ languages: ["es"],
1487
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1488
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
1489
+ },
1490
+ {
1491
+ id: "10a3a20742114a4ea6dd441e7591850f",
1492
+ name: "Manon",
1493
+ gender: "female",
1494
+ languages: ["fr"],
1495
+ description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
1496
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
1497
+ },
1498
+ {
1499
+ id: "f69bca092b674168a8d02d61ca20943c",
1500
+ name: "Lucas",
1501
+ gender: "male",
1502
+ languages: ["fr"],
1503
+ description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
1504
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
1505
+ },
1506
+ {
1507
+ id: "3937b44b604249f18b94913daef94043",
1508
+ name: "Lena",
1509
+ gender: "female",
1510
+ languages: ["de"],
1511
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1512
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
1513
+ },
1514
+ {
1515
+ id: "c1e7cc926aa5469aa966c353094d4b0b",
1516
+ name: "Lukas",
1517
+ gender: "male",
1518
+ languages: ["de"],
1519
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1520
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
1521
+ },
1522
+ {
1523
+ id: "b3c060cc41544a7da94a2c487647c902",
1524
+ name: "Let\xEDcia",
1525
+ gender: "female",
1526
+ accent: "brazilian",
1527
+ languages: ["pt"],
1528
+ description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
1529
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
1530
+ },
1531
+ {
1532
+ id: "add7bcb8d3c8423bbfa152ca232aad6e",
1533
+ name: "Ricardo",
1534
+ gender: "male",
1535
+ accent: "brazilian",
1536
+ languages: ["pt"],
1537
+ description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
1538
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
1539
+ },
1540
+ {
1541
+ id: "b2d9d8db057042688a5e318b8f405bc2",
1542
+ name: "Kyoko",
1543
+ gender: "female",
1544
+ languages: ["ja"],
1545
+ description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
1546
+ previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
1547
+ },
1548
+ {
1549
+ id: "297a6fd278df47c3b9da9bfdf55ac89a",
1550
+ name: "Satoru",
1551
+ gender: "male",
1552
+ languages: ["ja"],
1553
+ description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
1554
+ previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
1555
+ },
1556
+ {
1557
+ id: "0b14f34a13a94ed88fe6113193749bb0",
1558
+ name: "Fatima",
1559
+ gender: "female",
1560
+ languages: ["ar"],
1561
+ description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
1562
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
1563
+ },
1564
+ {
1565
+ id: "74c6aba5cbf94a15bbdc547ffce5cb38",
1566
+ name: "Yutong",
1567
+ gender: "female",
1568
+ languages: ["zh"],
1569
+ description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
1570
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
1571
+ }
1572
+ ];
1573
+
1574
+ // src/catalog/speech-fish.ts
1575
+ var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
1576
+ var PER_CALL = { unit: "images" };
1577
+ var PER_REQUEST = { unit: "requests" };
1578
+ var TTS_MAX_CHARS = 1e4;
1579
+ function fishTts(id, label, providerModelId, description) {
1580
+ return {
1581
+ id,
1582
+ aliases: [],
1583
+ label,
1584
+ type: "speech",
1585
+ adapter: "fish",
1586
+ providerModelId,
1587
+ lifecycle: "active",
1588
+ exposure: [],
1589
+ constraints: {
1590
+ voices: FISH_VOICES,
1591
+ outputFormats: ["mp3", "wav"],
1592
+ supports: [],
1593
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
1594
+ },
1595
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
1596
+ usage: PER_CALL,
1597
+ pricingKind: "flat",
1598
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
1599
+ capabilities: { customVoices: true }
1600
+ };
1601
+ }
1602
+ var FISH_MODELS = [
1603
+ fishTts(
1604
+ "fish-s2.1-pro",
1605
+ "Fish Audio S2.1 Pro",
1606
+ "s2.1-pro",
1607
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
1608
+ ),
1609
+ fishTts(
1610
+ "fish-s2.1-pro-free",
1611
+ "Fish Audio S2.1 Pro Free",
1612
+ "s2.1-pro-free",
1613
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
1614
+ ),
1615
+ fishTts(
1616
+ "fish-drama-3",
1617
+ "Fish Audio Drama 3",
1618
+ "drama-3",
1619
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
1620
+ ),
1621
+ {
1622
+ id: "fish-voice-clone",
1623
+ aliases: [],
1624
+ label: "Fish Audio Voice Clone",
1625
+ type: "voice-clone",
1626
+ adapter: "fish",
1627
+ providerModelId: "voice-clone",
1628
+ lifecycle: "active",
1629
+ exposure: [],
1630
+ constraints: {
1631
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
1632
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
1633
+ supports: []
1634
+ },
1635
+ defaults: {},
1636
+ usage: PER_REQUEST,
1637
+ pricingKind: "flat",
1638
+ display: {
1639
+ provider: "fishaudio",
1640
+ logo: FISH_LOGO,
1641
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
1642
+ },
1643
+ capabilities: {}
1644
+ },
1645
+ {
1646
+ id: "fish-voice-design-1",
1647
+ aliases: [],
1648
+ label: "Fish Audio Voice Design",
1649
+ type: "voice-design",
1650
+ adapter: "fish",
1651
+ providerModelId: "voice-design-1",
1652
+ lifecycle: "active",
1653
+ exposure: [],
1654
+ constraints: {
1655
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
1656
+ supports: [],
1657
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
1658
+ },
1659
+ defaults: {},
1660
+ usage: PER_REQUEST,
1661
+ pricingKind: "flat",
1662
+ display: {
1663
+ provider: "fishaudio",
1664
+ logo: FISH_LOGO,
1665
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
1666
+ },
1667
+ capabilities: {}
1668
+ }
1669
+ ];
1670
+
1371
1671
  // src/catalog/languages-audio.ts
1372
1672
  var ELEVENLABS_V4_LANGUAGES = [
1373
1673
  { code: "af", name: "Afrikaans" },
@@ -3449,7 +3749,7 @@ var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.
3449
3749
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3450
3750
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3451
3751
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3452
- var PER_CALL = { unit: "images" };
3752
+ var PER_CALL2 = { unit: "images" };
3453
3753
  var EXPOSURE4 = ["cowork", "space_builder"];
3454
3754
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3455
3755
  function elevenLabsTts(tts) {
@@ -3470,7 +3770,7 @@ function elevenLabsTts(tts) {
3470
3770
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3471
3771
  },
3472
3772
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3473
- usage: PER_CALL,
3773
+ usage: PER_CALL2,
3474
3774
  pricingKind: "flat",
3475
3775
  display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3476
3776
  capabilities: {}
@@ -3494,7 +3794,7 @@ function geminiTts(id, label, description) {
3494
3794
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3495
3795
  },
3496
3796
  defaults: { voice: "Kore" },
3497
- usage: PER_CALL,
3797
+ usage: PER_CALL2,
3498
3798
  pricingKind: "flat",
3499
3799
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3500
3800
  capabilities: {}
@@ -3517,7 +3817,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3517
3817
  },
3518
3818
  defaults: {},
3519
3819
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3520
- usage: PER_CALL,
3820
+ usage: PER_CALL2,
3521
3821
  pricingKind: "flat",
3522
3822
  display: { provider: "sync", logo: SYNC_LOGO, description },
3523
3823
  capabilities: { acceptsSourceVideo: true }
@@ -3578,7 +3878,7 @@ var MEDIA_NODE_MODELS = [
3578
3878
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3579
3879
  },
3580
3880
  defaults: { voice: "Wise_Woman" },
3581
- usage: PER_CALL,
3881
+ usage: PER_CALL2,
3582
3882
  pricingKind: "flat",
3583
3883
  display: {
3584
3884
  provider: "minimax",
@@ -3605,7 +3905,7 @@ var MEDIA_NODE_MODELS = [
3605
3905
  supports: []
3606
3906
  },
3607
3907
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3608
- usage: PER_CALL,
3908
+ usage: PER_CALL2,
3609
3909
  pricingKind: "flat",
3610
3910
  display: {
3611
3911
  provider: "elevenlabs",
@@ -3632,7 +3932,7 @@ var MEDIA_NODE_MODELS = [
3632
3932
  supports: []
3633
3933
  },
3634
3934
  defaults: {},
3635
- usage: PER_CALL,
3935
+ usage: PER_CALL2,
3636
3936
  pricingKind: "flat",
3637
3937
  display: {
3638
3938
  provider: "elevenlabs",
@@ -3679,7 +3979,7 @@ var MEDIA_NODE_MODELS = [
3679
3979
  supports: []
3680
3980
  },
3681
3981
  defaults: {},
3682
- usage: PER_CALL,
3982
+ usage: PER_CALL2,
3683
3983
  pricingKind: "flat",
3684
3984
  display: {
3685
3985
  provider: "veed",
@@ -3731,7 +4031,7 @@ var MEDIA_NODE_MODELS = [
3731
4031
  supports: []
3732
4032
  },
3733
4033
  defaults: {},
3734
- usage: PER_CALL,
4034
+ usage: PER_CALL2,
3735
4035
  pricingKind: "flat",
3736
4036
  display: {
3737
4037
  provider: "elevenlabs",
@@ -3740,7 +4040,8 @@ var MEDIA_NODE_MODELS = [
3740
4040
  },
3741
4041
  capabilities: {}
3742
4042
  },
3743
- SAM_3_IMAGE
4043
+ SAM_3_IMAGE,
4044
+ ...FISH_MODELS
3744
4045
  ];
3745
4046
 
3746
4047
  // src/catalog/model3d.ts
@@ -7375,7 +7676,8 @@ var ADAPTER_IDS = [
7375
7676
  "prodia",
7376
7677
  "higgsfield",
7377
7678
  "xai-video",
7378
- "luma"
7679
+ "luma",
7680
+ "fish"
7379
7681
  ];
7380
7682
  var ModelTypeSchema = import_zod3.z.enum([
7381
7683
  "text",
@@ -7392,6 +7694,8 @@ var ModelTypeSchema = import_zod3.z.enum([
7392
7694
  "dubbing",
7393
7695
  "lipsync",
7394
7696
  "transcription",
7697
+ "voice-clone",
7698
+ "voice-design",
7395
7699
  "model3d"
7396
7700
  ]);
7397
7701
  var LifecycleSchema = import_zod3.z.enum(["active", "deprecated", "retired"]);
@@ -7567,6 +7871,10 @@ var ModelConstraintsSchema = import_zod3.z.looseObject({
7567
7871
  supports: import_zod3.z.array(SupportedOptionSchema).optional(),
7568
7872
  ratioIgnoredWith: import_zod3.z.array(import_zod3.z.enum(["firstFrame", "sourceVideo"])).optional(),
7569
7873
  voices: import_zod3.z.array(VoiceOptionSchema).optional(),
7874
+ voiceDesign: import_zod3.z.object({
7875
+ maxCandidates: import_zod3.z.number().int().positive(),
7876
+ previewMaxChars: import_zod3.z.number().int().positive()
7877
+ }).optional(),
7570
7878
  languages: import_zod3.z.array(LanguageOptionSchema).optional(),
7571
7879
  outputFormats: import_zod3.z.array(import_zod3.z.string().min(1)).min(1).optional(),
7572
7880
  sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: import_zod3.z.boolean().optional() }).optional(),
@@ -7665,6 +7973,7 @@ var CatalogDisplaySchema = import_zod3.z.looseObject({
7665
7973
  });
7666
7974
  var CatalogCapabilitiesSchema = import_zod3.z.looseObject({
7667
7975
  acceptsSourceVideo: import_zod3.z.boolean().optional(),
7976
+ customVoices: import_zod3.z.boolean().optional(),
7668
7977
  videoEdit: import_zod3.z.boolean().optional(),
7669
7978
  framesExcludeReferences: import_zod3.z.boolean().optional(),
7670
7979
  sourceVideoExcludesFrames: import_zod3.z.boolean().optional(),
@@ -8184,7 +8493,7 @@ var errorCodes = import_zod6.z.object({
8184
8493
  type: import_zod6.z.string().optional(),
8185
8494
  error: import_zod6.z.object({ code: import_zod6.z.string().optional(), type: import_zod6.z.string().optional() }).optional()
8186
8495
  });
8187
- var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
8496
+ var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
8188
8497
  var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
8189
8498
  function billingCode(body) {
8190
8499
  const parsed = errorCodes.safeParse(body);
@@ -8581,16 +8890,16 @@ async function generateSeedreamImage(req, ctx) {
8581
8890
  } else {
8582
8891
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8583
8892
  }
8584
- const usage3 = {
8893
+ const usage4 = {
8585
8894
  model: modelId,
8586
8895
  provider: "ark",
8587
8896
  modality: "IMAGE",
8588
8897
  unit: "images",
8589
8898
  quantity: 1
8590
8899
  };
8591
- if (req.size !== void 0) usage3.imageSize = req.size;
8592
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
8593
- return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage3, raw: data };
8900
+ if (req.size !== void 0) usage4.imageSize = req.size;
8901
+ if (req.quality !== void 0) usage4.imageQuality = req.quality;
8902
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage4, raw: data };
8594
8903
  }
8595
8904
  var SeedanceUsageSchema = import_zod7.z.object({
8596
8905
  total_tokens: import_zod7.z.number().optional(),
@@ -8631,7 +8940,7 @@ function seedanceErrorMessage(error, status) {
8631
8940
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8632
8941
  return `Seedance task ${status}`;
8633
8942
  }
8634
- function seedanceJob(ctx, key, jobId, usage3) {
8943
+ function seedanceJob(ctx, key, jobId, usage4) {
8635
8944
  const modelId = ctx.model.id;
8636
8945
  const fetchStatus = async () => {
8637
8946
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8681,21 +8990,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
8681
8990
  modelId
8682
8991
  );
8683
8992
  if (polled.duration !== void 0 && polled.duration > 0) {
8684
- usage3.quantity = polled.duration;
8685
- usage3.durationSeconds = polled.duration;
8993
+ usage4.quantity = polled.duration;
8994
+ usage4.durationSeconds = polled.duration;
8686
8995
  }
8687
8996
  const rendered = VideoResolutionSchema.safeParse(
8688
8997
  polled.resolution?.toLowerCase()
8689
8998
  );
8690
- if (rendered.success) usage3.resolution = rendered.data;
8999
+ if (rendered.success) usage4.resolution = rendered.data;
8691
9000
  const tokens = polled.usage;
8692
9001
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
8693
- usage3.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8694
- usage3.outputTokens = tokens.completion_tokens;
9002
+ usage4.inputTokens = tokens.total_tokens - tokens.completion_tokens;
9003
+ usage4.outputTokens = tokens.completion_tokens;
8695
9004
  }
8696
9005
  return {
8697
9006
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8698
- usage: usage3,
9007
+ usage: usage4,
8699
9008
  raw: polled
8700
9009
  };
8701
9010
  }
@@ -8801,8 +9110,8 @@ async function generateSeedanceVideo(req, ctx) {
8801
9110
  );
8802
9111
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8803
9112
  const jobId = submit.id;
8804
- const usage3 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8805
- return seedanceJob(ctx, key, jobId, usage3);
9113
+ const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9114
+ return seedanceJob(ctx, key, jobId, usage4);
8806
9115
  }
8807
9116
 
8808
9117
  // src/adapters/fal.ts
@@ -10290,7 +10599,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10290
10599
  return { bytes, mime: mime || "image/png" };
10291
10600
  })
10292
10601
  );
10293
- const usage3 = {
10602
+ const usage4 = {
10294
10603
  model: ctx.model.id,
10295
10604
  provider: "fal",
10296
10605
  modality: "IMAGE",
@@ -10298,9 +10607,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10298
10607
  quantity: images.length
10299
10608
  };
10300
10609
  const billedSize = plan4.imageSize ?? req.size;
10301
- if (billedSize !== void 0 && ctx.model.type === "image") usage3.imageSize = billedSize;
10302
- if (plan4.imageQuality !== void 0) usage3.imageQuality = plan4.imageQuality;
10303
- const result = { images, usage: usage3, raw: payload };
10610
+ if (billedSize !== void 0 && ctx.model.type === "image") usage4.imageSize = billedSize;
10611
+ if (plan4.imageQuality !== void 0) usage4.imageQuality = plan4.imageQuality;
10612
+ const result = { images, usage: usage4, raw: payload };
10304
10613
  const remote = files.find((f) => !f.url.startsWith("data:"));
10305
10614
  if (remote !== void 0) result.outputUrl = remote.url;
10306
10615
  return result;
@@ -12463,12 +12772,295 @@ function planUsage(ctx, plan4) {
12463
12772
  };
12464
12773
  }
12465
12774
 
12775
+ // src/adapters/fish.ts
12776
+ var import_zod21 = require("zod");
12777
+ var DEFAULT_BASE_URL = "https://api.fish.audio";
12778
+ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12779
+ "s2.1-pro",
12780
+ "s2.1-pro-free",
12781
+ "drama-3"
12782
+ ]);
12783
+ var FISH_VOICE_CLONE = "voice-clone";
12784
+ var FISH_VOICE_DESIGN = "voice-design-1";
12785
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12786
+ function fishRowRefusal(row2) {
12787
+ const id = row2.providerModelId;
12788
+ if (row2.type === "speech") {
12789
+ return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
12790
+ }
12791
+ if (row2.type === "voice-clone") {
12792
+ return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
12793
+ }
12794
+ if (row2.type === "voice-design") {
12795
+ return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
12796
+ }
12797
+ return `fish has no ${row2.type} rows`;
12798
+ }
12799
+ function fishError(ctx, code, message) {
12800
+ return new ModelKitError({
12801
+ code,
12802
+ message,
12803
+ provider: "fish",
12804
+ model: ctx.model.id,
12805
+ retryable: false
12806
+ });
12807
+ }
12808
+ function checkRow(ctx, type) {
12809
+ const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12810
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12811
+ throw fishError(
12812
+ ctx,
12813
+ "unsupported_option",
12814
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12815
+ );
12816
+ }
12817
+ }
12818
+ function checkVoiceId(ctx, field, id) {
12819
+ if (!VOICE_ID.test(id))
12820
+ throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12821
+ return id;
12822
+ }
12823
+ function fishKey(ctx) {
12824
+ const key = ctx.keys.fish;
12825
+ if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
12826
+ return key;
12827
+ }
12828
+ function fishUrl(ctx, path) {
12829
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
12830
+ }
12831
+ async function fishFetch(ctx, path, init) {
12832
+ throwIfAborted(ctx.signal);
12833
+ const request = {
12834
+ method: init.method,
12835
+ headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
12836
+ };
12837
+ if (init.body !== void 0) request.body = init.body;
12838
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12839
+ let res;
12840
+ try {
12841
+ res = await ctx.fetch(fishUrl(ctx, path), request);
12842
+ } catch (cause) {
12843
+ throw classifyThrown("fish", cause, ctx.model.id);
12844
+ }
12845
+ if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12846
+ return res;
12847
+ }
12848
+ function usage2(ctx) {
12849
+ return {
12850
+ model: ctx.model.id,
12851
+ provider: "fish",
12852
+ modality: "AUDIO",
12853
+ unit: ctx.model.usage.unit,
12854
+ quantity: 1
12855
+ };
12856
+ }
12857
+ function audioMime(res, format) {
12858
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12859
+ if (header?.startsWith("audio/")) return header;
12860
+ return format === "wav" ? "audio/wav" : "audio/mpeg";
12861
+ }
12862
+ async function generateSpeech(req, ctx) {
12863
+ checkRow(ctx, "speech");
12864
+ const format = req.outputFormat ?? "mp3";
12865
+ const body = { text: req.text, format };
12866
+ const voice = req.customVoice ?? req.voice;
12867
+ if (voice !== void 0) {
12868
+ body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12869
+ }
12870
+ if (req.language !== void 0) body.language = req.language;
12871
+ const { bytes, mime } = await withRetry(
12872
+ async () => {
12873
+ const res = await fishFetch(ctx, "/v1/tts", {
12874
+ method: "POST",
12875
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
12876
+ body: JSON.stringify(body)
12877
+ });
12878
+ let audio;
12879
+ try {
12880
+ audio = new Uint8Array(await res.arrayBuffer());
12881
+ } catch (cause) {
12882
+ throw classifyThrown("fish", cause, ctx.model.id);
12883
+ }
12884
+ return { bytes: audio, mime: audioMime(res, format) };
12885
+ },
12886
+ mediaRetryOptions(ctx.call, ctx.signal)
12887
+ );
12888
+ if (bytes.byteLength === 0)
12889
+ throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12890
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12891
+ }
12892
+ var createdModelSchema = import_zod21.z.object({
12893
+ _id: import_zod21.z.string().min(1),
12894
+ state: import_zod21.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12895
+ });
12896
+ function fileName(index, mime) {
12897
+ const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12898
+ return `sample-${index + 1}.${ext}`;
12899
+ }
12900
+ function allOrNone(ctx, field, values) {
12901
+ const set = values.filter((v) => v !== void 0 && v.trim() !== "");
12902
+ if (set.length === 0) return [];
12903
+ if (set.length !== values.length) {
12904
+ throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
12905
+ }
12906
+ return set;
12907
+ }
12908
+ async function cloneForm(req, ctx) {
12909
+ if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12910
+ const transcripts = allOrNone(
12911
+ ctx,
12912
+ "transcript",
12913
+ req.samples.map((s) => s.transcript)
12914
+ );
12915
+ const signatures = allOrNone(
12916
+ ctx,
12917
+ "designSignature",
12918
+ req.samples.map((s) => s.designSignature)
12919
+ );
12920
+ const form = new FormData();
12921
+ form.append("type", "tts");
12922
+ form.append("train_mode", "fast");
12923
+ form.append("visibility", "private");
12924
+ form.append("title", req.title.trim());
12925
+ if (req.description?.trim()) form.append("description", req.description.trim());
12926
+ if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
12927
+ for (const [index, sample] of req.samples.entries()) {
12928
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
12929
+ signal: ctx.signal,
12930
+ provider: "fish",
12931
+ model: ctx.model.id
12932
+ });
12933
+ const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12934
+ form.append("voices", audio, fileName(index, mime));
12935
+ }
12936
+ for (const text2 of transcripts) form.append("texts", text2.trim());
12937
+ for (const signature of signatures) form.append("voice_design_signatures", signature);
12938
+ return form;
12939
+ }
12940
+ async function onlyRateLimitRetries(fn) {
12941
+ try {
12942
+ return await fn();
12943
+ } catch (cause) {
12944
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
12945
+ throw cause;
12946
+ throw new ModelKitError({
12947
+ code: cause.code,
12948
+ message: cause.message,
12949
+ ...cause.provider !== void 0 && { provider: cause.provider },
12950
+ ...cause.model !== void 0 && { model: cause.model },
12951
+ ...cause.status !== void 0 && { status: cause.status },
12952
+ ...cause.body !== void 0 && { body: cause.body },
12953
+ cause,
12954
+ retryable: false
12955
+ });
12956
+ }
12957
+ }
12958
+ async function createVoice(req, ctx) {
12959
+ checkRow(ctx, "voice-clone");
12960
+ const form = await cloneForm(req, ctx);
12961
+ const res = await withRetry(
12962
+ () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12963
+ mediaRetryOptions(ctx.call, ctx.signal)
12964
+ );
12965
+ const raw = await readBody(res);
12966
+ const parsed = createdModelSchema.safeParse(raw);
12967
+ if (!parsed.success) {
12968
+ throw new ModelKitError({
12969
+ code: "provider_rejected",
12970
+ message: "Fish returned no voice id",
12971
+ provider: "fish",
12972
+ model: ctx.model.id,
12973
+ status: res.status,
12974
+ body: raw,
12975
+ retryable: false
12976
+ });
12977
+ }
12978
+ const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
12979
+ if (parsed.data.state !== void 0) result.state = parsed.data.state;
12980
+ return result;
12981
+ }
12982
+ var designSchema = import_zod21.z.object({
12983
+ candidates: import_zod21.z.array(
12984
+ import_zod21.z.looseObject({
12985
+ id: import_zod21.z.string().min(1),
12986
+ index: import_zod21.z.number().int(),
12987
+ audio_base64: import_zod21.z.string().min(1),
12988
+ duration_ms: import_zod21.z.number().nonnegative(),
12989
+ signature: import_zod21.z.string().min(1).optional()
12990
+ })
12991
+ ).min(1)
12992
+ });
12993
+ async function designVoice(req, ctx) {
12994
+ checkRow(ctx, "voice-design");
12995
+ const body = { instruction: req.prompt.trim() };
12996
+ if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12997
+ if (req.language !== void 0) body.language = req.language;
12998
+ if (req.count !== void 0) body.n = req.count;
12999
+ if (req.seed !== void 0) body.seed = req.seed;
13000
+ const raw = await withRetry(
13001
+ async () => {
13002
+ const res = await fishFetch(ctx, "/v1/voice-design", {
13003
+ method: "POST",
13004
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
13005
+ body: JSON.stringify(body)
13006
+ });
13007
+ return readBody(res);
13008
+ },
13009
+ mediaRetryOptions(ctx.call, ctx.signal)
13010
+ );
13011
+ const parsed = designSchema.safeParse(raw);
13012
+ if (!parsed.success) {
13013
+ throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
13014
+ }
13015
+ const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
13016
+ audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
13017
+ durationSeconds: c.duration_ms / 1e3,
13018
+ // The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
13019
+ // rejects a clone whose signature does not verify, so a wrong one fails loudly.
13020
+ signature: c.signature ?? c.id
13021
+ }));
13022
+ return { candidates, usage: usage2(ctx) };
13023
+ }
13024
+ async function deleteVoice(req, ctx) {
13025
+ checkRow(ctx, "voice-clone");
13026
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13027
+ let attempts = 0;
13028
+ await withRetry(
13029
+ async () => {
13030
+ attempts += 1;
13031
+ try {
13032
+ await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
13033
+ } catch (cause) {
13034
+ if (!isModelKitError(cause) || cause.status !== 404) throw cause;
13035
+ if (attempts > 1) return;
13036
+ throw new ModelKitError({
13037
+ code: "provider_rejected",
13038
+ message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13039
+ provider: "fish",
13040
+ model: ctx.model.id,
13041
+ status: 404,
13042
+ cause,
13043
+ retryable: false
13044
+ });
13045
+ }
13046
+ },
13047
+ mediaRetryOptions(ctx.call, ctx.signal)
13048
+ );
13049
+ }
13050
+ var fishAdapter = {
13051
+ id: "fish",
13052
+ generateSpeech,
13053
+ createVoice,
13054
+ designVoice,
13055
+ deleteVoice
13056
+ };
13057
+
12466
13058
  // src/adapters/google-genai.ts
12467
- var import_zod22 = require("zod");
13059
+ var import_zod23 = require("zod");
12468
13060
  var import_genai = require("@google/genai");
12469
13061
 
12470
13062
  // src/adapters/google-files.ts
12471
- var import_zod21 = require("zod");
13063
+ var import_zod22 = require("zod");
12472
13064
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12473
13065
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12474
13066
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12478,17 +13070,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12478
13070
  "binary/octet-stream",
12479
13071
  "application/binary"
12480
13072
  ]);
12481
- var uploadedFileSchema = import_zod21.z.object({
12482
- file: import_zod21.z.object({
12483
- uri: import_zod21.z.string().optional(),
12484
- name: import_zod21.z.string().optional(),
12485
- state: import_zod21.z.string().optional(),
12486
- mimeType: import_zod21.z.string().optional()
13073
+ var uploadedFileSchema = import_zod22.z.object({
13074
+ file: import_zod22.z.object({
13075
+ uri: import_zod22.z.string().optional(),
13076
+ name: import_zod22.z.string().optional(),
13077
+ state: import_zod22.z.string().optional(),
13078
+ mimeType: import_zod22.z.string().optional()
12487
13079
  }).optional()
12488
13080
  });
12489
- var fileStateSchema = import_zod21.z.object({
12490
- state: import_zod21.z.string().optional(),
12491
- error: import_zod21.z.object({ message: import_zod21.z.string().optional() }).optional()
13081
+ var fileStateSchema = import_zod22.z.object({
13082
+ state: import_zod22.z.string().optional(),
13083
+ error: import_zod22.z.object({ message: import_zod22.z.string().optional() }).optional()
12492
13084
  });
12493
13085
  function resolveMime(declared, fallback) {
12494
13086
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -12595,7 +13187,7 @@ async function startAndUpload(bytes, mimeType, opts) {
12595
13187
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
12596
13188
  return ref;
12597
13189
  }
12598
- async function waitForActive(fileName, opts) {
13190
+ async function waitForActive(fileName2, opts) {
12599
13191
  const pollOptions2 = {
12600
13192
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
12601
13193
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -12608,14 +13200,14 @@ async function waitForActive(fileName, opts) {
12608
13200
  retryInit.signal = opts.signal;
12609
13201
  }
12610
13202
  await pollUntil(async () => {
12611
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, retryInit);
13203
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
12612
13204
  if (res.ok) {
12613
13205
  const json = fileStateSchema.parse(await res.json());
12614
13206
  if (json.state === "ACTIVE") return true;
12615
13207
  if (json.state === "FAILED") {
12616
13208
  throw classifyHttpError(
12617
13209
  void 0,
12618
- `Files API processing failed for ${fileName}: ${json.error?.message ?? "unknown error"}`,
13210
+ `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
12619
13211
  "google-genai",
12620
13212
  opts.model
12621
13213
  );
@@ -12627,9 +13219,9 @@ async function waitForActive(fileName, opts) {
12627
13219
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
12628
13220
  }, pollOptions2);
12629
13221
  }
12630
- async function deleteGoogleFile(fileName, apiKey, fetchImpl) {
13222
+ async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
12631
13223
  try {
12632
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, {
13224
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
12633
13225
  method: "DELETE",
12634
13226
  headers: { "x-goog-api-key": apiKey }
12635
13227
  });
@@ -12709,7 +13301,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
12709
13301
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
12710
13302
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
12711
13303
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
12712
- var errorTextSchema = import_zod22.z.string();
13304
+ var errorTextSchema = import_zod23.z.string();
12713
13305
  function isGoogleGenaiVideoKnown(providerModelId) {
12714
13306
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
12715
13307
  }
@@ -12904,7 +13496,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12904
13496
  }
12905
13497
  };
12906
13498
  const jobId = operation.name ?? crypto.randomUUID();
12907
- const usage3 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13499
+ const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
12908
13500
  return {
12909
13501
  jobId,
12910
13502
  async poll() {
@@ -12942,7 +13534,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12942
13534
  modelId
12943
13535
  );
12944
13536
  }
12945
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage3, raw: finished };
13537
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
12946
13538
  }
12947
13539
  };
12948
13540
  }
@@ -13053,7 +13645,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13053
13645
  return file.fileUri;
13054
13646
  };
13055
13647
  const cleanupUploads = async () => {
13056
- for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
13648
+ for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
13057
13649
  };
13058
13650
  const callCreate = (input) => client2.interactions.create(
13059
13651
  previousId !== void 0 ? {
@@ -13147,7 +13739,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13147
13739
  if (!(extend && !chained)) await cleanupUploads();
13148
13740
  }
13149
13741
  const jobId = interaction.id ?? crypto.randomUUID();
13150
- const usage3 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13742
+ const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13151
13743
  const getInteraction = async () => {
13152
13744
  try {
13153
13745
  const getParams = { stream: false };
@@ -13195,7 +13787,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13195
13787
  bytes: Buffer.from(video.data, "base64"),
13196
13788
  mime: video.mime_type ?? "video/mp4"
13197
13789
  },
13198
- usage: usage3,
13790
+ usage: usage4,
13199
13791
  raw: done,
13200
13792
  providerRef
13201
13793
  };
@@ -13203,7 +13795,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13203
13795
  if (video.uri)
13204
13796
  return {
13205
13797
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13206
- usage: usage3,
13798
+ usage: usage4,
13207
13799
  raw: done,
13208
13800
  providerRef
13209
13801
  };
@@ -13373,15 +13965,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13373
13965
  // src/adapters/google-image.ts
13374
13966
  var import_google2 = require("@ai-sdk/google");
13375
13967
  var import_ai2 = require("ai");
13376
- var import_zod23 = require("zod");
13968
+ var import_zod24 = require("zod");
13377
13969
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13378
13970
  var defaultGoogleImageDeps = {
13379
13971
  createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
13380
13972
  runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
13381
13973
  };
13382
- var causeChainNodeSchema = import_zod23.z.object({
13383
- message: import_zod23.z.string().optional(),
13384
- cause: import_zod23.z.unknown().optional()
13974
+ var causeChainNodeSchema = import_zod24.z.object({
13975
+ message: import_zod24.z.string().optional(),
13976
+ cause: import_zod24.z.unknown().optional()
13385
13977
  });
13386
13978
  function extractBlockReason(cause) {
13387
13979
  let current = cause;
@@ -13481,7 +14073,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13481
14073
  retryable: false
13482
14074
  });
13483
14075
  }
13484
- const usage3 = {
14076
+ const usage4 = {
13485
14077
  model: ctx.model.id,
13486
14078
  provider: "google-image",
13487
14079
  modality: "IMAGE",
@@ -13489,19 +14081,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13489
14081
  quantity: images.length,
13490
14082
  imageQuality: "auto"
13491
14083
  };
13492
- if (req.size !== void 0) usage3.imageSize = req.size;
14084
+ if (req.size !== void 0) usage4.imageSize = req.size;
13493
14085
  if (result.usage?.inputTokens !== void 0)
13494
- usage3.inputTokens = result.usage.inputTokens;
14086
+ usage4.inputTokens = result.usage.inputTokens;
13495
14087
  if (result.usage?.outputTokens !== void 0)
13496
- usage3.outputTokens = result.usage.outputTokens;
13497
- return { images, usage: usage3, raw: result };
14088
+ usage4.outputTokens = result.usage.outputTokens;
14089
+ return { images, usage: usage4, raw: result };
13498
14090
  }
13499
14091
  };
13500
14092
  }
13501
14093
  var googleImageAdapter = createGoogleImageAdapter();
13502
14094
 
13503
14095
  // src/adapters/higgsfield.ts
13504
- var import_zod24 = require("zod");
14096
+ var import_zod25 = require("zod");
13505
14097
 
13506
14098
  // src/adapters/higgsfield-motions.ts
13507
14099
  var MOTION_MAP = {
@@ -13720,14 +14312,14 @@ function klingEndpointFields(providerModelId) {
13720
14312
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
13721
14313
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
13722
14314
  }
13723
- var klingCreateSchema = import_zod24.z.object({ status_url: import_zod24.z.string() });
13724
- var klingStatusSchema = import_zod24.z.object({
13725
- status: import_zod24.z.string().optional(),
13726
- video: import_zod24.z.object({ url: import_zod24.z.string().optional() }).optional(),
14315
+ var klingCreateSchema = import_zod25.z.object({ status_url: import_zod25.z.string() });
14316
+ var klingStatusSchema = import_zod25.z.object({
14317
+ status: import_zod25.z.string().optional(),
14318
+ video: import_zod25.z.object({ url: import_zod25.z.string().optional() }).optional(),
13727
14319
  error: JsonValueSchema.optional()
13728
14320
  });
13729
- var errorMessageSchema = import_zod24.z.object({ message: import_zod24.z.string().optional() });
13730
- var textValueSchema = import_zod24.z.string();
14321
+ var errorMessageSchema = import_zod25.z.object({ message: import_zod25.z.string().optional() });
14322
+ var textValueSchema = import_zod25.z.string();
13731
14323
  function klingErrorDetail(error) {
13732
14324
  if (error === void 0) return "unknown_error";
13733
14325
  const asText = textValueSchema.safeParse(error);
@@ -13883,8 +14475,8 @@ async function generateKlingVideo(req, ctx) {
13883
14475
  }
13884
14476
  };
13885
14477
  }
13886
- var dopMotionOptionsSchema = import_zod24.z.object({
13887
- modelkit: import_zod24.z.object({ motion: import_zod24.z.string().optional() }).optional()
14478
+ var dopMotionOptionsSchema = import_zod25.z.object({
14479
+ modelkit: import_zod25.z.object({ motion: import_zod25.z.string().optional() }).optional()
13888
14480
  });
13889
14481
  function dopMotionId(ctx) {
13890
14482
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -13900,7 +14492,7 @@ function dopMotionId(ctx) {
13900
14492
  });
13901
14493
  return id;
13902
14494
  }
13903
- var jsonRecordSchema = import_zod24.z.record(import_zod24.z.string(), JsonValueSchema);
14495
+ var jsonRecordSchema = import_zod25.z.record(import_zod25.z.string(), JsonValueSchema);
13904
14496
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
13905
14497
  var DOP_NESTED_KEYS = ["video", "result", "results"];
13906
14498
  function dopUrl(body) {
@@ -13928,8 +14520,8 @@ function dopUrl(body) {
13928
14520
  }
13929
14521
  return void 0;
13930
14522
  }
13931
- var dopCreateSchema = import_zod24.z.object({ id: import_zod24.z.string() });
13932
- var dopStatusSchema = import_zod24.z.object({ status: import_zod24.z.string().optional() });
14523
+ var dopCreateSchema = import_zod25.z.object({ id: import_zod25.z.string() });
14524
+ var dopStatusSchema = import_zod25.z.object({ status: import_zod25.z.string().optional() });
13933
14525
  async function generateDopVideo(req, ctx) {
13934
14526
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
13935
14527
  if (!firstFrame) {
@@ -14056,7 +14648,7 @@ var higgsfieldAdapter = {
14056
14648
  };
14057
14649
 
14058
14650
  // src/adapters/luma.ts
14059
- var import_zod25 = require("zod");
14651
+ var import_zod26 = require("zod");
14060
14652
 
14061
14653
  // src/adapters/mp4-duration.ts
14062
14654
  function mp4DurationSeconds(bytes) {
@@ -14112,7 +14704,7 @@ function findBox(bytes, from, to, type) {
14112
14704
  }
14113
14705
 
14114
14706
  // src/adapters/luma.ts
14115
- var DEFAULT_BASE_URL = "https://agents.lumalabs.ai";
14707
+ var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
14116
14708
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14117
14709
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14118
14710
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14141,7 +14733,7 @@ function lumaModel(ctx) {
14141
14733
  return ctx.model.providerModelId.toLowerCase();
14142
14734
  }
14143
14735
  function lumaBase(ctx) {
14144
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
14736
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
14145
14737
  }
14146
14738
  function lumaKey(ctx) {
14147
14739
  const key = ctx.keys.luma;
@@ -14273,17 +14865,17 @@ function lumaReframeResolution(req, ctx) {
14273
14865
  });
14274
14866
  return "720p";
14275
14867
  }
14276
- var lumaGenerationSchema = import_zod25.z.looseObject({
14277
- id: import_zod25.z.string(),
14278
- state: import_zod25.z.string().optional(),
14279
- output: import_zod25.z.array(
14280
- import_zod25.z.looseObject({
14281
- type: import_zod25.z.string().optional(),
14282
- url: import_zod25.z.string().optional()
14868
+ var lumaGenerationSchema = import_zod26.z.looseObject({
14869
+ id: import_zod26.z.string(),
14870
+ state: import_zod26.z.string().optional(),
14871
+ output: import_zod26.z.array(
14872
+ import_zod26.z.looseObject({
14873
+ type: import_zod26.z.string().optional(),
14874
+ url: import_zod26.z.string().optional()
14283
14875
  })
14284
14876
  ).optional(),
14285
- failure_reason: import_zod25.z.string().optional().nullable(),
14286
- failure_code: import_zod25.z.string().optional().nullable()
14877
+ failure_reason: import_zod26.z.string().optional().nullable(),
14878
+ failure_code: import_zod26.z.string().optional().nullable()
14287
14879
  });
14288
14880
  function lumaFailure(ctx, code, reason) {
14289
14881
  const detail = reason ?? code ?? "unknown_error";
@@ -14715,7 +15307,7 @@ var lumaAdapter = {
14715
15307
 
14716
15308
  // src/adapters/openai-image.ts
14717
15309
  var import_openai2 = __toESM(require("openai"), 1);
14718
- var import_zod26 = require("zod");
15310
+ var import_zod27 = require("zod");
14719
15311
  var MAX_EDIT_REFERENCES = 16;
14720
15312
  function aspectRatioToSize(ratio, tier) {
14721
15313
  const TIER_LONG_EDGE = {
@@ -14798,9 +15390,9 @@ function toProviderError2(cause, ctx) {
14798
15390
  ctx.model.id
14799
15391
  );
14800
15392
  }
14801
- var openaiUsageSchema = import_zod26.z.object({
14802
- input_tokens: import_zod26.z.number().optional(),
14803
- output_tokens: import_zod26.z.number().optional()
15393
+ var openaiUsageSchema = import_zod27.z.object({
15394
+ input_tokens: import_zod27.z.number().optional(),
15395
+ output_tokens: import_zod27.z.number().optional()
14804
15396
  });
14805
15397
  var openaiImageAdapter = {
14806
15398
  id: "openai-image",
@@ -14925,7 +15517,7 @@ var openaiImageAdapter = {
14925
15517
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
14926
15518
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
14927
15519
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
14928
- const usage3 = {
15520
+ const usage4 = {
14929
15521
  model: ctx.model.id,
14930
15522
  provider: "openai-image",
14931
15523
  modality: "IMAGE",
@@ -14933,10 +15525,10 @@ var openaiImageAdapter = {
14933
15525
  quantity: images.length,
14934
15526
  imageQuality: quality
14935
15527
  };
14936
- if (inputTokens !== void 0) usage3.inputTokens = inputTokens;
14937
- if (outputTokens !== void 0) usage3.outputTokens = outputTokens;
14938
- if (req.size !== void 0) usage3.imageSize = req.size;
14939
- return { images, usage: usage3, raw: response };
15528
+ if (inputTokens !== void 0) usage4.inputTokens = inputTokens;
15529
+ if (outputTokens !== void 0) usage4.outputTokens = outputTokens;
15530
+ if (req.size !== void 0) usage4.imageSize = req.size;
15531
+ return { images, usage: usage4, raw: response };
14940
15532
  }
14941
15533
  };
14942
15534
 
@@ -15192,16 +15784,16 @@ async function generateProdiaImage(req, ctx) {
15192
15784
  new Uint8Array(await res.arrayBuffer()),
15193
15785
  res.headers.get("content-type")
15194
15786
  );
15195
- const usage3 = {
15787
+ const usage4 = {
15196
15788
  model: ctx.model.id,
15197
15789
  provider: "prodia",
15198
15790
  modality: "IMAGE",
15199
15791
  unit: "images",
15200
15792
  quantity: 1
15201
15793
  };
15202
- if (req.size !== void 0) usage3.imageSize = req.size;
15203
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
15204
- return { images: [{ bytes, mime }], usage: usage3, raw: void 0 };
15794
+ if (req.size !== void 0) usage4.imageSize = req.size;
15795
+ if (req.quality !== void 0) usage4.imageQuality = req.quality;
15796
+ return { images: [{ bytes, mime }], usage: usage4, raw: void 0 };
15205
15797
  }
15206
15798
  var prodiaAdapter = {
15207
15799
  id: "prodia",
@@ -15212,13 +15804,13 @@ var prodiaAdapter = {
15212
15804
  var import_replicate = __toESM(require("replicate"), 1);
15213
15805
 
15214
15806
  // src/adapters/replicate-http.ts
15215
- var import_zod27 = require("zod");
15216
- var predictionSchema = import_zod27.z.object({
15217
- id: import_zod27.z.string(),
15218
- status: import_zod27.z.string(),
15807
+ var import_zod28 = require("zod");
15808
+ var predictionSchema = import_zod28.z.object({
15809
+ id: import_zod28.z.string(),
15810
+ status: import_zod28.z.string(),
15219
15811
  output: JsonValueSchema.optional(),
15220
15812
  error: JsonValueSchema.optional(),
15221
- metrics: import_zod27.z.object({ predict_time: import_zod27.z.number().optional() }).optional()
15813
+ metrics: import_zod28.z.object({ predict_time: import_zod28.z.number().optional() }).optional()
15222
15814
  });
15223
15815
  function createReplicateHttpClient(opts) {
15224
15816
  async function request(path, body, signal) {
@@ -15269,7 +15861,7 @@ function createReplicateHttpClient(opts) {
15269
15861
  }
15270
15862
 
15271
15863
  // src/adapters/replicate.ts
15272
- var import_zod28 = require("zod");
15864
+ var import_zod29 = require("zod");
15273
15865
  var POLL_INTERVAL_MS = 1e3;
15274
15866
  var POLL_TIMEOUT_MS = 15 * 6e4;
15275
15867
  var defaultReplicateDeps = {
@@ -15309,8 +15901,8 @@ function route(providerModelId) {
15309
15901
  if (!providerModelId.includes("/")) return { version: providerModelId };
15310
15902
  return { model: providerModelId };
15311
15903
  }
15312
- var replicateResponseStatusSchema = import_zod28.z.object({
15313
- response: import_zod28.z.object({ status: import_zod28.z.number() }).partial()
15904
+ var replicateResponseStatusSchema = import_zod29.z.object({
15905
+ response: import_zod29.z.object({ status: import_zod29.z.number() }).partial()
15314
15906
  });
15315
15907
  function replicateError(cause, ctx) {
15316
15908
  if (isModelKitError(cause)) return cause;
@@ -15333,7 +15925,7 @@ function isUrlFn(value) {
15333
15925
  function extractOutputUrl(output) {
15334
15926
  const root = Array.isArray(output) ? output[0] : output;
15335
15927
  if (root === void 0) throw noOutput();
15336
- const asString = import_zod28.z.string().safeParse(root);
15928
+ const asString = import_zod29.z.string().safeParse(root);
15337
15929
  if (asString.success && asString.data) return asString.data;
15338
15930
  if (root instanceof URL) return root.href;
15339
15931
  if (isObjectOutput(root)) {
@@ -15342,15 +15934,15 @@ function extractOutputUrl(output) {
15342
15934
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15343
15935
  const called = urlValue();
15344
15936
  if (called instanceof URL) return called.href;
15345
- const calledString = import_zod28.z.string().safeParse(called);
15937
+ const calledString = import_zod29.z.string().safeParse(called);
15346
15938
  if (calledString.success && calledString.data) return calledString.data;
15347
15939
  } else {
15348
- const direct = import_zod28.z.string().safeParse(urlValue);
15940
+ const direct = import_zod29.z.string().safeParse(urlValue);
15349
15941
  if (direct.success && direct.data) return direct.data;
15350
15942
  }
15351
15943
  }
15352
15944
  if ("default" in root) {
15353
- const fallback = import_zod28.z.string().safeParse(root.default);
15945
+ const fallback = import_zod29.z.string().safeParse(root.default);
15354
15946
  if (fallback.success && fallback.data) return fallback.data;
15355
15947
  }
15356
15948
  }
@@ -15411,7 +16003,7 @@ async function runPrediction(ctx, input, deps) {
15411
16003
  }
15412
16004
  return void 0;
15413
16005
  }, pollOpts);
15414
- const predictTime = import_zod28.z.number().safeParse(done.metrics?.predict_time);
16006
+ const predictTime = import_zod29.z.number().safeParse(done.metrics?.predict_time);
15415
16007
  if (done.output === void 0) throw noOutput();
15416
16008
  return {
15417
16009
  url: extractOutputUrl(done.output),
@@ -15657,9 +16249,9 @@ async function generateReplicateImage(req, ctx, deps) {
15657
16249
  }
15658
16250
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15659
16251
  const file = await download(ctx, url);
15660
- const usage3 = imageUsage3(ctx, req);
15661
- usage3.quantity = predictTime;
15662
- return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage3, raw, outputUrl: url };
16252
+ const usage4 = imageUsage3(ctx, req);
16253
+ usage4.quantity = predictTime;
16254
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage4, raw, outputUrl: url };
15663
16255
  }
15664
16256
  function klingInput(req) {
15665
16257
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -15764,7 +16356,7 @@ async function generateReplicateVideo(req, ctx, deps) {
15764
16356
  throw replicateError(cause, ctx);
15765
16357
  }
15766
16358
  if (current.status === "succeeded") {
15767
- const predictTime = import_zod28.z.number().safeParse(current.metrics?.predict_time);
16359
+ const predictTime = import_zod29.z.number().safeParse(current.metrics?.predict_time);
15768
16360
  if (current.output === void 0) throw noOutput();
15769
16361
  return {
15770
16362
  url: extractOutputUrl(current.output),
@@ -15783,9 +16375,9 @@ async function generateReplicateVideo(req, ctx, deps) {
15783
16375
  return void 0;
15784
16376
  };
15785
16377
  const toResult = (done) => {
15786
- const usage3 = videoUsage5(ctx, req);
15787
- usage3.quantity = done.predictTime;
15788
- return { video: { url: done.url }, usage: usage3, raw: done.raw };
16378
+ const usage4 = videoUsage5(ctx, req);
16379
+ usage4.quantity = done.predictTime;
16380
+ return { video: { url: done.url }, usage: usage4, raw: done.raw };
15789
16381
  };
15790
16382
  return {
15791
16383
  jobId,
@@ -15892,21 +16484,21 @@ async function generateReplicateAudio(req, ctx, deps) {
15892
16484
  input = specResult.input;
15893
16485
  }
15894
16486
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15895
- const usage3 = audioUsage(ctx, req);
16487
+ const usage4 = audioUsage(ctx, req);
15896
16488
  if (ctx.model.usage.unit === "seconds") {
15897
16489
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
15898
- usage3.quantity = seconds3;
15899
- usage3.durationSeconds = seconds3;
16490
+ usage4.quantity = seconds3;
16491
+ usage4.durationSeconds = seconds3;
15900
16492
  } else {
15901
- usage3.quantity = predictTime;
16493
+ usage4.quantity = predictTime;
15902
16494
  }
15903
- return { audio: { url }, usage: usage3, raw: predictionRaw(raw) };
16495
+ return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
15904
16496
  }
15905
16497
 
15906
16498
  // src/adapters/xai-video.ts
15907
16499
  var import_ai3 = require("ai");
15908
16500
  var import_xai2 = require("@ai-sdk/xai");
15909
- var import_zod29 = require("zod");
16501
+ var import_zod30 = require("zod");
15910
16502
  var POLL_INTERVAL_MS2 = 1e4;
15911
16503
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
15912
16504
  var defaultXaiDeps = {
@@ -15919,8 +16511,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
15919
16511
  };
15920
16512
  }
15921
16513
  var xaiVideoAdapter = createXaiVideoAdapter();
15922
- var xaiResponseStatusSchema = import_zod29.z.object({
15923
- response: import_zod29.z.object({ status: import_zod29.z.number() }).partial()
16514
+ var xaiResponseStatusSchema = import_zod30.z.object({
16515
+ response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
15924
16516
  });
15925
16517
  function xaiError(cause, ctx) {
15926
16518
  const info = describeThrown(cause);
@@ -15928,12 +16520,12 @@ function xaiError(cause, ctx) {
15928
16520
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
15929
16521
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
15930
16522
  }
15931
- var xaiMetaSchema = import_zod29.z.object({
16523
+ var xaiMetaSchema = import_zod30.z.object({
15932
16524
  videoUrl: JsonValueSchema.optional(),
15933
16525
  costInUsdTicks: JsonValueSchema.optional(),
15934
16526
  duration: JsonValueSchema.optional()
15935
16527
  });
15936
- var xaiProviderMetadataSchema = import_zod29.z.object({ xai: xaiMetaSchema });
16528
+ var xaiProviderMetadataSchema = import_zod30.z.object({ xai: xaiMetaSchema });
15937
16529
  function metaOf(result) {
15938
16530
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
15939
16531
  if (!parsed.success) return {};
@@ -16045,12 +16637,12 @@ async function mapResult(ctx, req, result) {
16045
16637
  if (first) {
16046
16638
  return {
16047
16639
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16048
- usage: usage2(ctx, req, metaOf(result)),
16640
+ usage: usage3(ctx, req, metaOf(result)),
16049
16641
  raw: result.providerMetadata
16050
16642
  };
16051
16643
  }
16052
16644
  const meta = metaOf(result);
16053
- const videoUrl = import_zod29.z.string().safeParse(meta.videoUrl);
16645
+ const videoUrl = import_zod30.z.string().safeParse(meta.videoUrl);
16054
16646
  if (videoUrl.success && videoUrl.data) {
16055
16647
  const res = await ctx.fetch(videoUrl.data);
16056
16648
  if (!res.ok) {
@@ -16060,7 +16652,7 @@ async function mapResult(ctx, req, result) {
16060
16652
  const mime = res.headers.get("content-type") ?? "video/mp4";
16061
16653
  return {
16062
16654
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16063
- usage: usage2(ctx, req, meta),
16655
+ usage: usage3(ctx, req, meta),
16064
16656
  raw: result.providerMetadata
16065
16657
  };
16066
16658
  }
@@ -16072,8 +16664,8 @@ async function mapResult(ctx, req, result) {
16072
16664
  retryable: false
16073
16665
  });
16074
16666
  }
16075
- function usage2(ctx, req, meta) {
16076
- const costTicks = import_zod29.z.number().safeParse(meta.costInUsdTicks);
16667
+ function usage3(ctx, req, meta) {
16668
+ const costTicks = import_zod30.z.number().safeParse(meta.costInUsdTicks);
16077
16669
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16078
16670
  const event = {
16079
16671
  model: ctx.model.id,
@@ -16112,7 +16704,8 @@ var DEFAULT_ADAPTERS = {
16112
16704
  prodia: prodiaAdapter,
16113
16705
  higgsfield: higgsfieldAdapter,
16114
16706
  "xai-video": xaiVideoAdapter,
16115
- luma: lumaAdapter
16707
+ luma: lumaAdapter,
16708
+ fish: fishAdapter
16116
16709
  };
16117
16710
 
16118
16711
  // src/catalog/data-only.ts
@@ -16136,6 +16729,8 @@ function adapterServesType(adapter, type) {
16136
16729
  if (type === "dubbing") return adapter.dub !== void 0;
16137
16730
  if (type === "lipsync") return adapter.lipsync !== void 0;
16138
16731
  if (type === "transcription") return adapter.transcribe !== void 0;
16732
+ if (type === "voice-clone") return adapter.createVoice !== void 0;
16733
+ if (type === "voice-design") return adapter.designVoice !== void 0;
16139
16734
  if (type === "video-tool") return adapter.submitVideoTool !== void 0;
16140
16735
  if (type === "model3d") return adapter.submitModel3d !== void 0;
16141
16736
  return adapter.languageModel !== void 0;
@@ -16149,12 +16744,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16149
16744
  "transcription",
16150
16745
  "mask"
16151
16746
  ]);
16747
+ function fishSpeech(row2) {
16748
+ return row2.adapter === "fish" && row2.type === "speech";
16749
+ }
16152
16750
  function dataOnlyCapable(row2) {
16153
16751
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16154
16752
  if (!adapterServesType(adapter, row2.type)) {
16155
16753
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16156
16754
  }
16157
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
16755
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
16158
16756
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16159
16757
  }
16160
16758
  switch (row2.adapter) {
@@ -16232,6 +16830,10 @@ function dataOnlyCapable(row2) {
16232
16830
  const reason = lumaRowRefusal(row2);
16233
16831
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16234
16832
  }
16833
+ case "fish": {
16834
+ const reason = fishRowRefusal(row2);
16835
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
16836
+ }
16235
16837
  default: {
16236
16838
  return assertNever(row2.adapter);
16237
16839
  }
@@ -16251,22 +16853,22 @@ var liveState = store[KEY] ??= {
16251
16853
  var liveCatalog = liveState.catalog;
16252
16854
 
16253
16855
  // src/catalog/load.ts
16254
- var import_zod30 = require("zod");
16856
+ var import_zod31 = require("zod");
16255
16857
  function rowCount() {
16256
16858
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16257
16859
  }
16258
16860
  function authHeaders(auth) {
16259
16861
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16260
16862
  }
16261
- var EnvelopeSchema = import_zod30.z.object({
16262
- rows: import_zod30.z.array(JsonValueSchema),
16263
- revision: import_zod30.z.string().optional()
16863
+ var EnvelopeSchema = import_zod31.z.object({
16864
+ rows: import_zod31.z.array(JsonValueSchema),
16865
+ revision: import_zod31.z.string().optional()
16264
16866
  });
16265
16867
  function dropReason(path, message) {
16266
16868
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16267
16869
  }
16268
16870
  function rowId(raw) {
16269
- const parsed = import_zod30.z.object({ id: import_zod30.z.string().min(1) }).loose().safeParse(raw);
16871
+ const parsed = import_zod31.z.object({ id: import_zod31.z.string().min(1) }).loose().safeParse(raw);
16270
16872
  if (!parsed.success) return "?";
16271
16873
  return parsed.data.id;
16272
16874
  }
@@ -17182,8 +17784,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
17182
17784
  const warnings = [];
17183
17785
  checkScript(model, request.text);
17184
17786
  const resolved = { model: model.id, text: request.text };
17185
- const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
17186
- if (voice !== void 0) resolved.voice = voice;
17787
+ const customVoice = request.customVoice?.trim();
17788
+ if (customVoice) {
17789
+ if (model.capabilities?.customVoices !== true) {
17790
+ throw unsupported3(model, "does not take a custom voice");
17791
+ }
17792
+ if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
17793
+ resolved.customVoice = customVoice;
17794
+ } else {
17795
+ const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
17796
+ if (voice !== void 0) resolved.voice = voice;
17797
+ }
17187
17798
  const language = resolveListed(
17188
17799
  model,
17189
17800
  {
@@ -17305,6 +17916,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
17305
17916
  return { request: resolved, warnings };
17306
17917
  }
17307
17918
 
17919
+ // src/resolve-voice.ts
17920
+ function refuse(model, code, message) {
17921
+ return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
17922
+ }
17923
+ function checkSample(model, sample, index) {
17924
+ const limits = model.constraints.references?.audioSeconds;
17925
+ const length = sample.audio.durationSeconds;
17926
+ if (limits === void 0 || length === void 0) return;
17927
+ if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
17928
+ const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
17929
+ throw refuse(
17930
+ model,
17931
+ "unsupported_option",
17932
+ `takes samples of ${range2}; sample ${index + 1} is ${length} s`
17933
+ );
17934
+ }
17935
+ }
17936
+ function resolveVoiceCloneOptions(model, request) {
17937
+ const title = request.title.trim();
17938
+ if (!title) throw refuse(model, "missing_input", "needs a title");
17939
+ if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
17940
+ const max = model.constraints.references?.audios;
17941
+ if (max !== void 0 && request.samples.length > max) {
17942
+ throw refuse(
17943
+ model,
17944
+ "unsupported_option",
17945
+ `takes up to ${max} samples; got ${request.samples.length}`
17946
+ );
17947
+ }
17948
+ request.samples.forEach((sample, index) => checkSample(model, sample, index));
17949
+ const total = model.constraints.references?.audioSeconds?.total;
17950
+ const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
17951
+ if (total !== void 0 && seconds3 > total) {
17952
+ throw refuse(
17953
+ model,
17954
+ "unsupported_option",
17955
+ `takes up to ${total} s of samples; got ${seconds3} s`
17956
+ );
17957
+ }
17958
+ for (const field of ["transcript", "designSignature"]) {
17959
+ const set = request.samples.filter((s) => s[field]?.trim()).length;
17960
+ if (set !== 0 && set !== request.samples.length) {
17961
+ throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
17962
+ }
17963
+ }
17964
+ return { request: { ...request, model: model.id, title }, warnings: [] };
17965
+ }
17966
+ function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
17967
+ const warnings = [];
17968
+ const prompt = request.prompt.trim();
17969
+ if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
17970
+ const maxChars = promptConventions(model).maxChars;
17971
+ if (maxChars !== void 0 && prompt.length > maxChars) {
17972
+ throw refuse(
17973
+ model,
17974
+ "unsupported_option",
17975
+ `takes up to ${maxChars} characters; got ${prompt.length}`
17976
+ );
17977
+ }
17978
+ const limits = model.constraints.voiceDesign;
17979
+ const resolved = { model: model.id, prompt };
17980
+ const preview2 = request.previewText?.trim();
17981
+ if (preview2) {
17982
+ if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
17983
+ throw refuse(
17984
+ model,
17985
+ "unsupported_option",
17986
+ `takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
17987
+ );
17988
+ }
17989
+ resolved.previewText = preview2;
17990
+ }
17991
+ const language = request.language?.trim();
17992
+ if (language) resolved.language = language;
17993
+ if (request.seed !== void 0) resolved.seed = request.seed;
17994
+ const count2 = request.count ?? model.defaults.count;
17995
+ if (count2 !== void 0) {
17996
+ const cap = limits?.maxCandidates ?? count2;
17997
+ if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
17998
+ if (onUnsupported === "error" || !Number.isInteger(count2)) {
17999
+ throw refuse(
18000
+ model,
18001
+ "unsupported_option",
18002
+ `returns 1-${cap} candidates; got ${count2}`
18003
+ );
18004
+ }
18005
+ const to = Math.min(Math.max(count2, 1), cap);
18006
+ warnings.push({
18007
+ code: "option_ignored",
18008
+ field: "count",
18009
+ from: String(count2),
18010
+ to: String(to),
18011
+ message: `count ${count2} replaced by ${to} for ${model.id}`
18012
+ });
18013
+ resolved.count = to;
18014
+ } else resolved.count = count2;
18015
+ }
18016
+ return { request: resolved, warnings };
18017
+ }
18018
+
17308
18019
  // src/keys.ts
17309
18020
  var ADAPTER_KEYS = {
17310
18021
  "ai-sdk-text": [],
@@ -17317,7 +18028,8 @@ var ADAPTER_KEYS = {
17317
18028
  prodia: ["prodia"],
17318
18029
  higgsfield: ["higgsfield"],
17319
18030
  "xai-video": ["xai"],
17320
- luma: ["luma"]
18031
+ luma: ["luma"],
18032
+ fish: ["fish"]
17321
18033
  };
17322
18034
  function hasAll(keys, names) {
17323
18035
  if (!keys) return false;
@@ -17376,6 +18088,7 @@ function keysFromEnv(env, prefix = "") {
17376
18088
  set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
17377
18089
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17378
18090
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
18091
+ set("fish", pick2("FISH_AUDIO_API_KEY"));
17379
18092
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17380
18093
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17381
18094
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17398,7 +18111,7 @@ function keysFromEnv(env, prefix = "") {
17398
18111
 
17399
18112
  // src/text.ts
17400
18113
  var import_ai4 = require("ai");
17401
- var import_zod31 = require("zod");
18114
+ var import_zod32 = require("zod");
17402
18115
  function mergeTextProviderOptions(catalog, caller) {
17403
18116
  const merged = {};
17404
18117
  const catalogOptions = catalog.providerOptions ?? {};
@@ -17437,17 +18150,17 @@ function passthroughTextModel(model) {
17437
18150
  pricingKind: "token"
17438
18151
  };
17439
18152
  }
17440
- var perplexityCostSchema = import_zod31.z.object({
17441
- perplexity: import_zod31.z.object({ cost: import_zod31.z.object({ totalCost: import_zod31.z.number().finite().nonnegative() }) })
18153
+ var perplexityCostSchema = import_zod32.z.object({
18154
+ perplexity: import_zod32.z.object({ cost: import_zod32.z.object({ totalCost: import_zod32.z.number().finite().nonnegative() }) })
17442
18155
  });
17443
18156
  function reportedCostUsd(metadata) {
17444
18157
  const parsed = perplexityCostSchema.safeParse(metadata);
17445
18158
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
17446
18159
  }
17447
- function textUsageEvent(model, provider, usage3, providerMetadata) {
17448
- const inputTokens = usage3.inputTokens ?? 0;
17449
- const outputTokens = usage3.outputTokens ?? 0;
17450
- const total = usage3.totalTokens ?? inputTokens + outputTokens;
18160
+ function textUsageEvent(model, provider, usage4, providerMetadata) {
18161
+ const inputTokens = usage4.inputTokens ?? 0;
18162
+ const outputTokens = usage4.outputTokens ?? 0;
18163
+ const total = usage4.totalTokens ?? inputTokens + outputTokens;
17451
18164
  const event = {
17452
18165
  model: model.id,
17453
18166
  provider,
@@ -17482,7 +18195,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17482
18195
  return { ...prepared, providerOptions };
17483
18196
  };
17484
18197
  }
17485
- function usage3(results) {
18198
+ function usage4(results) {
17486
18199
  const grouped = /* @__PURE__ */ new Map();
17487
18200
  for (const [index, step] of results.entries()) {
17488
18201
  const target = steps.get(index) ?? initial;
@@ -17506,12 +18219,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17506
18219
  }
17507
18220
  return [...grouped.values()];
17508
18221
  }
17509
- return { wrap, usage: usage3 };
18222
+ return { wrap, usage: usage4 };
17510
18223
  }
17511
18224
 
17512
18225
  // src/client.ts
17513
18226
  var import_ai5 = require("ai");
17514
- var import_zod32 = require("zod");
18227
+ var import_zod33 = require("zod");
17515
18228
 
17516
18229
  // src/generated-image.ts
17517
18230
  function toGeneratedImage(image) {
@@ -17633,9 +18346,9 @@ function providerJobMethods(kind, deps) {
17633
18346
  if (!methods.result) throw missing3(adapter, ctx.model);
17634
18347
  const result = await methods.result(sub, ctx, webhook);
17635
18348
  const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
17636
- const usage3 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
17637
- await deps.emit(usage3);
17638
- return { ...result, usage: usage3 };
18349
+ const usage4 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18350
+ await deps.emit(usage4);
18351
+ return { ...result, usage: usage4 };
17639
18352
  },
17640
18353
  async cancel(sub, call = {}) {
17641
18354
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -17660,6 +18373,9 @@ var MEDIA_METHODS = {
17660
18373
  lipsync: ["lipsync"],
17661
18374
  dubbing: ["dub"],
17662
18375
  transcription: ["transcribe"],
18376
+ // deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
18377
+ "voice-clone": ["createVoice"],
18378
+ "voice-design": ["designVoice"],
17663
18379
  "video-tool": ["submitVideoTool"],
17664
18380
  // 3D jobs run through submitModel3d, which checks the row type itself; their preflight
17665
18381
  // is model3dInputRefusal, not resolveOptions.
@@ -17674,6 +18390,8 @@ var METHOD_NOUN = {
17674
18390
  lipsync: "a lipsync model",
17675
18391
  dub: "a dubbing model",
17676
18392
  transcribe: "a transcription model",
18393
+ createVoice: "a voice cloning model",
18394
+ designVoice: "a voice design model",
17677
18395
  submitVideoTool: "a video tool"
17678
18396
  };
17679
18397
  function assertMethod(model, method) {
@@ -17716,6 +18434,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
17716
18434
  assertMethod(model, "transcribe");
17717
18435
  return resolveTranscriptionOptions(model, request, onUnsupported);
17718
18436
  }
18437
+ function resolveVoiceCloneCall(model, request) {
18438
+ assertMethod(model, "createVoice");
18439
+ return resolveVoiceCloneOptions(model, request);
18440
+ }
18441
+ function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
18442
+ assertMethod(model, "designVoice");
18443
+ return resolveVoiceDesignOptions(model, request, onUnsupported);
18444
+ }
17719
18445
 
17720
18446
  // src/client-audio.ts
17721
18447
  function noMethod(adapter, model, what) {
@@ -17805,6 +18531,49 @@ function audioNodeMethods(deps) {
17805
18531
  const result = await adapter.transcribe(resolved, ctx);
17806
18532
  return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
17807
18533
  },
18534
+ async createVoice(req, call = {}) {
18535
+ mediaRetryOptions(call);
18536
+ const { abortSignal, ...request } = req;
18537
+ const model = catalog.require(req.model);
18538
+ const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
18539
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18540
+ if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
18541
+ const startedAt = Date.now();
18542
+ const result = await adapter.createVoice(resolved, ctx);
18543
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18544
+ },
18545
+ async designVoice(req, call = {}) {
18546
+ mediaRetryOptions(call);
18547
+ const { abortSignal, ...request } = req;
18548
+ const model = catalog.require(req.model);
18549
+ const { request: resolved, warnings } = resolveVoiceDesignCall(
18550
+ model,
18551
+ request,
18552
+ call.onUnsupported ?? "error"
18553
+ );
18554
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18555
+ if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
18556
+ const startedAt = Date.now();
18557
+ const result = await adapter.designVoice(resolved, ctx);
18558
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18559
+ },
18560
+ async deleteVoice(req, call = {}) {
18561
+ mediaRetryOptions(call);
18562
+ const { abortSignal, ...request } = req;
18563
+ const model = catalog.require(req.model);
18564
+ assertMethod(model, "createVoice");
18565
+ const voiceId = request.voiceId.trim();
18566
+ if (!voiceId) {
18567
+ throw new ModelKitError({
18568
+ code: "missing_input",
18569
+ message: `${model.id} requires voiceId`,
18570
+ model: model.id
18571
+ });
18572
+ }
18573
+ const { adapter, ctx } = prepare(model, call, abortSignal, []);
18574
+ if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
18575
+ await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
18576
+ },
17808
18577
  async dub(req, call = {}) {
17809
18578
  mediaRetryOptions(call);
17810
18579
  const { abortSignal, ...request } = req;
@@ -17819,10 +18588,10 @@ function audioNodeMethods(deps) {
17819
18588
  const startedAt = Date.now();
17820
18589
  const outcome = await adapter.dub(resolved, ctx);
17821
18590
  if (outcome.kind === "audio") {
17822
- const { audio, usage: usage3, raw } = outcome.result;
18591
+ const { audio, usage: usage4, raw } = outcome.result;
17823
18592
  return {
17824
18593
  audio,
17825
- usage: await deps.settle(model, usage3, startedAt),
18594
+ usage: await deps.settle(model, usage4, startedAt),
17826
18595
  ...raw !== void 0 && { raw }
17827
18596
  };
17828
18597
  }
@@ -17860,10 +18629,10 @@ function textAbortOptions(sdk, context) {
17860
18629
  if (abortSignal) return { abortSignal };
17861
18630
  return {};
17862
18631
  }
17863
- var catalogId = import_zod32.z.string();
17864
- var exactSize = import_zod32.z.templateLiteral([import_zod32.z.number(), "x", import_zod32.z.number()]);
17865
- var sdkRatio = import_zod32.z.templateLiteral([import_zod32.z.number(), ":", import_zod32.z.number()]);
17866
- var sizeTier = import_zod32.z.enum(["512", "1K", "2K", "4K"]);
18632
+ var catalogId = import_zod33.z.string();
18633
+ var exactSize = import_zod33.z.templateLiteral([import_zod33.z.number(), "x", import_zod33.z.number()]);
18634
+ var sdkRatio = import_zod33.z.templateLiteral([import_zod33.z.number(), ":", import_zod33.z.number()]);
18635
+ var sizeTier = import_zod33.z.enum(["512", "1K", "2K", "4K"]);
17867
18636
  function isCatalogId(model) {
17868
18637
  return catalogId.safeParse(model).success;
17869
18638
  }
@@ -18076,7 +18845,7 @@ function createModelKit(config, adapters) {
18076
18845
  const images = result.images.map(
18077
18846
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18078
18847
  );
18079
- const usage3 = timed(
18848
+ const usage4 = timed(
18080
18849
  {
18081
18850
  model: model.modelId,
18082
18851
  provider: model.provider,
@@ -18086,8 +18855,8 @@ function createModelKit(config, adapters) {
18086
18855
  },
18087
18856
  startedAt
18088
18857
  );
18089
- await emit(usage3);
18090
- return { image: images[0], images, usage: usage3, raw: result, warnings };
18858
+ await emit(usage4);
18859
+ return { image: images[0], images, usage: usage4, raw: result, warnings };
18091
18860
  }
18092
18861
  function passthroughVideo(req, call) {
18093
18862
  const {
@@ -18163,7 +18932,7 @@ function createModelKit(config, adapters) {
18163
18932
  let settled;
18164
18933
  let failed = false;
18165
18934
  const done = pending.then(async (result) => {
18166
- const usage3 = timed(
18935
+ const usage4 = timed(
18167
18936
  {
18168
18937
  model: model.modelId,
18169
18938
  provider: model.provider,
@@ -18176,10 +18945,10 @@ function createModelKit(config, adapters) {
18176
18945
  );
18177
18946
  settled = {
18178
18947
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18179
- usage: usage3,
18948
+ usage: usage4,
18180
18949
  raw: result
18181
18950
  };
18182
- await emit(usage3);
18951
+ await emit(usage4);
18183
18952
  return settled;
18184
18953
  });
18185
18954
  done.catch(() => {
@@ -18206,12 +18975,12 @@ function createModelKit(config, adapters) {
18206
18975
  if (settled) return settled;
18207
18976
  const pending = result(opts).then(
18208
18977
  async (out) => {
18209
- const usage3 = timed(
18978
+ const usage4 = timed(
18210
18979
  { ...out.usage, model: model.id, unit: model.usage.unit },
18211
18980
  startedAt
18212
18981
  );
18213
- await emit(usage3);
18214
- return { ...out, usage: usage3 };
18982
+ await emit(usage4);
18983
+ return { ...out, usage: usage4 };
18215
18984
  },
18216
18985
  (cause) => {
18217
18986
  settled = void 0;
@@ -18231,9 +19000,9 @@ function createModelKit(config, adapters) {
18231
19000
  return context(model, signal ? { ...call, signal } : call, warnings);
18232
19001
  },
18233
19002
  async settle(model, event, startedAt) {
18234
- const usage3 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
18235
- await emit(usage3);
18236
- return usage3;
19003
+ const usage4 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19004
+ await emit(usage4);
19005
+ return usage4;
18237
19006
  },
18238
19007
  wrapVideoJob
18239
19008
  });
@@ -18269,11 +19038,11 @@ function createModelKit(config, adapters) {
18269
19038
  });
18270
19039
  const startedAt = Date.now();
18271
19040
  const result = await adapter.generateImage(request, ctx);
18272
- const usage3 = timed(
19041
+ const usage4 = timed(
18273
19042
  { ...result.usage, model: model.id, unit: model.usage.unit },
18274
19043
  startedAt
18275
19044
  );
18276
- await emit(usage3);
19045
+ await emit(usage4);
18277
19046
  const images = result.images.map(toGeneratedImage);
18278
19047
  const first = images[0];
18279
19048
  if (!first)
@@ -18282,7 +19051,7 @@ function createModelKit(config, adapters) {
18282
19051
  message: `${model.id} returned no image`,
18283
19052
  model: model.id
18284
19053
  });
18285
- return { ...result, usage: usage3, image: first, images, warnings };
19054
+ return { ...result, usage: usage4, image: first, images, warnings };
18286
19055
  },
18287
19056
  async generateVideo(req, call = {}) {
18288
19057
  mediaRetryOptions(call);
@@ -18381,12 +19150,12 @@ function createModelKit(config, adapters) {
18381
19150
  }
18382
19151
  const startedAt = Date.now();
18383
19152
  const result = await adapter.generateAudio(resolved, ctx);
18384
- const usage3 = timed(
19153
+ const usage4 = timed(
18385
19154
  { ...result.usage, model: model.id, unit: model.usage.unit },
18386
19155
  startedAt
18387
19156
  );
18388
- await emit(usage3);
18389
- return { ...result, usage: usage3 };
19157
+ await emit(usage4);
19158
+ return { ...result, usage: usage4 };
18390
19159
  },
18391
19160
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
18392
19161
  mediaRetryOptions(call);
@@ -18466,8 +19235,8 @@ function createModelKit(config, adapters) {
18466
19235
  options.prepareStep ?? options.experimental_prepareStep
18467
19236
  ),
18468
19237
  onFinish: async (event) => {
18469
- for (const usage3 of steps.usage(event.steps))
18470
- await emit(textTimed(withRowUnit(usage3), event.steps.length, startedAt));
19238
+ for (const usage4 of steps.usage(event.steps))
19239
+ await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
18471
19240
  await callerOnFinish?.(event);
18472
19241
  }
18473
19242
  });
@@ -18590,6 +19359,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
18590
19359
  falAdapter,
18591
19360
  falWebhookBodySchema,
18592
19361
  fileCatalogCache,
19362
+ fishAdapter,
18593
19363
  generateAudio,
18594
19364
  generateImage,
18595
19365
  generateObject,
@@ -18642,6 +19412,8 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
18642
19412
  resolveTranscriptionOptions,
18643
19413
  resolveVideoOptions,
18644
19414
  resolveVoiceChangeOptions,
19415
+ resolveVoiceCloneOptions,
19416
+ resolveVoiceDesignOptions,
18645
19417
  shouldRetry,
18646
19418
  sleep,
18647
19419
  sortCatalogRows,