@shop-os/modelkit 0.9.0 → 0.10.1

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
@@ -66,6 +66,7 @@ __export(index_exports, {
66
66
  dataOnlyCapable: () => dataOnlyCapable,
67
67
  describe: () => describe,
68
68
  describeThrown: () => describeThrown,
69
+ elevenLabsAdapter: () => elevenLabsAdapter,
69
70
  experimental_generateImage: () => generateImage,
70
71
  falAdapter: () => falAdapter,
71
72
  falWebhookBodySchema: () => falWebhookBodySchema,
@@ -1371,303 +1372,6 @@ var VEED_SUBTITLES = {
1371
1372
  }
1372
1373
  };
1373
1374
 
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
-
1671
1375
  // src/catalog/languages-audio.ts
1672
1376
  var ELEVENLABS_V4_LANGUAGES = [
1673
1377
  { code: "af", name: "Afrikaans" },
@@ -2054,119 +1758,483 @@ var ELEVENLABS_VOICES = [
2054
1758
  id: "Callum",
2055
1759
  name: "Callum",
2056
1760
  gender: "male",
2057
- accent: "american",
2058
- languages: ["en", "fr", "hi"],
2059
- description: "Deceptively gravelly, yet unsettling edge.",
2060
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
1761
+ accent: "american",
1762
+ languages: ["en", "fr", "hi"],
1763
+ description: "Deceptively gravelly, yet unsettling edge.",
1764
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
1765
+ },
1766
+ {
1767
+ id: "River",
1768
+ name: "River",
1769
+ gender: "neutral",
1770
+ accent: "american",
1771
+ languages: ["en", "it", "fr", "pt", "zh"],
1772
+ description: "A relaxed, neutral voice ready for narrations or conversational projects.",
1773
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
1774
+ },
1775
+ {
1776
+ id: "Liam",
1777
+ name: "Liam",
1778
+ gender: "male",
1779
+ accent: "american",
1780
+ languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
1781
+ description: "A young adult with energy and warmth - suitable for reels and shorts.",
1782
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
1783
+ },
1784
+ { id: "Charlotte", name: "Charlotte" },
1785
+ {
1786
+ id: "Alice",
1787
+ name: "Alice",
1788
+ gender: "female",
1789
+ accent: "british",
1790
+ languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
1791
+ description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
1792
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
1793
+ },
1794
+ {
1795
+ id: "Matilda",
1796
+ name: "Matilda",
1797
+ gender: "female",
1798
+ accent: "american",
1799
+ languages: ["en", "it", "fr", "de", "ar", "es"],
1800
+ description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
1801
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
1802
+ },
1803
+ {
1804
+ id: "Will",
1805
+ name: "Will",
1806
+ gender: "male",
1807
+ accent: "american",
1808
+ languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
1809
+ description: "Conversational and laid back.",
1810
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
1811
+ },
1812
+ {
1813
+ id: "Jessica",
1814
+ name: "Jessica",
1815
+ gender: "female",
1816
+ accent: "american",
1817
+ languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
1818
+ description: "Young and popular, this playful American female voice is perfect for trendy content.",
1819
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
1820
+ },
1821
+ {
1822
+ id: "Eric",
1823
+ name: "Eric",
1824
+ gender: "male",
1825
+ accent: "american",
1826
+ languages: ["en", "fr", "pt", "de", "sk", "es"],
1827
+ description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
1828
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
1829
+ },
1830
+ {
1831
+ id: "Chris",
1832
+ name: "Chris",
1833
+ gender: "male",
1834
+ accent: "american",
1835
+ languages: ["en", "fr", "ar", "pt", "sv", "hi"],
1836
+ description: "Natural and real, this down-to-earth voice is great across many use-cases.",
1837
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
1838
+ },
1839
+ {
1840
+ id: "Brian",
1841
+ name: "Brian",
1842
+ gender: "male",
1843
+ accent: "american",
1844
+ languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
1845
+ description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
1846
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
1847
+ },
1848
+ {
1849
+ id: "Daniel",
1850
+ name: "Daniel",
1851
+ gender: "male",
1852
+ accent: "british",
1853
+ languages: ["en", "de", "tr"],
1854
+ description: "A strong voice perfect for delivering a professional broadcast or news story.",
1855
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
1856
+ },
1857
+ {
1858
+ id: "Lily",
1859
+ name: "Lily",
1860
+ gender: "female",
1861
+ accent: "british",
1862
+ languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
1863
+ description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
1864
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
1865
+ },
1866
+ {
1867
+ id: "Bill",
1868
+ name: "Bill",
1869
+ gender: "male",
1870
+ accent: "american",
1871
+ languages: ["en", "fr", "ar", "zh", "de", "cs"],
1872
+ description: "Friendly and comforting voice ready to narrate your stories.",
1873
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
1874
+ }
1875
+ ];
1876
+ var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
1877
+ var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
1878
+ const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
1879
+ return id ? [{ ...v, id }] : [];
1880
+ });
1881
+ var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
1882
+
1883
+ // src/catalog/speech-elevenlabs-direct.ts
1884
+ var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
1885
+ var PER_CALL = { unit: "images" };
1886
+ var PER_REQUEST = { unit: "requests" };
1887
+ var ELEVENLABS_DIRECT_MODELS = [
1888
+ {
1889
+ id: "elevenlabs-v4-direct",
1890
+ aliases: [],
1891
+ label: "ElevenLabs v4 (direct)",
1892
+ type: "speech",
1893
+ adapter: "elevenlabs",
1894
+ providerModelId: "eleven_v4",
1895
+ lifecycle: "active",
1896
+ exposure: [],
1897
+ constraints: {
1898
+ // Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
1899
+ voices: ELEVENLABS_DIRECT_VOICES,
1900
+ languages: ELEVENLABS_V4_LANGUAGES,
1901
+ outputFormats: ELEVENLABS_MP3_FORMATS,
1902
+ supports: [],
1903
+ // ElevenLabs docs: 10,000 characters per request.
1904
+ prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
1905
+ },
1906
+ defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
1907
+ usage: PER_CALL,
1908
+ pricingKind: "flat",
1909
+ display: {
1910
+ provider: "elevenlabs",
1911
+ logo: ELEVENLABS_LOGO,
1912
+ description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
1913
+ },
1914
+ capabilities: { customVoices: true }
1915
+ },
1916
+ {
1917
+ id: "elevenlabs-ivc",
1918
+ aliases: [],
1919
+ label: "ElevenLabs Instant Voice Clone",
1920
+ type: "voice-clone",
1921
+ adapter: "elevenlabs",
1922
+ providerModelId: "ivc",
1923
+ lifecycle: "active",
1924
+ exposure: [],
1925
+ constraints: {
1926
+ // POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
1927
+ // clean speech in total. Each clone uses a voice slot on our plan until deleted.
1928
+ references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
1929
+ supports: []
1930
+ },
1931
+ defaults: {},
1932
+ usage: PER_REQUEST,
1933
+ pricingKind: "flat",
1934
+ display: {
1935
+ provider: "elevenlabs",
1936
+ logo: ELEVENLABS_LOGO,
1937
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
1938
+ },
1939
+ capabilities: {}
1940
+ }
1941
+ ];
1942
+
1943
+ // src/catalog/voices-fish.ts
1944
+ var FISH_VOICES = [
1945
+ {
1946
+ id: "933563129e564b19a115bedd57b7406a",
1947
+ name: "Sarah",
1948
+ gender: "female",
1949
+ languages: ["en"],
1950
+ description: "An engaged speaker.",
1951
+ previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
1952
+ },
1953
+ {
1954
+ id: "bf322df2096a46f18c579d0baa36f41d",
1955
+ name: "Adrian",
1956
+ gender: "male",
1957
+ languages: ["en"],
1958
+ description: "A steady and reliable narrator.",
1959
+ previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
1960
+ },
1961
+ {
1962
+ id: "536d3a5e000945adb7038665781a4aca",
1963
+ name: "Ethan",
1964
+ gender: "male",
1965
+ languages: ["en"],
1966
+ description: "A curious explainer.",
1967
+ previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
1968
+ },
1969
+ {
1970
+ id: "b347db033a6549378b48d00acb0d06cd",
1971
+ name: "Selene",
1972
+ gender: "female",
1973
+ languages: ["en"],
1974
+ description: "A meditative female voice.",
1975
+ previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
1976
+ },
1977
+ {
1978
+ id: "9a9cf47702da476aa4629e2506d4a857",
1979
+ name: "Hannah",
1980
+ gender: "female",
1981
+ languages: ["en"],
1982
+ description: "A conversation specialist.",
1983
+ previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
1984
+ },
1985
+ {
1986
+ id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
1987
+ name: "Jordan",
1988
+ gender: "male",
1989
+ languages: ["en"],
1990
+ description: "A motivational speaker.",
1991
+ previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
1992
+ },
1993
+ {
1994
+ id: "e3cd384158934cc9a01029cd7d278634",
1995
+ name: "Laura",
1996
+ gender: "female",
1997
+ languages: ["en"],
1998
+ description: "A confident female narrator.",
1999
+ previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
2000
+ },
2001
+ {
2002
+ id: "f3a2b90078d54a65af4b95f63bc7798e",
2003
+ name: "Sheila",
2004
+ gender: "female",
2005
+ accent: "american",
2006
+ languages: ["en"],
2007
+ description: "A young American English woman's voice.",
2008
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
2009
+ },
2010
+ {
2011
+ id: "0db6e93af420470b9d9b9a886dbaa954",
2012
+ name: "Kai",
2013
+ gender: "male",
2014
+ languages: ["en"],
2015
+ description: "A friendly English man's voice for companion apps and everyday conversation.",
2016
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
2017
+ },
2018
+ {
2019
+ id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
2020
+ name: "Freya",
2021
+ gender: "female",
2022
+ accent: "british",
2023
+ languages: ["en"],
2024
+ 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.",
2025
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
2026
+ },
2027
+ {
2028
+ id: "2f64e528a4f2406691925ab1e0ed5b7f",
2029
+ name: "Ananya",
2030
+ gender: "female",
2031
+ languages: ["hi"],
2032
+ 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",
2033
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
2034
+ },
2035
+ {
2036
+ id: "cefd91a07b99468f9148e2580990082d",
2037
+ name: "Arjun",
2038
+ gender: "male",
2039
+ languages: ["hi"],
2040
+ 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",
2041
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
2061
2042
  },
2062
2043
  {
2063
- id: "River",
2064
- name: "River",
2065
- gender: "neutral",
2066
- accent: "american",
2067
- languages: ["en", "it", "fr", "pt", "zh"],
2068
- description: "A relaxed, neutral voice ready for narrations or conversational projects.",
2069
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
2044
+ id: "3f065d660212478a9c697fa965b4d098",
2045
+ name: "Carmen",
2046
+ gender: "female",
2047
+ languages: ["es"],
2048
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
2049
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
2070
2050
  },
2071
2051
  {
2072
- id: "Liam",
2073
- name: "Liam",
2052
+ id: "ec0718028a2445fb9be8e8bfb56a0150",
2053
+ name: "Rodrigo",
2074
2054
  gender: "male",
2075
- accent: "american",
2076
- languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
2077
- description: "A young adult with energy and warmth - suitable for reels and shorts.",
2078
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
2055
+ languages: ["es"],
2056
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
2057
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
2079
2058
  },
2080
- { id: "Charlotte", name: "Charlotte" },
2081
2059
  {
2082
- id: "Alice",
2083
- name: "Alice",
2060
+ id: "10a3a20742114a4ea6dd441e7591850f",
2061
+ name: "Manon",
2084
2062
  gender: "female",
2085
- accent: "british",
2086
- languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
2087
- description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
2088
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
2063
+ languages: ["fr"],
2064
+ description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
2065
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
2089
2066
  },
2090
2067
  {
2091
- id: "Matilda",
2092
- name: "Matilda",
2068
+ id: "f69bca092b674168a8d02d61ca20943c",
2069
+ name: "Lucas",
2070
+ gender: "male",
2071
+ languages: ["fr"],
2072
+ description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
2073
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
2074
+ },
2075
+ {
2076
+ id: "3937b44b604249f18b94913daef94043",
2077
+ name: "Lena",
2093
2078
  gender: "female",
2094
- accent: "american",
2095
- languages: ["en", "it", "fr", "de", "ar", "es"],
2096
- description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
2097
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
2079
+ languages: ["de"],
2080
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
2081
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
2098
2082
  },
2099
2083
  {
2100
- id: "Will",
2101
- name: "Will",
2084
+ id: "c1e7cc926aa5469aa966c353094d4b0b",
2085
+ name: "Lukas",
2102
2086
  gender: "male",
2103
- accent: "american",
2104
- languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
2105
- description: "Conversational and laid back.",
2106
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
2087
+ languages: ["de"],
2088
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
2089
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
2107
2090
  },
2108
2091
  {
2109
- id: "Jessica",
2110
- name: "Jessica",
2092
+ id: "b3c060cc41544a7da94a2c487647c902",
2093
+ name: "Let\xEDcia",
2111
2094
  gender: "female",
2112
- accent: "american",
2113
- languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
2114
- description: "Young and popular, this playful American female voice is perfect for trendy content.",
2115
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
2095
+ accent: "brazilian",
2096
+ languages: ["pt"],
2097
+ 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.",
2098
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
2116
2099
  },
2117
2100
  {
2118
- id: "Eric",
2119
- name: "Eric",
2101
+ id: "add7bcb8d3c8423bbfa152ca232aad6e",
2102
+ name: "Ricardo",
2120
2103
  gender: "male",
2121
- accent: "american",
2122
- languages: ["en", "fr", "pt", "de", "sk", "es"],
2123
- description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
2124
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
2104
+ accent: "brazilian",
2105
+ languages: ["pt"],
2106
+ 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.",
2107
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
2125
2108
  },
2126
2109
  {
2127
- id: "Chris",
2128
- name: "Chris",
2129
- gender: "male",
2130
- accent: "american",
2131
- languages: ["en", "fr", "ar", "pt", "sv", "hi"],
2132
- description: "Natural and real, this down-to-earth voice is great across many use-cases.",
2133
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
2110
+ id: "b2d9d8db057042688a5e318b8f405bc2",
2111
+ name: "Kyoko",
2112
+ gender: "female",
2113
+ languages: ["ja"],
2114
+ 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",
2115
+ previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
2134
2116
  },
2135
2117
  {
2136
- id: "Brian",
2137
- name: "Brian",
2118
+ id: "297a6fd278df47c3b9da9bfdf55ac89a",
2119
+ name: "Satoru",
2138
2120
  gender: "male",
2139
- accent: "american",
2140
- languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
2141
- description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
2142
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
2121
+ languages: ["ja"],
2122
+ 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",
2123
+ previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
2143
2124
  },
2144
2125
  {
2145
- id: "Daniel",
2146
- name: "Daniel",
2147
- gender: "male",
2148
- accent: "british",
2149
- languages: ["en", "de", "tr"],
2150
- description: "A strong voice perfect for delivering a professional broadcast or news story.",
2151
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
2126
+ id: "0b14f34a13a94ed88fe6113193749bb0",
2127
+ name: "Fatima",
2128
+ gender: "female",
2129
+ languages: ["ar"],
2130
+ 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.",
2131
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
2152
2132
  },
2153
2133
  {
2154
- id: "Lily",
2155
- name: "Lily",
2134
+ id: "74c6aba5cbf94a15bbdc547ffce5cb38",
2135
+ name: "Yutong",
2156
2136
  gender: "female",
2157
- accent: "british",
2158
- languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
2159
- description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
2160
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
2137
+ languages: ["zh"],
2138
+ 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",
2139
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
2140
+ }
2141
+ ];
2142
+
2143
+ // src/catalog/speech-fish.ts
2144
+ var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
2145
+ var PER_CALL2 = { unit: "images" };
2146
+ var PER_REQUEST2 = { unit: "requests" };
2147
+ var EXPOSURE4 = ["cowork", "space_builder"];
2148
+ var TTS_MAX_CHARS = 1e4;
2149
+ function fishTts(id, label, providerModelId, description) {
2150
+ return {
2151
+ id,
2152
+ aliases: [],
2153
+ label,
2154
+ type: "speech",
2155
+ adapter: "fish",
2156
+ providerModelId,
2157
+ lifecycle: "active",
2158
+ exposure: EXPOSURE4,
2159
+ constraints: {
2160
+ voices: FISH_VOICES,
2161
+ outputFormats: ["mp3", "wav"],
2162
+ supports: [],
2163
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2164
+ },
2165
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2166
+ usage: PER_CALL2,
2167
+ pricingKind: "flat",
2168
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2169
+ capabilities: { customVoices: true }
2170
+ };
2171
+ }
2172
+ var FISH_MODELS = [
2173
+ fishTts(
2174
+ "fish-s2.1-pro",
2175
+ "Fish Audio S2.1 Pro",
2176
+ "s2.1-pro",
2177
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2178
+ ),
2179
+ fishTts(
2180
+ "fish-s2.1-pro-free",
2181
+ "Fish Audio S2.1 Pro Free",
2182
+ "s2.1-pro-free",
2183
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2184
+ ),
2185
+ fishTts(
2186
+ "fish-drama-3",
2187
+ "Fish Audio Drama 3",
2188
+ "drama-3",
2189
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2190
+ ),
2191
+ {
2192
+ id: "fish-voice-clone",
2193
+ aliases: [],
2194
+ label: "Fish Audio Voice Clone",
2195
+ type: "voice-clone",
2196
+ adapter: "fish",
2197
+ providerModelId: "voice-clone",
2198
+ lifecycle: "active",
2199
+ exposure: EXPOSURE4,
2200
+ constraints: {
2201
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2202
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2203
+ supports: []
2204
+ },
2205
+ defaults: {},
2206
+ usage: PER_REQUEST2,
2207
+ pricingKind: "flat",
2208
+ display: {
2209
+ provider: "fishaudio",
2210
+ logo: FISH_LOGO,
2211
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2212
+ },
2213
+ capabilities: {}
2161
2214
  },
2162
2215
  {
2163
- id: "Bill",
2164
- name: "Bill",
2165
- gender: "male",
2166
- accent: "american",
2167
- languages: ["en", "fr", "ar", "zh", "de", "cs"],
2168
- description: "Friendly and comforting voice ready to narrate your stories.",
2169
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
2216
+ id: "fish-voice-design-1",
2217
+ aliases: [],
2218
+ label: "Fish Audio Voice Design",
2219
+ type: "voice-design",
2220
+ adapter: "fish",
2221
+ providerModelId: "voice-design-1",
2222
+ lifecycle: "active",
2223
+ exposure: EXPOSURE4,
2224
+ constraints: {
2225
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2226
+ supports: [],
2227
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2228
+ },
2229
+ defaults: {},
2230
+ usage: PER_REQUEST2,
2231
+ pricingKind: "flat",
2232
+ display: {
2233
+ provider: "fishaudio",
2234
+ logo: FISH_LOGO,
2235
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2236
+ },
2237
+ capabilities: {}
2170
2238
  }
2171
2239
  ];
2172
2240
 
@@ -3745,12 +3813,12 @@ var MINIMAX_VOICES = [
3745
3813
  ];
3746
3814
 
3747
3815
  // src/catalog/media-nodes.ts
3748
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3816
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3749
3817
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3750
3818
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3751
3819
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3752
- var PER_CALL2 = { unit: "images" };
3753
- var EXPOSURE4 = ["cowork", "space_builder"];
3820
+ var PER_CALL3 = { unit: "images" };
3821
+ var EXPOSURE5 = ["cowork", "space_builder"];
3754
3822
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3755
3823
  function elevenLabsTts(tts) {
3756
3824
  return {
@@ -3761,7 +3829,7 @@ function elevenLabsTts(tts) {
3761
3829
  adapter: "fal",
3762
3830
  providerModelId: tts.providerModelId,
3763
3831
  lifecycle: "active",
3764
- exposure: EXPOSURE4,
3832
+ exposure: EXPOSURE5,
3765
3833
  constraints: {
3766
3834
  voices: ELEVENLABS_VOICES,
3767
3835
  languages: tts.languages,
@@ -3770,9 +3838,9 @@ function elevenLabsTts(tts) {
3770
3838
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3771
3839
  },
3772
3840
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3773
- usage: PER_CALL2,
3841
+ usage: PER_CALL3,
3774
3842
  pricingKind: "flat",
3775
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3843
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3776
3844
  capabilities: {}
3777
3845
  };
3778
3846
  }
@@ -3786,7 +3854,7 @@ function geminiTts(id, label, description) {
3786
3854
  adapter: "fal",
3787
3855
  providerModelId,
3788
3856
  lifecycle: "active",
3789
- exposure: EXPOSURE4,
3857
+ exposure: EXPOSURE5,
3790
3858
  constraints: {
3791
3859
  voices: GEMINI_TTS_VOICES,
3792
3860
  supports: ["style"],
@@ -3794,7 +3862,7 @@ function geminiTts(id, label, description) {
3794
3862
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3795
3863
  },
3796
3864
  defaults: { voice: "Kore" },
3797
- usage: PER_CALL2,
3865
+ usage: PER_CALL3,
3798
3866
  pricingKind: "flat",
3799
3867
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3800
3868
  capabilities: {}
@@ -3809,7 +3877,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3809
3877
  adapter: "fal",
3810
3878
  providerModelId,
3811
3879
  lifecycle: "active",
3812
- exposure: EXPOSURE4,
3880
+ exposure: EXPOSURE5,
3813
3881
  constraints: {
3814
3882
  requires: ["sourceVideo", "sourceAudio"],
3815
3883
  references: LIPSYNC_AUDIO,
@@ -3817,7 +3885,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3817
3885
  },
3818
3886
  defaults: {},
3819
3887
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3820
- usage: PER_CALL2,
3888
+ usage: PER_CALL3,
3821
3889
  pricingKind: "flat",
3822
3890
  display: { provider: "sync", logo: SYNC_LOGO, description },
3823
3891
  capabilities: { acceptsSourceVideo: true }
@@ -3870,7 +3938,7 @@ var MEDIA_NODE_MODELS = [
3870
3938
  adapter: "fal",
3871
3939
  providerModelId: "fal-ai/minimax/speech-2.8-hd",
3872
3940
  lifecycle: "active",
3873
- exposure: EXPOSURE4,
3941
+ exposure: EXPOSURE5,
3874
3942
  constraints: {
3875
3943
  voices: MINIMAX_VOICES,
3876
3944
  languages: MINIMAX_SPEECH_LANGUAGES,
@@ -3878,7 +3946,7 @@ var MEDIA_NODE_MODELS = [
3878
3946
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3879
3947
  },
3880
3948
  defaults: { voice: "Wise_Woman" },
3881
- usage: PER_CALL2,
3949
+ usage: PER_CALL3,
3882
3950
  pricingKind: "flat",
3883
3951
  display: {
3884
3952
  provider: "minimax",
@@ -3895,7 +3963,7 @@ var MEDIA_NODE_MODELS = [
3895
3963
  adapter: "fal",
3896
3964
  providerModelId: "fal-ai/elevenlabs/voice-changer",
3897
3965
  lifecycle: "active",
3898
- exposure: EXPOSURE4,
3966
+ exposure: EXPOSURE5,
3899
3967
  constraints: {
3900
3968
  requires: ["sourceAudio"],
3901
3969
  // The flat price assumes at most a minute of speech.
@@ -3905,11 +3973,11 @@ var MEDIA_NODE_MODELS = [
3905
3973
  supports: []
3906
3974
  },
3907
3975
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3908
- usage: PER_CALL2,
3976
+ usage: PER_CALL3,
3909
3977
  pricingKind: "flat",
3910
3978
  display: {
3911
3979
  provider: "elevenlabs",
3912
- logo: ELEVENLABS_LOGO,
3980
+ logo: ELEVENLABS_LOGO2,
3913
3981
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3914
3982
  },
3915
3983
  capabilities: {}
@@ -3922,7 +3990,7 @@ var MEDIA_NODE_MODELS = [
3922
3990
  adapter: "fal",
3923
3991
  providerModelId: "fal-ai/elevenlabs/dubbing",
3924
3992
  lifecycle: "active",
3925
- exposure: EXPOSURE4,
3993
+ exposure: EXPOSURE5,
3926
3994
  constraints: {
3927
3995
  requiresOneOf: ["sourceVideo", "sourceAudio"],
3928
3996
  // The flat price covers 60 s of source.
@@ -3932,11 +4000,11 @@ var MEDIA_NODE_MODELS = [
3932
4000
  supports: []
3933
4001
  },
3934
4002
  defaults: {},
3935
- usage: PER_CALL2,
4003
+ usage: PER_CALL3,
3936
4004
  pricingKind: "flat",
3937
4005
  display: {
3938
4006
  provider: "elevenlabs",
3939
- logo: ELEVENLABS_LOGO,
4007
+ logo: ELEVENLABS_LOGO2,
3940
4008
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3941
4009
  },
3942
4010
  capabilities: { acceptsSourceVideo: true }
@@ -3970,7 +4038,7 @@ var MEDIA_NODE_MODELS = [
3970
4038
  adapter: "fal",
3971
4039
  providerModelId: "veed/lipsync/v2",
3972
4040
  lifecycle: "active",
3973
- exposure: EXPOSURE4,
4041
+ exposure: EXPOSURE5,
3974
4042
  constraints: {
3975
4043
  requires: ["sourceVideo", "sourceAudio"],
3976
4044
  references: LIPSYNC_AUDIO,
@@ -3979,7 +4047,7 @@ var MEDIA_NODE_MODELS = [
3979
4047
  supports: []
3980
4048
  },
3981
4049
  defaults: {},
3982
- usage: PER_CALL2,
4050
+ usage: PER_CALL3,
3983
4051
  pricingKind: "flat",
3984
4052
  display: {
3985
4053
  provider: "veed",
@@ -3996,7 +4064,7 @@ var MEDIA_NODE_MODELS = [
3996
4064
  adapter: "fal",
3997
4065
  providerModelId: "minimax/h3-max/lip-sync/image-to-video",
3998
4066
  lifecycle: "active",
3999
- exposure: EXPOSURE4,
4067
+ exposure: EXPOSURE5,
4000
4068
  constraints: {
4001
4069
  requires: ["firstFrame", "sourceAudio"],
4002
4070
  resolutions: ["480p", "768p", "1080p", "2k"],
@@ -4022,7 +4090,7 @@ var MEDIA_NODE_MODELS = [
4022
4090
  adapter: "fal",
4023
4091
  providerModelId: "fal-ai/elevenlabs/speech-to-text/scribe-v2",
4024
4092
  lifecycle: "active",
4025
- exposure: EXPOSURE4,
4093
+ exposure: EXPOSURE5,
4026
4094
  constraints: {
4027
4095
  requires: ["sourceAudio"],
4028
4096
  // The flat price covers 10 minutes of audio.
@@ -4031,17 +4099,18 @@ var MEDIA_NODE_MODELS = [
4031
4099
  supports: []
4032
4100
  },
4033
4101
  defaults: {},
4034
- usage: PER_CALL2,
4102
+ usage: PER_CALL3,
4035
4103
  pricingKind: "flat",
4036
4104
  display: {
4037
4105
  provider: "elevenlabs",
4038
- logo: ELEVENLABS_LOGO,
4106
+ logo: ELEVENLABS_LOGO2,
4039
4107
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
4040
4108
  },
4041
4109
  capabilities: {}
4042
4110
  },
4043
4111
  SAM_3_IMAGE,
4044
- ...FISH_MODELS
4112
+ ...FISH_MODELS,
4113
+ ...ELEVENLABS_DIRECT_MODELS
4045
4114
  ];
4046
4115
 
4047
4116
  // src/catalog/model3d.ts
@@ -4237,7 +4306,7 @@ var MODEL3D_MODELS = [
4237
4306
 
4238
4307
  // src/catalog/other.ts
4239
4308
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
4240
- var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4309
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4241
4310
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
4242
4311
  var OTHER_MODELS = [
4243
4312
  {
@@ -4402,7 +4471,7 @@ var OTHER_MODELS = [
4402
4471
  pricingKind: "flat",
4403
4472
  display: {
4404
4473
  provider: "elevenlabs",
4405
- logo: ELEVENLABS_LOGO2,
4474
+ logo: ELEVENLABS_LOGO3,
4406
4475
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
4407
4476
  },
4408
4477
  capabilities: {}
@@ -4454,7 +4523,7 @@ var OTHER_MODELS = [
4454
4523
  pricingKind: "flat",
4455
4524
  display: {
4456
4525
  provider: "elevenlabs",
4457
- logo: ELEVENLABS_LOGO2,
4526
+ logo: ELEVENLABS_LOGO3,
4458
4527
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4459
4528
  },
4460
4529
  capabilities: {}
@@ -5636,7 +5705,7 @@ var VIDEO_FAMILY_MODELS = [
5636
5705
 
5637
5706
  // src/catalog/video-luma.ts
5638
5707
  var VIDEO_USAGE2 = { unit: "seconds" };
5639
- var EXPOSURE5 = ["cowork", "space_builder"];
5708
+ var EXPOSURE6 = ["cowork", "space_builder"];
5640
5709
  var LUMA_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/luma-color.png";
5641
5710
  var RAY_RATIOS = ["9:16", "3:4", "1:1", "4:3", "16:9", "21:9"];
5642
5711
  var RAY_RESOLUTIONS = ["360p", "720p", "1080p"];
@@ -5654,7 +5723,7 @@ var LUMA_VIDEO_MODELS = [
5654
5723
  adapter: "luma",
5655
5724
  providerModelId: "ray-3.2",
5656
5725
  lifecycle: "active",
5657
- exposure: EXPOSURE5,
5726
+ exposure: EXPOSURE6,
5658
5727
  constraints: {
5659
5728
  aspectRatios: ["adaptive", ...RAY_RATIOS],
5660
5729
  resolutions: [...RAY_RESOLUTIONS],
@@ -5686,7 +5755,7 @@ var LUMA_VIDEO_MODELS = [
5686
5755
  adapter: "luma",
5687
5756
  providerModelId: "ray-3.2",
5688
5757
  lifecycle: "active",
5689
- exposure: EXPOSURE5,
5758
+ exposure: EXPOSURE6,
5690
5759
  constraints: {
5691
5760
  resolutions: [...RAY_RESOLUTIONS],
5692
5761
  requires: ["sourceVideo"],
@@ -5719,7 +5788,7 @@ var LUMA_VIDEO_MODELS = [
5719
5788
  adapter: "luma",
5720
5789
  providerModelId: "ray-3.2",
5721
5790
  lifecycle: "active",
5722
- exposure: EXPOSURE5,
5791
+ exposure: EXPOSURE6,
5723
5792
  constraints: {
5724
5793
  aspectRatios: [...RAY_RATIOS],
5725
5794
  resolutions: [...RAY_RESOLUTIONS],
@@ -7677,7 +7746,8 @@ var ADAPTER_IDS = [
7677
7746
  "higgsfield",
7678
7747
  "xai-video",
7679
7748
  "luma",
7680
- "fish"
7749
+ "fish",
7750
+ "elevenlabs"
7681
7751
  ];
7682
7752
  var ModelTypeSchema = import_zod3.z.enum([
7683
7753
  "text",
@@ -8890,16 +8960,16 @@ async function generateSeedreamImage(req, ctx) {
8890
8960
  } else {
8891
8961
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8892
8962
  }
8893
- const usage4 = {
8963
+ const usage5 = {
8894
8964
  model: modelId,
8895
8965
  provider: "ark",
8896
8966
  modality: "IMAGE",
8897
8967
  unit: "images",
8898
8968
  quantity: 1
8899
8969
  };
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 };
8970
+ if (req.size !== void 0) usage5.imageSize = req.size;
8971
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8972
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8903
8973
  }
8904
8974
  var SeedanceUsageSchema = import_zod7.z.object({
8905
8975
  total_tokens: import_zod7.z.number().optional(),
@@ -8940,7 +9010,7 @@ function seedanceErrorMessage(error, status) {
8940
9010
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8941
9011
  return `Seedance task ${status}`;
8942
9012
  }
8943
- function seedanceJob(ctx, key, jobId, usage4) {
9013
+ function seedanceJob(ctx, key, jobId, usage5) {
8944
9014
  const modelId = ctx.model.id;
8945
9015
  const fetchStatus = async () => {
8946
9016
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8990,21 +9060,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
8990
9060
  modelId
8991
9061
  );
8992
9062
  if (polled.duration !== void 0 && polled.duration > 0) {
8993
- usage4.quantity = polled.duration;
8994
- usage4.durationSeconds = polled.duration;
9063
+ usage5.quantity = polled.duration;
9064
+ usage5.durationSeconds = polled.duration;
8995
9065
  }
8996
9066
  const rendered = VideoResolutionSchema.safeParse(
8997
9067
  polled.resolution?.toLowerCase()
8998
9068
  );
8999
- if (rendered.success) usage4.resolution = rendered.data;
9069
+ if (rendered.success) usage5.resolution = rendered.data;
9000
9070
  const tokens = polled.usage;
9001
9071
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
9002
- usage4.inputTokens = tokens.total_tokens - tokens.completion_tokens;
9003
- usage4.outputTokens = tokens.completion_tokens;
9072
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
9073
+ usage5.outputTokens = tokens.completion_tokens;
9004
9074
  }
9005
9075
  return {
9006
9076
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
9007
- usage: usage4,
9077
+ usage: usage5,
9008
9078
  raw: polled
9009
9079
  };
9010
9080
  }
@@ -9110,8 +9180,8 @@ async function generateSeedanceVideo(req, ctx) {
9110
9180
  );
9111
9181
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
9112
9182
  const jobId = submit.id;
9113
- const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9114
- return seedanceJob(ctx, key, jobId, usage4);
9183
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9184
+ return seedanceJob(ctx, key, jobId, usage5);
9115
9185
  }
9116
9186
 
9117
9187
  // src/adapters/fal.ts
@@ -10599,7 +10669,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10599
10669
  return { bytes, mime: mime || "image/png" };
10600
10670
  })
10601
10671
  );
10602
- const usage4 = {
10672
+ const usage5 = {
10603
10673
  model: ctx.model.id,
10604
10674
  provider: "fal",
10605
10675
  modality: "IMAGE",
@@ -10607,9 +10677,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10607
10677
  quantity: images.length
10608
10678
  };
10609
10679
  const billedSize = plan4.imageSize ?? req.size;
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 };
10680
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10681
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10682
+ const result = { images, usage: usage5, raw: payload };
10613
10683
  const remote = files.find((f) => !f.url.startsWith("data:"));
10614
10684
  if (remote !== void 0) result.outputUrl = remote.url;
10615
10685
  return result;
@@ -12772,9 +12842,282 @@ function planUsage(ctx, plan4) {
12772
12842
  };
12773
12843
  }
12774
12844
 
12775
- // src/adapters/fish.ts
12845
+ // src/adapters/elevenlabs.ts
12776
12846
  var import_zod21 = require("zod");
12777
- var DEFAULT_BASE_URL = "https://api.fish.audio";
12847
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12848
+ var DEFAULT_FORMAT = "mp3_44100_128";
12849
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12850
+ var ELEVENLABS_IVC = "ivc";
12851
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12852
+ function elevenLabsRowRefusal(row2) {
12853
+ const id = row2.providerModelId;
12854
+ if (row2.type === "speech") {
12855
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12856
+ }
12857
+ if (row2.type === "voice-clone") {
12858
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12859
+ }
12860
+ return `elevenlabs has no ${row2.type} rows`;
12861
+ }
12862
+ function elevenLabsError(ctx, code, message) {
12863
+ return new ModelKitError({
12864
+ code,
12865
+ message,
12866
+ provider: "elevenlabs",
12867
+ model: ctx.model.id,
12868
+ retryable: false
12869
+ });
12870
+ }
12871
+ function checkRow(ctx, type) {
12872
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12873
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12874
+ throw elevenLabsError(
12875
+ ctx,
12876
+ "unsupported_option",
12877
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12878
+ );
12879
+ }
12880
+ }
12881
+ function checkVoiceId(ctx, field, id) {
12882
+ if (!VOICE_ID.test(id))
12883
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12884
+ return id;
12885
+ }
12886
+ function elevenLabsKey(ctx) {
12887
+ const key = ctx.keys.elevenlabs;
12888
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12889
+ return key;
12890
+ }
12891
+ function elevenLabsUrl(ctx, path) {
12892
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12893
+ }
12894
+ var errorDetail = import_zod21.z.object({
12895
+ detail: import_zod21.z.object({ status: import_zod21.z.string(), message: import_zod21.z.string().optional() })
12896
+ });
12897
+ function errorStatus(body) {
12898
+ const parsed = errorDetail.safeParse(body);
12899
+ return parsed.success ? parsed.data.detail : void 0;
12900
+ }
12901
+ function classifyResponse(ctx, status, body) {
12902
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12903
+ const detail = errorStatus(body);
12904
+ if (detail?.status === "voice_limit_reached") {
12905
+ return new ModelKitError({
12906
+ code: "provider_rejected",
12907
+ message: detail.message ?? "ElevenLabs voice limit reached",
12908
+ provider: "elevenlabs",
12909
+ model: ctx.model.id,
12910
+ status,
12911
+ body,
12912
+ cause: error,
12913
+ retryable: false
12914
+ });
12915
+ }
12916
+ if (detail?.status === "quota_exceeded") {
12917
+ return new ModelKitError({
12918
+ code: "provider_billing",
12919
+ message: error.message,
12920
+ provider: "elevenlabs",
12921
+ model: ctx.model.id,
12922
+ status,
12923
+ body,
12924
+ cause: error,
12925
+ retryable: false
12926
+ });
12927
+ }
12928
+ return error;
12929
+ }
12930
+ async function elevenLabsFetch(ctx, path, init) {
12931
+ throwIfAborted(ctx.signal);
12932
+ const request = {
12933
+ method: init.method,
12934
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12935
+ };
12936
+ if (init.body !== void 0) request.body = init.body;
12937
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12938
+ let res;
12939
+ try {
12940
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12941
+ } catch (cause) {
12942
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12943
+ }
12944
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12945
+ return res;
12946
+ }
12947
+ function usage2(ctx) {
12948
+ return {
12949
+ model: ctx.model.id,
12950
+ provider: "elevenlabs",
12951
+ modality: "AUDIO",
12952
+ unit: ctx.model.usage.unit,
12953
+ quantity: 1
12954
+ };
12955
+ }
12956
+ function audioMime(res) {
12957
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12958
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12959
+ }
12960
+ async function generateSpeech(req, ctx) {
12961
+ checkRow(ctx, "speech");
12962
+ const voice = req.customVoice ?? req.voice;
12963
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12964
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12965
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12966
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12967
+ if (req.language !== void 0) body.language_code = req.language;
12968
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12969
+ const { bytes, mime } = await withRetry(
12970
+ async () => {
12971
+ const res = await elevenLabsFetch(ctx, path, {
12972
+ method: "POST",
12973
+ headers: { "Content-Type": "application/json" },
12974
+ body: JSON.stringify(body)
12975
+ });
12976
+ let audio;
12977
+ try {
12978
+ audio = new Uint8Array(await res.arrayBuffer());
12979
+ } catch (cause) {
12980
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12981
+ }
12982
+ return { bytes: audio, mime: audioMime(res) };
12983
+ },
12984
+ mediaRetryOptions(ctx.call, ctx.signal)
12985
+ );
12986
+ if (bytes.byteLength === 0)
12987
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12988
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12989
+ }
12990
+ var createdVoiceSchema = import_zod21.z.object({
12991
+ voice_id: import_zod21.z.string().min(1),
12992
+ requires_verification: import_zod21.z.boolean().optional().catch(void 0)
12993
+ });
12994
+ function sampleMime(mime) {
12995
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12996
+ }
12997
+ function fileName(index, mime, ref) {
12998
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12999
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
13000
+ const ext = fromMime || fromUrl?.toLowerCase();
13001
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
13002
+ }
13003
+ async function cloneForm(req, ctx) {
13004
+ if (req.samples.length === 0)
13005
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
13006
+ if (req.samples.some((s) => s.designSignature?.trim())) {
13007
+ throw elevenLabsError(
13008
+ ctx,
13009
+ "unsupported_option",
13010
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
13011
+ );
13012
+ }
13013
+ const form = new FormData();
13014
+ form.append("name", req.title.trim());
13015
+ if (req.description?.trim()) form.append("description", req.description.trim());
13016
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
13017
+ for (const [index, sample] of req.samples.entries()) {
13018
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
13019
+ signal: ctx.signal,
13020
+ provider: "elevenlabs",
13021
+ model: ctx.model.id
13022
+ });
13023
+ const type = sampleMime(mime);
13024
+ const audio = new Blob([new Uint8Array(bytes)], { type });
13025
+ form.append("files", audio, fileName(index, type, sample.audio));
13026
+ }
13027
+ return form;
13028
+ }
13029
+ async function onlyRateLimitRetries(fn) {
13030
+ try {
13031
+ return await fn();
13032
+ } catch (cause) {
13033
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
13034
+ throw cause;
13035
+ throw new ModelKitError({
13036
+ code: cause.code,
13037
+ message: cause.message,
13038
+ ...cause.provider !== void 0 && { provider: cause.provider },
13039
+ ...cause.model !== void 0 && { model: cause.model },
13040
+ ...cause.status !== void 0 && { status: cause.status },
13041
+ ...cause.body !== void 0 && { body: cause.body },
13042
+ cause,
13043
+ retryable: false
13044
+ });
13045
+ }
13046
+ }
13047
+ async function createVoice(req, ctx) {
13048
+ checkRow(ctx, "voice-clone");
13049
+ const form = await cloneForm(req, ctx);
13050
+ const res = await withRetry(
13051
+ () => onlyRateLimitRetries(
13052
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
13053
+ ),
13054
+ mediaRetryOptions(ctx.call, ctx.signal)
13055
+ );
13056
+ const raw = await readBody(res);
13057
+ const parsed = createdVoiceSchema.safeParse(raw);
13058
+ if (!parsed.success) {
13059
+ throw new ModelKitError({
13060
+ code: "provider_rejected",
13061
+ message: "ElevenLabs returned no voice id",
13062
+ provider: "elevenlabs",
13063
+ model: ctx.model.id,
13064
+ status: res.status,
13065
+ body: raw,
13066
+ retryable: false
13067
+ });
13068
+ }
13069
+ return {
13070
+ voiceId: parsed.data.voice_id,
13071
+ state: parsed.data.requires_verification === true ? "created" : "trained",
13072
+ usage: usage2(ctx),
13073
+ raw
13074
+ };
13075
+ }
13076
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
13077
+ "voice_not_found",
13078
+ "voice_does_not_exist"
13079
+ ]);
13080
+ function notFound(cause) {
13081
+ if (cause.status === 404) return true;
13082
+ const status = errorStatus(cause.body)?.status;
13083
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
13084
+ }
13085
+ async function deleteVoice(req, ctx) {
13086
+ checkRow(ctx, "voice-clone");
13087
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13088
+ let attempts = 0;
13089
+ await withRetry(
13090
+ async () => {
13091
+ attempts += 1;
13092
+ try {
13093
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
13094
+ } catch (cause) {
13095
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
13096
+ if (attempts > 1) return;
13097
+ throw new ModelKitError({
13098
+ code: "provider_rejected",
13099
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13100
+ provider: "elevenlabs",
13101
+ model: ctx.model.id,
13102
+ ...cause.status !== void 0 && { status: cause.status },
13103
+ cause,
13104
+ retryable: false
13105
+ });
13106
+ }
13107
+ },
13108
+ mediaRetryOptions(ctx.call, ctx.signal)
13109
+ );
13110
+ }
13111
+ var elevenLabsAdapter = {
13112
+ id: "elevenlabs",
13113
+ generateSpeech,
13114
+ createVoice,
13115
+ deleteVoice
13116
+ };
13117
+
13118
+ // src/adapters/fish.ts
13119
+ var import_zod22 = require("zod");
13120
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
12778
13121
  var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12779
13122
  "s2.1-pro",
12780
13123
  "s2.1-pro-free",
@@ -12782,7 +13125,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12782
13125
  ]);
12783
13126
  var FISH_VOICE_CLONE = "voice-clone";
12784
13127
  var FISH_VOICE_DESIGN = "voice-design-1";
12785
- var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
13128
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
12786
13129
  function fishRowRefusal(row2) {
12787
13130
  const id = row2.providerModelId;
12788
13131
  if (row2.type === "speech") {
@@ -12805,7 +13148,7 @@ function fishError(ctx, code, message) {
12805
13148
  retryable: false
12806
13149
  });
12807
13150
  }
12808
- function checkRow(ctx, type) {
13151
+ function checkRow2(ctx, type) {
12809
13152
  const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12810
13153
  if (ctx.model.type !== type || refusal2 !== void 0) {
12811
13154
  throw fishError(
@@ -12815,8 +13158,8 @@ function checkRow(ctx, type) {
12815
13158
  );
12816
13159
  }
12817
13160
  }
12818
- function checkVoiceId(ctx, field, id) {
12819
- if (!VOICE_ID.test(id))
13161
+ function checkVoiceId2(ctx, field, id) {
13162
+ if (!VOICE_ID2.test(id))
12820
13163
  throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12821
13164
  return id;
12822
13165
  }
@@ -12826,7 +13169,7 @@ function fishKey(ctx) {
12826
13169
  return key;
12827
13170
  }
12828
13171
  function fishUrl(ctx, path) {
12829
- return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
13172
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
12830
13173
  }
12831
13174
  async function fishFetch(ctx, path, init) {
12832
13175
  throwIfAborted(ctx.signal);
@@ -12845,7 +13188,7 @@ async function fishFetch(ctx, path, init) {
12845
13188
  if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12846
13189
  return res;
12847
13190
  }
12848
- function usage2(ctx) {
13191
+ function usage3(ctx) {
12849
13192
  return {
12850
13193
  model: ctx.model.id,
12851
13194
  provider: "fish",
@@ -12854,18 +13197,18 @@ function usage2(ctx) {
12854
13197
  quantity: 1
12855
13198
  };
12856
13199
  }
12857
- function audioMime(res, format) {
13200
+ function audioMime2(res, format) {
12858
13201
  const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12859
13202
  if (header?.startsWith("audio/")) return header;
12860
13203
  return format === "wav" ? "audio/wav" : "audio/mpeg";
12861
13204
  }
12862
- async function generateSpeech(req, ctx) {
12863
- checkRow(ctx, "speech");
13205
+ async function generateSpeech2(req, ctx) {
13206
+ checkRow2(ctx, "speech");
12864
13207
  const format = req.outputFormat ?? "mp3";
12865
13208
  const body = { text: req.text, format };
12866
13209
  const voice = req.customVoice ?? req.voice;
12867
13210
  if (voice !== void 0) {
12868
- body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
13211
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
12869
13212
  }
12870
13213
  if (req.language !== void 0) body.language = req.language;
12871
13214
  const { bytes, mime } = await withRetry(
@@ -12881,19 +13224,19 @@ async function generateSpeech(req, ctx) {
12881
13224
  } catch (cause) {
12882
13225
  throw classifyThrown("fish", cause, ctx.model.id);
12883
13226
  }
12884
- return { bytes: audio, mime: audioMime(res, format) };
13227
+ return { bytes: audio, mime: audioMime2(res, format) };
12885
13228
  },
12886
13229
  mediaRetryOptions(ctx.call, ctx.signal)
12887
13230
  );
12888
13231
  if (bytes.byteLength === 0)
12889
13232
  throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12890
- return { audio: { bytes, mime }, usage: usage2(ctx) };
13233
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
12891
13234
  }
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)
13235
+ var createdModelSchema = import_zod22.z.object({
13236
+ _id: import_zod22.z.string().min(1),
13237
+ state: import_zod22.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12895
13238
  });
12896
- function fileName(index, mime) {
13239
+ function fileName2(index, mime) {
12897
13240
  const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12898
13241
  return `sample-${index + 1}.${ext}`;
12899
13242
  }
@@ -12905,7 +13248,7 @@ function allOrNone(ctx, field, values) {
12905
13248
  }
12906
13249
  return set;
12907
13250
  }
12908
- async function cloneForm(req, ctx) {
13251
+ async function cloneForm2(req, ctx) {
12909
13252
  if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12910
13253
  const transcripts = allOrNone(
12911
13254
  ctx,
@@ -12931,13 +13274,13 @@ async function cloneForm(req, ctx) {
12931
13274
  model: ctx.model.id
12932
13275
  });
12933
13276
  const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12934
- form.append("voices", audio, fileName(index, mime));
13277
+ form.append("voices", audio, fileName2(index, mime));
12935
13278
  }
12936
13279
  for (const text2 of transcripts) form.append("texts", text2.trim());
12937
13280
  for (const signature of signatures) form.append("voice_design_signatures", signature);
12938
13281
  return form;
12939
13282
  }
12940
- async function onlyRateLimitRetries(fn) {
13283
+ async function onlyRateLimitRetries2(fn) {
12941
13284
  try {
12942
13285
  return await fn();
12943
13286
  } catch (cause) {
@@ -12955,11 +13298,11 @@ async function onlyRateLimitRetries(fn) {
12955
13298
  });
12956
13299
  }
12957
13300
  }
12958
- async function createVoice(req, ctx) {
12959
- checkRow(ctx, "voice-clone");
12960
- const form = await cloneForm(req, ctx);
13301
+ async function createVoice2(req, ctx) {
13302
+ checkRow2(ctx, "voice-clone");
13303
+ const form = await cloneForm2(req, ctx);
12961
13304
  const res = await withRetry(
12962
- () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13305
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12963
13306
  mediaRetryOptions(ctx.call, ctx.signal)
12964
13307
  );
12965
13308
  const raw = await readBody(res);
@@ -12975,23 +13318,23 @@ async function createVoice(req, ctx) {
12975
13318
  retryable: false
12976
13319
  });
12977
13320
  }
12978
- const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
13321
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
12979
13322
  if (parsed.data.state !== void 0) result.state = parsed.data.state;
12980
13323
  return result;
12981
13324
  }
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()
13325
+ var designSchema = import_zod22.z.object({
13326
+ candidates: import_zod22.z.array(
13327
+ import_zod22.z.looseObject({
13328
+ id: import_zod22.z.string().min(1),
13329
+ index: import_zod22.z.number().int(),
13330
+ audio_base64: import_zod22.z.string().min(1),
13331
+ duration_ms: import_zod22.z.number().nonnegative(),
13332
+ signature: import_zod22.z.string().min(1).optional()
12990
13333
  })
12991
13334
  ).min(1)
12992
13335
  });
12993
13336
  async function designVoice(req, ctx) {
12994
- checkRow(ctx, "voice-design");
13337
+ checkRow2(ctx, "voice-design");
12995
13338
  const body = { instruction: req.prompt.trim() };
12996
13339
  if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12997
13340
  if (req.language !== void 0) body.language = req.language;
@@ -13019,11 +13362,11 @@ async function designVoice(req, ctx) {
13019
13362
  // rejects a clone whose signature does not verify, so a wrong one fails loudly.
13020
13363
  signature: c.signature ?? c.id
13021
13364
  }));
13022
- return { candidates, usage: usage2(ctx) };
13365
+ return { candidates, usage: usage3(ctx) };
13023
13366
  }
13024
- async function deleteVoice(req, ctx) {
13025
- checkRow(ctx, "voice-clone");
13026
- const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13367
+ async function deleteVoice2(req, ctx) {
13368
+ checkRow2(ctx, "voice-clone");
13369
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
13027
13370
  let attempts = 0;
13028
13371
  await withRetry(
13029
13372
  async () => {
@@ -13049,18 +13392,18 @@ async function deleteVoice(req, ctx) {
13049
13392
  }
13050
13393
  var fishAdapter = {
13051
13394
  id: "fish",
13052
- generateSpeech,
13053
- createVoice,
13395
+ generateSpeech: generateSpeech2,
13396
+ createVoice: createVoice2,
13054
13397
  designVoice,
13055
- deleteVoice
13398
+ deleteVoice: deleteVoice2
13056
13399
  };
13057
13400
 
13058
13401
  // src/adapters/google-genai.ts
13059
- var import_zod23 = require("zod");
13402
+ var import_zod24 = require("zod");
13060
13403
  var import_genai = require("@google/genai");
13061
13404
 
13062
13405
  // src/adapters/google-files.ts
13063
- var import_zod22 = require("zod");
13406
+ var import_zod23 = require("zod");
13064
13407
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
13065
13408
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
13066
13409
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -13070,17 +13413,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
13070
13413
  "binary/octet-stream",
13071
13414
  "application/binary"
13072
13415
  ]);
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()
13416
+ var uploadedFileSchema = import_zod23.z.object({
13417
+ file: import_zod23.z.object({
13418
+ uri: import_zod23.z.string().optional(),
13419
+ name: import_zod23.z.string().optional(),
13420
+ state: import_zod23.z.string().optional(),
13421
+ mimeType: import_zod23.z.string().optional()
13079
13422
  }).optional()
13080
13423
  });
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()
13424
+ var fileStateSchema = import_zod23.z.object({
13425
+ state: import_zod23.z.string().optional(),
13426
+ error: import_zod23.z.object({ message: import_zod23.z.string().optional() }).optional()
13084
13427
  });
13085
13428
  function resolveMime(declared, fallback) {
13086
13429
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -13187,7 +13530,7 @@ async function startAndUpload(bytes, mimeType, opts) {
13187
13530
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
13188
13531
  return ref;
13189
13532
  }
13190
- async function waitForActive(fileName2, opts) {
13533
+ async function waitForActive(fileName3, opts) {
13191
13534
  const pollOptions2 = {
13192
13535
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
13193
13536
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -13200,14 +13543,14 @@ async function waitForActive(fileName2, opts) {
13200
13543
  retryInit.signal = opts.signal;
13201
13544
  }
13202
13545
  await pollUntil(async () => {
13203
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
13546
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
13204
13547
  if (res.ok) {
13205
13548
  const json = fileStateSchema.parse(await res.json());
13206
13549
  if (json.state === "ACTIVE") return true;
13207
13550
  if (json.state === "FAILED") {
13208
13551
  throw classifyHttpError(
13209
13552
  void 0,
13210
- `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
13553
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
13211
13554
  "google-genai",
13212
13555
  opts.model
13213
13556
  );
@@ -13219,9 +13562,9 @@ async function waitForActive(fileName2, opts) {
13219
13562
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
13220
13563
  }, pollOptions2);
13221
13564
  }
13222
- async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
13565
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
13223
13566
  try {
13224
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
13567
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
13225
13568
  method: "DELETE",
13226
13569
  headers: { "x-goog-api-key": apiKey }
13227
13570
  });
@@ -13301,7 +13644,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
13301
13644
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
13302
13645
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
13303
13646
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
13304
- var errorTextSchema = import_zod23.z.string();
13647
+ var errorTextSchema = import_zod24.z.string();
13305
13648
  function isGoogleGenaiVideoKnown(providerModelId) {
13306
13649
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
13307
13650
  }
@@ -13496,7 +13839,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13496
13839
  }
13497
13840
  };
13498
13841
  const jobId = operation.name ?? crypto.randomUUID();
13499
- const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13842
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13500
13843
  return {
13501
13844
  jobId,
13502
13845
  async poll() {
@@ -13534,7 +13877,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13534
13877
  modelId
13535
13878
  );
13536
13879
  }
13537
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
13880
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
13538
13881
  }
13539
13882
  };
13540
13883
  }
@@ -13645,7 +13988,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13645
13988
  return file.fileUri;
13646
13989
  };
13647
13990
  const cleanupUploads = async () => {
13648
- for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
13991
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
13649
13992
  };
13650
13993
  const callCreate = (input) => client2.interactions.create(
13651
13994
  previousId !== void 0 ? {
@@ -13739,7 +14082,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13739
14082
  if (!(extend && !chained)) await cleanupUploads();
13740
14083
  }
13741
14084
  const jobId = interaction.id ?? crypto.randomUUID();
13742
- const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
14085
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13743
14086
  const getInteraction = async () => {
13744
14087
  try {
13745
14088
  const getParams = { stream: false };
@@ -13787,7 +14130,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13787
14130
  bytes: Buffer.from(video.data, "base64"),
13788
14131
  mime: video.mime_type ?? "video/mp4"
13789
14132
  },
13790
- usage: usage4,
14133
+ usage: usage5,
13791
14134
  raw: done,
13792
14135
  providerRef
13793
14136
  };
@@ -13795,7 +14138,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13795
14138
  if (video.uri)
13796
14139
  return {
13797
14140
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13798
- usage: usage4,
14141
+ usage: usage5,
13799
14142
  raw: done,
13800
14143
  providerRef
13801
14144
  };
@@ -13965,15 +14308,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13965
14308
  // src/adapters/google-image.ts
13966
14309
  var import_google2 = require("@ai-sdk/google");
13967
14310
  var import_ai2 = require("ai");
13968
- var import_zod24 = require("zod");
14311
+ var import_zod25 = require("zod");
13969
14312
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13970
14313
  var defaultGoogleImageDeps = {
13971
14314
  createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
13972
14315
  runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
13973
14316
  };
13974
- var causeChainNodeSchema = import_zod24.z.object({
13975
- message: import_zod24.z.string().optional(),
13976
- cause: import_zod24.z.unknown().optional()
14317
+ var causeChainNodeSchema = import_zod25.z.object({
14318
+ message: import_zod25.z.string().optional(),
14319
+ cause: import_zod25.z.unknown().optional()
13977
14320
  });
13978
14321
  function extractBlockReason(cause) {
13979
14322
  let current = cause;
@@ -14073,7 +14416,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
14073
14416
  retryable: false
14074
14417
  });
14075
14418
  }
14076
- const usage4 = {
14419
+ const usage5 = {
14077
14420
  model: ctx.model.id,
14078
14421
  provider: "google-image",
14079
14422
  modality: "IMAGE",
@@ -14081,19 +14424,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
14081
14424
  quantity: images.length,
14082
14425
  imageQuality: "auto"
14083
14426
  };
14084
- if (req.size !== void 0) usage4.imageSize = req.size;
14427
+ if (req.size !== void 0) usage5.imageSize = req.size;
14085
14428
  if (result.usage?.inputTokens !== void 0)
14086
- usage4.inputTokens = result.usage.inputTokens;
14429
+ usage5.inputTokens = result.usage.inputTokens;
14087
14430
  if (result.usage?.outputTokens !== void 0)
14088
- usage4.outputTokens = result.usage.outputTokens;
14089
- return { images, usage: usage4, raw: result };
14431
+ usage5.outputTokens = result.usage.outputTokens;
14432
+ return { images, usage: usage5, raw: result };
14090
14433
  }
14091
14434
  };
14092
14435
  }
14093
14436
  var googleImageAdapter = createGoogleImageAdapter();
14094
14437
 
14095
14438
  // src/adapters/higgsfield.ts
14096
- var import_zod25 = require("zod");
14439
+ var import_zod26 = require("zod");
14097
14440
 
14098
14441
  // src/adapters/higgsfield-motions.ts
14099
14442
  var MOTION_MAP = {
@@ -14312,14 +14655,14 @@ function klingEndpointFields(providerModelId) {
14312
14655
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
14313
14656
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
14314
14657
  }
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(),
14658
+ var klingCreateSchema = import_zod26.z.object({ status_url: import_zod26.z.string() });
14659
+ var klingStatusSchema = import_zod26.z.object({
14660
+ status: import_zod26.z.string().optional(),
14661
+ video: import_zod26.z.object({ url: import_zod26.z.string().optional() }).optional(),
14319
14662
  error: JsonValueSchema.optional()
14320
14663
  });
14321
- var errorMessageSchema = import_zod25.z.object({ message: import_zod25.z.string().optional() });
14322
- var textValueSchema = import_zod25.z.string();
14664
+ var errorMessageSchema = import_zod26.z.object({ message: import_zod26.z.string().optional() });
14665
+ var textValueSchema = import_zod26.z.string();
14323
14666
  function klingErrorDetail(error) {
14324
14667
  if (error === void 0) return "unknown_error";
14325
14668
  const asText = textValueSchema.safeParse(error);
@@ -14475,8 +14818,8 @@ async function generateKlingVideo(req, ctx) {
14475
14818
  }
14476
14819
  };
14477
14820
  }
14478
- var dopMotionOptionsSchema = import_zod25.z.object({
14479
- modelkit: import_zod25.z.object({ motion: import_zod25.z.string().optional() }).optional()
14821
+ var dopMotionOptionsSchema = import_zod26.z.object({
14822
+ modelkit: import_zod26.z.object({ motion: import_zod26.z.string().optional() }).optional()
14480
14823
  });
14481
14824
  function dopMotionId(ctx) {
14482
14825
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -14492,7 +14835,7 @@ function dopMotionId(ctx) {
14492
14835
  });
14493
14836
  return id;
14494
14837
  }
14495
- var jsonRecordSchema = import_zod25.z.record(import_zod25.z.string(), JsonValueSchema);
14838
+ var jsonRecordSchema = import_zod26.z.record(import_zod26.z.string(), JsonValueSchema);
14496
14839
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
14497
14840
  var DOP_NESTED_KEYS = ["video", "result", "results"];
14498
14841
  function dopUrl(body) {
@@ -14520,8 +14863,8 @@ function dopUrl(body) {
14520
14863
  }
14521
14864
  return void 0;
14522
14865
  }
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() });
14866
+ var dopCreateSchema = import_zod26.z.object({ id: import_zod26.z.string() });
14867
+ var dopStatusSchema = import_zod26.z.object({ status: import_zod26.z.string().optional() });
14525
14868
  async function generateDopVideo(req, ctx) {
14526
14869
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
14527
14870
  if (!firstFrame) {
@@ -14648,7 +14991,7 @@ var higgsfieldAdapter = {
14648
14991
  };
14649
14992
 
14650
14993
  // src/adapters/luma.ts
14651
- var import_zod26 = require("zod");
14994
+ var import_zod27 = require("zod");
14652
14995
 
14653
14996
  // src/adapters/mp4-duration.ts
14654
14997
  function mp4DurationSeconds(bytes) {
@@ -14704,7 +15047,7 @@ function findBox(bytes, from, to, type) {
14704
15047
  }
14705
15048
 
14706
15049
  // src/adapters/luma.ts
14707
- var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
15050
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
14708
15051
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14709
15052
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14710
15053
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14733,7 +15076,7 @@ function lumaModel(ctx) {
14733
15076
  return ctx.model.providerModelId.toLowerCase();
14734
15077
  }
14735
15078
  function lumaBase(ctx) {
14736
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
15079
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14737
15080
  }
14738
15081
  function lumaKey(ctx) {
14739
15082
  const key = ctx.keys.luma;
@@ -14865,17 +15208,17 @@ function lumaReframeResolution(req, ctx) {
14865
15208
  });
14866
15209
  return "720p";
14867
15210
  }
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()
15211
+ var lumaGenerationSchema = import_zod27.z.looseObject({
15212
+ id: import_zod27.z.string(),
15213
+ state: import_zod27.z.string().optional(),
15214
+ output: import_zod27.z.array(
15215
+ import_zod27.z.looseObject({
15216
+ type: import_zod27.z.string().optional(),
15217
+ url: import_zod27.z.string().optional()
14875
15218
  })
14876
15219
  ).optional(),
14877
- failure_reason: import_zod26.z.string().optional().nullable(),
14878
- failure_code: import_zod26.z.string().optional().nullable()
15220
+ failure_reason: import_zod27.z.string().optional().nullable(),
15221
+ failure_code: import_zod27.z.string().optional().nullable()
14879
15222
  });
14880
15223
  function lumaFailure(ctx, code, reason) {
14881
15224
  const detail = reason ?? code ?? "unknown_error";
@@ -15307,7 +15650,7 @@ var lumaAdapter = {
15307
15650
 
15308
15651
  // src/adapters/openai-image.ts
15309
15652
  var import_openai2 = __toESM(require("openai"), 1);
15310
- var import_zod27 = require("zod");
15653
+ var import_zod28 = require("zod");
15311
15654
  var MAX_EDIT_REFERENCES = 16;
15312
15655
  function aspectRatioToSize(ratio, tier) {
15313
15656
  const TIER_LONG_EDGE = {
@@ -15390,9 +15733,9 @@ function toProviderError2(cause, ctx) {
15390
15733
  ctx.model.id
15391
15734
  );
15392
15735
  }
15393
- var openaiUsageSchema = import_zod27.z.object({
15394
- input_tokens: import_zod27.z.number().optional(),
15395
- output_tokens: import_zod27.z.number().optional()
15736
+ var openaiUsageSchema = import_zod28.z.object({
15737
+ input_tokens: import_zod28.z.number().optional(),
15738
+ output_tokens: import_zod28.z.number().optional()
15396
15739
  });
15397
15740
  var openaiImageAdapter = {
15398
15741
  id: "openai-image",
@@ -15517,7 +15860,7 @@ var openaiImageAdapter = {
15517
15860
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
15518
15861
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
15519
15862
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
15520
- const usage4 = {
15863
+ const usage5 = {
15521
15864
  model: ctx.model.id,
15522
15865
  provider: "openai-image",
15523
15866
  modality: "IMAGE",
@@ -15525,10 +15868,10 @@ var openaiImageAdapter = {
15525
15868
  quantity: images.length,
15526
15869
  imageQuality: quality
15527
15870
  };
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 };
15871
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15872
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15873
+ if (req.size !== void 0) usage5.imageSize = req.size;
15874
+ return { images, usage: usage5, raw: response };
15532
15875
  }
15533
15876
  };
15534
15877
 
@@ -15784,16 +16127,16 @@ async function generateProdiaImage(req, ctx) {
15784
16127
  new Uint8Array(await res.arrayBuffer()),
15785
16128
  res.headers.get("content-type")
15786
16129
  );
15787
- const usage4 = {
16130
+ const usage5 = {
15788
16131
  model: ctx.model.id,
15789
16132
  provider: "prodia",
15790
16133
  modality: "IMAGE",
15791
16134
  unit: "images",
15792
16135
  quantity: 1
15793
16136
  };
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 };
16137
+ if (req.size !== void 0) usage5.imageSize = req.size;
16138
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
16139
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15797
16140
  }
15798
16141
  var prodiaAdapter = {
15799
16142
  id: "prodia",
@@ -15804,13 +16147,13 @@ var prodiaAdapter = {
15804
16147
  var import_replicate = __toESM(require("replicate"), 1);
15805
16148
 
15806
16149
  // src/adapters/replicate-http.ts
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(),
16150
+ var import_zod29 = require("zod");
16151
+ var predictionSchema = import_zod29.z.object({
16152
+ id: import_zod29.z.string(),
16153
+ status: import_zod29.z.string(),
15811
16154
  output: JsonValueSchema.optional(),
15812
16155
  error: JsonValueSchema.optional(),
15813
- metrics: import_zod28.z.object({ predict_time: import_zod28.z.number().optional() }).optional()
16156
+ metrics: import_zod29.z.object({ predict_time: import_zod29.z.number().optional() }).optional()
15814
16157
  });
15815
16158
  function createReplicateHttpClient(opts) {
15816
16159
  async function request(path, body, signal) {
@@ -15861,7 +16204,7 @@ function createReplicateHttpClient(opts) {
15861
16204
  }
15862
16205
 
15863
16206
  // src/adapters/replicate.ts
15864
- var import_zod29 = require("zod");
16207
+ var import_zod30 = require("zod");
15865
16208
  var POLL_INTERVAL_MS = 1e3;
15866
16209
  var POLL_TIMEOUT_MS = 15 * 6e4;
15867
16210
  var defaultReplicateDeps = {
@@ -15901,8 +16244,8 @@ function route(providerModelId) {
15901
16244
  if (!providerModelId.includes("/")) return { version: providerModelId };
15902
16245
  return { model: providerModelId };
15903
16246
  }
15904
- var replicateResponseStatusSchema = import_zod29.z.object({
15905
- response: import_zod29.z.object({ status: import_zod29.z.number() }).partial()
16247
+ var replicateResponseStatusSchema = import_zod30.z.object({
16248
+ response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
15906
16249
  });
15907
16250
  function replicateError(cause, ctx) {
15908
16251
  if (isModelKitError(cause)) return cause;
@@ -15925,7 +16268,7 @@ function isUrlFn(value) {
15925
16268
  function extractOutputUrl(output) {
15926
16269
  const root = Array.isArray(output) ? output[0] : output;
15927
16270
  if (root === void 0) throw noOutput();
15928
- const asString = import_zod29.z.string().safeParse(root);
16271
+ const asString = import_zod30.z.string().safeParse(root);
15929
16272
  if (asString.success && asString.data) return asString.data;
15930
16273
  if (root instanceof URL) return root.href;
15931
16274
  if (isObjectOutput(root)) {
@@ -15934,15 +16277,15 @@ function extractOutputUrl(output) {
15934
16277
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15935
16278
  const called = urlValue();
15936
16279
  if (called instanceof URL) return called.href;
15937
- const calledString = import_zod29.z.string().safeParse(called);
16280
+ const calledString = import_zod30.z.string().safeParse(called);
15938
16281
  if (calledString.success && calledString.data) return calledString.data;
15939
16282
  } else {
15940
- const direct = import_zod29.z.string().safeParse(urlValue);
16283
+ const direct = import_zod30.z.string().safeParse(urlValue);
15941
16284
  if (direct.success && direct.data) return direct.data;
15942
16285
  }
15943
16286
  }
15944
16287
  if ("default" in root) {
15945
- const fallback = import_zod29.z.string().safeParse(root.default);
16288
+ const fallback = import_zod30.z.string().safeParse(root.default);
15946
16289
  if (fallback.success && fallback.data) return fallback.data;
15947
16290
  }
15948
16291
  }
@@ -16003,7 +16346,7 @@ async function runPrediction(ctx, input, deps) {
16003
16346
  }
16004
16347
  return void 0;
16005
16348
  }, pollOpts);
16006
- const predictTime = import_zod29.z.number().safeParse(done.metrics?.predict_time);
16349
+ const predictTime = import_zod30.z.number().safeParse(done.metrics?.predict_time);
16007
16350
  if (done.output === void 0) throw noOutput();
16008
16351
  return {
16009
16352
  url: extractOutputUrl(done.output),
@@ -16249,9 +16592,9 @@ async function generateReplicateImage(req, ctx, deps) {
16249
16592
  }
16250
16593
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16251
16594
  const file = await download(ctx, 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 };
16595
+ const usage5 = imageUsage3(ctx, req);
16596
+ usage5.quantity = predictTime;
16597
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
16255
16598
  }
16256
16599
  function klingInput(req) {
16257
16600
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -16356,7 +16699,7 @@ async function generateReplicateVideo(req, ctx, deps) {
16356
16699
  throw replicateError(cause, ctx);
16357
16700
  }
16358
16701
  if (current.status === "succeeded") {
16359
- const predictTime = import_zod29.z.number().safeParse(current.metrics?.predict_time);
16702
+ const predictTime = import_zod30.z.number().safeParse(current.metrics?.predict_time);
16360
16703
  if (current.output === void 0) throw noOutput();
16361
16704
  return {
16362
16705
  url: extractOutputUrl(current.output),
@@ -16375,9 +16718,9 @@ async function generateReplicateVideo(req, ctx, deps) {
16375
16718
  return void 0;
16376
16719
  };
16377
16720
  const toResult = (done) => {
16378
- const usage4 = videoUsage5(ctx, req);
16379
- usage4.quantity = done.predictTime;
16380
- return { video: { url: done.url }, usage: usage4, raw: done.raw };
16721
+ const usage5 = videoUsage5(ctx, req);
16722
+ usage5.quantity = done.predictTime;
16723
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
16381
16724
  };
16382
16725
  return {
16383
16726
  jobId,
@@ -16484,21 +16827,21 @@ async function generateReplicateAudio(req, ctx, deps) {
16484
16827
  input = specResult.input;
16485
16828
  }
16486
16829
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16487
- const usage4 = audioUsage(ctx, req);
16830
+ const usage5 = audioUsage(ctx, req);
16488
16831
  if (ctx.model.usage.unit === "seconds") {
16489
16832
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
16490
- usage4.quantity = seconds3;
16491
- usage4.durationSeconds = seconds3;
16833
+ usage5.quantity = seconds3;
16834
+ usage5.durationSeconds = seconds3;
16492
16835
  } else {
16493
- usage4.quantity = predictTime;
16836
+ usage5.quantity = predictTime;
16494
16837
  }
16495
- return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
16838
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
16496
16839
  }
16497
16840
 
16498
16841
  // src/adapters/xai-video.ts
16499
16842
  var import_ai3 = require("ai");
16500
16843
  var import_xai2 = require("@ai-sdk/xai");
16501
- var import_zod30 = require("zod");
16844
+ var import_zod31 = require("zod");
16502
16845
  var POLL_INTERVAL_MS2 = 1e4;
16503
16846
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
16504
16847
  var defaultXaiDeps = {
@@ -16511,8 +16854,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
16511
16854
  };
16512
16855
  }
16513
16856
  var xaiVideoAdapter = createXaiVideoAdapter();
16514
- var xaiResponseStatusSchema = import_zod30.z.object({
16515
- response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
16857
+ var xaiResponseStatusSchema = import_zod31.z.object({
16858
+ response: import_zod31.z.object({ status: import_zod31.z.number() }).partial()
16516
16859
  });
16517
16860
  function xaiError(cause, ctx) {
16518
16861
  const info = describeThrown(cause);
@@ -16520,12 +16863,12 @@ function xaiError(cause, ctx) {
16520
16863
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
16521
16864
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
16522
16865
  }
16523
- var xaiMetaSchema = import_zod30.z.object({
16866
+ var xaiMetaSchema = import_zod31.z.object({
16524
16867
  videoUrl: JsonValueSchema.optional(),
16525
16868
  costInUsdTicks: JsonValueSchema.optional(),
16526
16869
  duration: JsonValueSchema.optional()
16527
16870
  });
16528
- var xaiProviderMetadataSchema = import_zod30.z.object({ xai: xaiMetaSchema });
16871
+ var xaiProviderMetadataSchema = import_zod31.z.object({ xai: xaiMetaSchema });
16529
16872
  function metaOf(result) {
16530
16873
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
16531
16874
  if (!parsed.success) return {};
@@ -16637,12 +16980,12 @@ async function mapResult(ctx, req, result) {
16637
16980
  if (first) {
16638
16981
  return {
16639
16982
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16640
- usage: usage3(ctx, req, metaOf(result)),
16983
+ usage: usage4(ctx, req, metaOf(result)),
16641
16984
  raw: result.providerMetadata
16642
16985
  };
16643
16986
  }
16644
16987
  const meta = metaOf(result);
16645
- const videoUrl = import_zod30.z.string().safeParse(meta.videoUrl);
16988
+ const videoUrl = import_zod31.z.string().safeParse(meta.videoUrl);
16646
16989
  if (videoUrl.success && videoUrl.data) {
16647
16990
  const res = await ctx.fetch(videoUrl.data);
16648
16991
  if (!res.ok) {
@@ -16652,7 +16995,7 @@ async function mapResult(ctx, req, result) {
16652
16995
  const mime = res.headers.get("content-type") ?? "video/mp4";
16653
16996
  return {
16654
16997
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16655
- usage: usage3(ctx, req, meta),
16998
+ usage: usage4(ctx, req, meta),
16656
16999
  raw: result.providerMetadata
16657
17000
  };
16658
17001
  }
@@ -16664,8 +17007,8 @@ async function mapResult(ctx, req, result) {
16664
17007
  retryable: false
16665
17008
  });
16666
17009
  }
16667
- function usage3(ctx, req, meta) {
16668
- const costTicks = import_zod30.z.number().safeParse(meta.costInUsdTicks);
17010
+ function usage4(ctx, req, meta) {
17011
+ const costTicks = import_zod31.z.number().safeParse(meta.costInUsdTicks);
16669
17012
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16670
17013
  const event = {
16671
17014
  model: ctx.model.id,
@@ -16705,7 +17048,8 @@ var DEFAULT_ADAPTERS = {
16705
17048
  higgsfield: higgsfieldAdapter,
16706
17049
  "xai-video": xaiVideoAdapter,
16707
17050
  luma: lumaAdapter,
16708
- fish: fishAdapter
17051
+ fish: fishAdapter,
17052
+ elevenlabs: elevenLabsAdapter
16709
17053
  };
16710
17054
 
16711
17055
  // src/catalog/data-only.ts
@@ -16744,15 +17088,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16744
17088
  "transcription",
16745
17089
  "mask"
16746
17090
  ]);
16747
- function fishSpeech(row2) {
16748
- return row2.adapter === "fish" && row2.type === "speech";
17091
+ function directSpeech(row2) {
17092
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
16749
17093
  }
16750
17094
  function dataOnlyCapable(row2) {
16751
17095
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16752
17096
  if (!adapterServesType(adapter, row2.type)) {
16753
17097
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16754
17098
  }
16755
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
17099
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16756
17100
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16757
17101
  }
16758
17102
  switch (row2.adapter) {
@@ -16834,6 +17178,10 @@ function dataOnlyCapable(row2) {
16834
17178
  const reason = fishRowRefusal(row2);
16835
17179
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16836
17180
  }
17181
+ case "elevenlabs": {
17182
+ const reason = elevenLabsRowRefusal(row2);
17183
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17184
+ }
16837
17185
  default: {
16838
17186
  return assertNever(row2.adapter);
16839
17187
  }
@@ -16853,22 +17201,22 @@ var liveState = store[KEY] ??= {
16853
17201
  var liveCatalog = liveState.catalog;
16854
17202
 
16855
17203
  // src/catalog/load.ts
16856
- var import_zod31 = require("zod");
17204
+ var import_zod32 = require("zod");
16857
17205
  function rowCount() {
16858
17206
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16859
17207
  }
16860
17208
  function authHeaders(auth) {
16861
17209
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16862
17210
  }
16863
- var EnvelopeSchema = import_zod31.z.object({
16864
- rows: import_zod31.z.array(JsonValueSchema),
16865
- revision: import_zod31.z.string().optional()
17211
+ var EnvelopeSchema = import_zod32.z.object({
17212
+ rows: import_zod32.z.array(JsonValueSchema),
17213
+ revision: import_zod32.z.string().optional()
16866
17214
  });
16867
17215
  function dropReason(path, message) {
16868
17216
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16869
17217
  }
16870
17218
  function rowId(raw) {
16871
- const parsed = import_zod31.z.object({ id: import_zod31.z.string().min(1) }).loose().safeParse(raw);
17219
+ const parsed = import_zod32.z.object({ id: import_zod32.z.string().min(1) }).loose().safeParse(raw);
16872
17220
  if (!parsed.success) return "?";
16873
17221
  return parsed.data.id;
16874
17222
  }
@@ -18029,7 +18377,8 @@ var ADAPTER_KEYS = {
18029
18377
  higgsfield: ["higgsfield"],
18030
18378
  "xai-video": ["xai"],
18031
18379
  luma: ["luma"],
18032
- fish: ["fish"]
18380
+ fish: ["fish"],
18381
+ elevenlabs: ["elevenlabs"]
18033
18382
  };
18034
18383
  function hasAll(keys, names) {
18035
18384
  if (!keys) return false;
@@ -18089,6 +18438,7 @@ function keysFromEnv(env, prefix = "") {
18089
18438
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
18090
18439
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
18091
18440
  set("fish", pick2("FISH_AUDIO_API_KEY"));
18441
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
18092
18442
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
18093
18443
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
18094
18444
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -18111,7 +18461,7 @@ function keysFromEnv(env, prefix = "") {
18111
18461
 
18112
18462
  // src/text.ts
18113
18463
  var import_ai4 = require("ai");
18114
- var import_zod32 = require("zod");
18464
+ var import_zod33 = require("zod");
18115
18465
  function mergeTextProviderOptions(catalog, caller) {
18116
18466
  const merged = {};
18117
18467
  const catalogOptions = catalog.providerOptions ?? {};
@@ -18150,17 +18500,17 @@ function passthroughTextModel(model) {
18150
18500
  pricingKind: "token"
18151
18501
  };
18152
18502
  }
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() }) })
18503
+ var perplexityCostSchema = import_zod33.z.object({
18504
+ perplexity: import_zod33.z.object({ cost: import_zod33.z.object({ totalCost: import_zod33.z.number().finite().nonnegative() }) })
18155
18505
  });
18156
18506
  function reportedCostUsd(metadata) {
18157
18507
  const parsed = perplexityCostSchema.safeParse(metadata);
18158
18508
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
18159
18509
  }
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;
18510
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18511
+ const inputTokens = usage5.inputTokens ?? 0;
18512
+ const outputTokens = usage5.outputTokens ?? 0;
18513
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
18164
18514
  const event = {
18165
18515
  model: model.id,
18166
18516
  provider,
@@ -18195,7 +18545,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18195
18545
  return { ...prepared, providerOptions };
18196
18546
  };
18197
18547
  }
18198
- function usage4(results) {
18548
+ function usage5(results) {
18199
18549
  const grouped = /* @__PURE__ */ new Map();
18200
18550
  for (const [index, step] of results.entries()) {
18201
18551
  const target = steps.get(index) ?? initial;
@@ -18219,12 +18569,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18219
18569
  }
18220
18570
  return [...grouped.values()];
18221
18571
  }
18222
- return { wrap, usage: usage4 };
18572
+ return { wrap, usage: usage5 };
18223
18573
  }
18224
18574
 
18225
18575
  // src/client.ts
18226
18576
  var import_ai5 = require("ai");
18227
- var import_zod33 = require("zod");
18577
+ var import_zod34 = require("zod");
18228
18578
 
18229
18579
  // src/generated-image.ts
18230
18580
  function toGeneratedImage(image) {
@@ -18346,9 +18696,9 @@ function providerJobMethods(kind, deps) {
18346
18696
  if (!methods.result) throw missing3(adapter, ctx.model);
18347
18697
  const result = await methods.result(sub, ctx, webhook);
18348
18698
  const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
18349
- const usage4 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18350
- await deps.emit(usage4);
18351
- return { ...result, usage: usage4 };
18699
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18700
+ await deps.emit(usage5);
18701
+ return { ...result, usage: usage5 };
18352
18702
  },
18353
18703
  async cancel(sub, call = {}) {
18354
18704
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -18588,10 +18938,10 @@ function audioNodeMethods(deps) {
18588
18938
  const startedAt = Date.now();
18589
18939
  const outcome = await adapter.dub(resolved, ctx);
18590
18940
  if (outcome.kind === "audio") {
18591
- const { audio, usage: usage4, raw } = outcome.result;
18941
+ const { audio, usage: usage5, raw } = outcome.result;
18592
18942
  return {
18593
18943
  audio,
18594
- usage: await deps.settle(model, usage4, startedAt),
18944
+ usage: await deps.settle(model, usage5, startedAt),
18595
18945
  ...raw !== void 0 && { raw }
18596
18946
  };
18597
18947
  }
@@ -18629,10 +18979,10 @@ function textAbortOptions(sdk, context) {
18629
18979
  if (abortSignal) return { abortSignal };
18630
18980
  return {};
18631
18981
  }
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"]);
18982
+ var catalogId = import_zod34.z.string();
18983
+ var exactSize = import_zod34.z.templateLiteral([import_zod34.z.number(), "x", import_zod34.z.number()]);
18984
+ var sdkRatio = import_zod34.z.templateLiteral([import_zod34.z.number(), ":", import_zod34.z.number()]);
18985
+ var sizeTier = import_zod34.z.enum(["512", "1K", "2K", "4K"]);
18636
18986
  function isCatalogId(model) {
18637
18987
  return catalogId.safeParse(model).success;
18638
18988
  }
@@ -18845,7 +19195,7 @@ function createModelKit(config, adapters) {
18845
19195
  const images = result.images.map(
18846
19196
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18847
19197
  );
18848
- const usage4 = timed(
19198
+ const usage5 = timed(
18849
19199
  {
18850
19200
  model: model.modelId,
18851
19201
  provider: model.provider,
@@ -18855,8 +19205,8 @@ function createModelKit(config, adapters) {
18855
19205
  },
18856
19206
  startedAt
18857
19207
  );
18858
- await emit(usage4);
18859
- return { image: images[0], images, usage: usage4, raw: result, warnings };
19208
+ await emit(usage5);
19209
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
18860
19210
  }
18861
19211
  function passthroughVideo(req, call) {
18862
19212
  const {
@@ -18932,7 +19282,7 @@ function createModelKit(config, adapters) {
18932
19282
  let settled;
18933
19283
  let failed = false;
18934
19284
  const done = pending.then(async (result) => {
18935
- const usage4 = timed(
19285
+ const usage5 = timed(
18936
19286
  {
18937
19287
  model: model.modelId,
18938
19288
  provider: model.provider,
@@ -18945,10 +19295,10 @@ function createModelKit(config, adapters) {
18945
19295
  );
18946
19296
  settled = {
18947
19297
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18948
- usage: usage4,
19298
+ usage: usage5,
18949
19299
  raw: result
18950
19300
  };
18951
- await emit(usage4);
19301
+ await emit(usage5);
18952
19302
  return settled;
18953
19303
  });
18954
19304
  done.catch(() => {
@@ -18975,12 +19325,12 @@ function createModelKit(config, adapters) {
18975
19325
  if (settled) return settled;
18976
19326
  const pending = result(opts).then(
18977
19327
  async (out) => {
18978
- const usage4 = timed(
19328
+ const usage5 = timed(
18979
19329
  { ...out.usage, model: model.id, unit: model.usage.unit },
18980
19330
  startedAt
18981
19331
  );
18982
- await emit(usage4);
18983
- return { ...out, usage: usage4 };
19332
+ await emit(usage5);
19333
+ return { ...out, usage: usage5 };
18984
19334
  },
18985
19335
  (cause) => {
18986
19336
  settled = void 0;
@@ -19000,9 +19350,9 @@ function createModelKit(config, adapters) {
19000
19350
  return context(model, signal ? { ...call, signal } : call, warnings);
19001
19351
  },
19002
19352
  async settle(model, event, startedAt) {
19003
- const usage4 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19004
- await emit(usage4);
19005
- return usage4;
19353
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19354
+ await emit(usage5);
19355
+ return usage5;
19006
19356
  },
19007
19357
  wrapVideoJob
19008
19358
  });
@@ -19038,11 +19388,11 @@ function createModelKit(config, adapters) {
19038
19388
  });
19039
19389
  const startedAt = Date.now();
19040
19390
  const result = await adapter.generateImage(request, ctx);
19041
- const usage4 = timed(
19391
+ const usage5 = timed(
19042
19392
  { ...result.usage, model: model.id, unit: model.usage.unit },
19043
19393
  startedAt
19044
19394
  );
19045
- await emit(usage4);
19395
+ await emit(usage5);
19046
19396
  const images = result.images.map(toGeneratedImage);
19047
19397
  const first = images[0];
19048
19398
  if (!first)
@@ -19051,7 +19401,7 @@ function createModelKit(config, adapters) {
19051
19401
  message: `${model.id} returned no image`,
19052
19402
  model: model.id
19053
19403
  });
19054
- return { ...result, usage: usage4, image: first, images, warnings };
19404
+ return { ...result, usage: usage5, image: first, images, warnings };
19055
19405
  },
19056
19406
  async generateVideo(req, call = {}) {
19057
19407
  mediaRetryOptions(call);
@@ -19150,12 +19500,12 @@ function createModelKit(config, adapters) {
19150
19500
  }
19151
19501
  const startedAt = Date.now();
19152
19502
  const result = await adapter.generateAudio(resolved, ctx);
19153
- const usage4 = timed(
19503
+ const usage5 = timed(
19154
19504
  { ...result.usage, model: model.id, unit: model.usage.unit },
19155
19505
  startedAt
19156
19506
  );
19157
- await emit(usage4);
19158
- return { ...result, usage: usage4 };
19507
+ await emit(usage5);
19508
+ return { ...result, usage: usage5 };
19159
19509
  },
19160
19510
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
19161
19511
  mediaRetryOptions(call);
@@ -19235,8 +19585,8 @@ function createModelKit(config, adapters) {
19235
19585
  options.prepareStep ?? options.experimental_prepareStep
19236
19586
  ),
19237
19587
  onFinish: async (event) => {
19238
- for (const usage4 of steps.usage(event.steps))
19239
- await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
19588
+ for (const usage5 of steps.usage(event.steps))
19589
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
19240
19590
  await callerOnFinish?.(event);
19241
19591
  }
19242
19592
  });
@@ -19355,6 +19705,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
19355
19705
  dataOnlyCapable,
19356
19706
  describe,
19357
19707
  describeThrown,
19708
+ elevenLabsAdapter,
19358
19709
  experimental_generateImage,
19359
19710
  falAdapter,
19360
19711
  falWebhookBodySchema,