@shop-os/modelkit 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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" },
@@ -2042,131 +1746,494 @@ var ELEVENLABS_VOICES = [
2042
1746
  previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/IKne3meq5aSn9XLyUdCD/102de6f2-22ed-43e0-a1f1-111fa75c5481.mp3"
2043
1747
  },
2044
1748
  {
2045
- id: "George",
2046
- name: "George",
2047
- gender: "male",
1749
+ id: "George",
1750
+ name: "George",
1751
+ gender: "male",
1752
+ accent: "british",
1753
+ languages: ["en", "fr", "ar", "ja", "cs", "fil", "es", "hi"],
1754
+ description: "Warm resonance that instantly captivates listeners.",
1755
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3"
1756
+ },
1757
+ {
1758
+ id: "Callum",
1759
+ name: "Callum",
1760
+ gender: "male",
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",
2048
2022
  accent: "british",
2049
- languages: ["en", "fr", "ar", "ja", "cs", "fil", "es", "hi"],
2050
- description: "Warm resonance that instantly captivates listeners.",
2051
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3"
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"
2052
2026
  },
2053
2027
  {
2054
- id: "Callum",
2055
- name: "Callum",
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",
2056
2038
  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"
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 TTS_MAX_CHARS = 1e4;
2148
+ function fishTts(id, label, providerModelId, description) {
2149
+ return {
2150
+ id,
2151
+ aliases: [],
2152
+ label,
2153
+ type: "speech",
2154
+ adapter: "fish",
2155
+ providerModelId,
2156
+ lifecycle: "active",
2157
+ exposure: [],
2158
+ constraints: {
2159
+ voices: FISH_VOICES,
2160
+ outputFormats: ["mp3", "wav"],
2161
+ supports: [],
2162
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2163
+ },
2164
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2165
+ usage: PER_CALL2,
2166
+ pricingKind: "flat",
2167
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2168
+ capabilities: { customVoices: true }
2169
+ };
2170
+ }
2171
+ var FISH_MODELS = [
2172
+ fishTts(
2173
+ "fish-s2.1-pro",
2174
+ "Fish Audio S2.1 Pro",
2175
+ "s2.1-pro",
2176
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2177
+ ),
2178
+ fishTts(
2179
+ "fish-s2.1-pro-free",
2180
+ "Fish Audio S2.1 Pro Free",
2181
+ "s2.1-pro-free",
2182
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2183
+ ),
2184
+ fishTts(
2185
+ "fish-drama-3",
2186
+ "Fish Audio Drama 3",
2187
+ "drama-3",
2188
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2189
+ ),
2190
+ {
2191
+ id: "fish-voice-clone",
2192
+ aliases: [],
2193
+ label: "Fish Audio Voice Clone",
2194
+ type: "voice-clone",
2195
+ adapter: "fish",
2196
+ providerModelId: "voice-clone",
2197
+ lifecycle: "active",
2198
+ exposure: [],
2199
+ constraints: {
2200
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2201
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2202
+ supports: []
2203
+ },
2204
+ defaults: {},
2205
+ usage: PER_REQUEST2,
2206
+ pricingKind: "flat",
2207
+ display: {
2208
+ provider: "fishaudio",
2209
+ logo: FISH_LOGO,
2210
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2211
+ },
2212
+ capabilities: {}
2161
2213
  },
2162
2214
  {
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"
2215
+ id: "fish-voice-design-1",
2216
+ aliases: [],
2217
+ label: "Fish Audio Voice Design",
2218
+ type: "voice-design",
2219
+ adapter: "fish",
2220
+ providerModelId: "voice-design-1",
2221
+ lifecycle: "active",
2222
+ exposure: [],
2223
+ constraints: {
2224
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2225
+ supports: [],
2226
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2227
+ },
2228
+ defaults: {},
2229
+ usage: PER_REQUEST2,
2230
+ pricingKind: "flat",
2231
+ display: {
2232
+ provider: "fishaudio",
2233
+ logo: FISH_LOGO,
2234
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2235
+ },
2236
+ capabilities: {}
2170
2237
  }
2171
2238
  ];
2172
2239
 
@@ -3745,11 +3812,11 @@ var MINIMAX_VOICES = [
3745
3812
  ];
3746
3813
 
3747
3814
  // src/catalog/media-nodes.ts
3748
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3815
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3749
3816
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3750
3817
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3751
3818
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3752
- var PER_CALL2 = { unit: "images" };
3819
+ var PER_CALL3 = { unit: "images" };
3753
3820
  var EXPOSURE4 = ["cowork", "space_builder"];
3754
3821
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3755
3822
  function elevenLabsTts(tts) {
@@ -3770,9 +3837,9 @@ function elevenLabsTts(tts) {
3770
3837
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3771
3838
  },
3772
3839
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3773
- usage: PER_CALL2,
3840
+ usage: PER_CALL3,
3774
3841
  pricingKind: "flat",
3775
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3842
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3776
3843
  capabilities: {}
3777
3844
  };
3778
3845
  }
@@ -3794,7 +3861,7 @@ function geminiTts(id, label, description) {
3794
3861
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3795
3862
  },
3796
3863
  defaults: { voice: "Kore" },
3797
- usage: PER_CALL2,
3864
+ usage: PER_CALL3,
3798
3865
  pricingKind: "flat",
3799
3866
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3800
3867
  capabilities: {}
@@ -3817,7 +3884,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3817
3884
  },
3818
3885
  defaults: {},
3819
3886
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3820
- usage: PER_CALL2,
3887
+ usage: PER_CALL3,
3821
3888
  pricingKind: "flat",
3822
3889
  display: { provider: "sync", logo: SYNC_LOGO, description },
3823
3890
  capabilities: { acceptsSourceVideo: true }
@@ -3878,7 +3945,7 @@ var MEDIA_NODE_MODELS = [
3878
3945
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3879
3946
  },
3880
3947
  defaults: { voice: "Wise_Woman" },
3881
- usage: PER_CALL2,
3948
+ usage: PER_CALL3,
3882
3949
  pricingKind: "flat",
3883
3950
  display: {
3884
3951
  provider: "minimax",
@@ -3905,11 +3972,11 @@ var MEDIA_NODE_MODELS = [
3905
3972
  supports: []
3906
3973
  },
3907
3974
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3908
- usage: PER_CALL2,
3975
+ usage: PER_CALL3,
3909
3976
  pricingKind: "flat",
3910
3977
  display: {
3911
3978
  provider: "elevenlabs",
3912
- logo: ELEVENLABS_LOGO,
3979
+ logo: ELEVENLABS_LOGO2,
3913
3980
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3914
3981
  },
3915
3982
  capabilities: {}
@@ -3932,11 +3999,11 @@ var MEDIA_NODE_MODELS = [
3932
3999
  supports: []
3933
4000
  },
3934
4001
  defaults: {},
3935
- usage: PER_CALL2,
4002
+ usage: PER_CALL3,
3936
4003
  pricingKind: "flat",
3937
4004
  display: {
3938
4005
  provider: "elevenlabs",
3939
- logo: ELEVENLABS_LOGO,
4006
+ logo: ELEVENLABS_LOGO2,
3940
4007
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3941
4008
  },
3942
4009
  capabilities: { acceptsSourceVideo: true }
@@ -3979,7 +4046,7 @@ var MEDIA_NODE_MODELS = [
3979
4046
  supports: []
3980
4047
  },
3981
4048
  defaults: {},
3982
- usage: PER_CALL2,
4049
+ usage: PER_CALL3,
3983
4050
  pricingKind: "flat",
3984
4051
  display: {
3985
4052
  provider: "veed",
@@ -4031,17 +4098,18 @@ var MEDIA_NODE_MODELS = [
4031
4098
  supports: []
4032
4099
  },
4033
4100
  defaults: {},
4034
- usage: PER_CALL2,
4101
+ usage: PER_CALL3,
4035
4102
  pricingKind: "flat",
4036
4103
  display: {
4037
4104
  provider: "elevenlabs",
4038
- logo: ELEVENLABS_LOGO,
4105
+ logo: ELEVENLABS_LOGO2,
4039
4106
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
4040
4107
  },
4041
4108
  capabilities: {}
4042
4109
  },
4043
4110
  SAM_3_IMAGE,
4044
- ...FISH_MODELS
4111
+ ...FISH_MODELS,
4112
+ ...ELEVENLABS_DIRECT_MODELS
4045
4113
  ];
4046
4114
 
4047
4115
  // src/catalog/model3d.ts
@@ -4237,7 +4305,7 @@ var MODEL3D_MODELS = [
4237
4305
 
4238
4306
  // src/catalog/other.ts
4239
4307
  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";
4308
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4241
4309
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
4242
4310
  var OTHER_MODELS = [
4243
4311
  {
@@ -4402,7 +4470,7 @@ var OTHER_MODELS = [
4402
4470
  pricingKind: "flat",
4403
4471
  display: {
4404
4472
  provider: "elevenlabs",
4405
- logo: ELEVENLABS_LOGO2,
4473
+ logo: ELEVENLABS_LOGO3,
4406
4474
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
4407
4475
  },
4408
4476
  capabilities: {}
@@ -4454,7 +4522,7 @@ var OTHER_MODELS = [
4454
4522
  pricingKind: "flat",
4455
4523
  display: {
4456
4524
  provider: "elevenlabs",
4457
- logo: ELEVENLABS_LOGO2,
4525
+ logo: ELEVENLABS_LOGO3,
4458
4526
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4459
4527
  },
4460
4528
  capabilities: {}
@@ -7677,7 +7745,8 @@ var ADAPTER_IDS = [
7677
7745
  "higgsfield",
7678
7746
  "xai-video",
7679
7747
  "luma",
7680
- "fish"
7748
+ "fish",
7749
+ "elevenlabs"
7681
7750
  ];
7682
7751
  var ModelTypeSchema = import_zod3.z.enum([
7683
7752
  "text",
@@ -8890,16 +8959,16 @@ async function generateSeedreamImage(req, ctx) {
8890
8959
  } else {
8891
8960
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8892
8961
  }
8893
- const usage4 = {
8962
+ const usage5 = {
8894
8963
  model: modelId,
8895
8964
  provider: "ark",
8896
8965
  modality: "IMAGE",
8897
8966
  unit: "images",
8898
8967
  quantity: 1
8899
8968
  };
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 };
8969
+ if (req.size !== void 0) usage5.imageSize = req.size;
8970
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8971
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8903
8972
  }
8904
8973
  var SeedanceUsageSchema = import_zod7.z.object({
8905
8974
  total_tokens: import_zod7.z.number().optional(),
@@ -8940,7 +9009,7 @@ function seedanceErrorMessage(error, status) {
8940
9009
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8941
9010
  return `Seedance task ${status}`;
8942
9011
  }
8943
- function seedanceJob(ctx, key, jobId, usage4) {
9012
+ function seedanceJob(ctx, key, jobId, usage5) {
8944
9013
  const modelId = ctx.model.id;
8945
9014
  const fetchStatus = async () => {
8946
9015
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8990,21 +9059,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
8990
9059
  modelId
8991
9060
  );
8992
9061
  if (polled.duration !== void 0 && polled.duration > 0) {
8993
- usage4.quantity = polled.duration;
8994
- usage4.durationSeconds = polled.duration;
9062
+ usage5.quantity = polled.duration;
9063
+ usage5.durationSeconds = polled.duration;
8995
9064
  }
8996
9065
  const rendered = VideoResolutionSchema.safeParse(
8997
9066
  polled.resolution?.toLowerCase()
8998
9067
  );
8999
- if (rendered.success) usage4.resolution = rendered.data;
9068
+ if (rendered.success) usage5.resolution = rendered.data;
9000
9069
  const tokens = polled.usage;
9001
9070
  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;
9071
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
9072
+ usage5.outputTokens = tokens.completion_tokens;
9004
9073
  }
9005
9074
  return {
9006
9075
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
9007
- usage: usage4,
9076
+ usage: usage5,
9008
9077
  raw: polled
9009
9078
  };
9010
9079
  }
@@ -9110,8 +9179,8 @@ async function generateSeedanceVideo(req, ctx) {
9110
9179
  );
9111
9180
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
9112
9181
  const jobId = submit.id;
9113
- const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9114
- return seedanceJob(ctx, key, jobId, usage4);
9182
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9183
+ return seedanceJob(ctx, key, jobId, usage5);
9115
9184
  }
9116
9185
 
9117
9186
  // src/adapters/fal.ts
@@ -10599,7 +10668,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10599
10668
  return { bytes, mime: mime || "image/png" };
10600
10669
  })
10601
10670
  );
10602
- const usage4 = {
10671
+ const usage5 = {
10603
10672
  model: ctx.model.id,
10604
10673
  provider: "fal",
10605
10674
  modality: "IMAGE",
@@ -10607,9 +10676,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10607
10676
  quantity: images.length
10608
10677
  };
10609
10678
  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 };
10679
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10680
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10681
+ const result = { images, usage: usage5, raw: payload };
10613
10682
  const remote = files.find((f) => !f.url.startsWith("data:"));
10614
10683
  if (remote !== void 0) result.outputUrl = remote.url;
10615
10684
  return result;
@@ -12772,9 +12841,282 @@ function planUsage(ctx, plan4) {
12772
12841
  };
12773
12842
  }
12774
12843
 
12775
- // src/adapters/fish.ts
12844
+ // src/adapters/elevenlabs.ts
12776
12845
  var import_zod21 = require("zod");
12777
- var DEFAULT_BASE_URL = "https://api.fish.audio";
12846
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12847
+ var DEFAULT_FORMAT = "mp3_44100_128";
12848
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12849
+ var ELEVENLABS_IVC = "ivc";
12850
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12851
+ function elevenLabsRowRefusal(row2) {
12852
+ const id = row2.providerModelId;
12853
+ if (row2.type === "speech") {
12854
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12855
+ }
12856
+ if (row2.type === "voice-clone") {
12857
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12858
+ }
12859
+ return `elevenlabs has no ${row2.type} rows`;
12860
+ }
12861
+ function elevenLabsError(ctx, code, message) {
12862
+ return new ModelKitError({
12863
+ code,
12864
+ message,
12865
+ provider: "elevenlabs",
12866
+ model: ctx.model.id,
12867
+ retryable: false
12868
+ });
12869
+ }
12870
+ function checkRow(ctx, type) {
12871
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12872
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12873
+ throw elevenLabsError(
12874
+ ctx,
12875
+ "unsupported_option",
12876
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12877
+ );
12878
+ }
12879
+ }
12880
+ function checkVoiceId(ctx, field, id) {
12881
+ if (!VOICE_ID.test(id))
12882
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12883
+ return id;
12884
+ }
12885
+ function elevenLabsKey(ctx) {
12886
+ const key = ctx.keys.elevenlabs;
12887
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12888
+ return key;
12889
+ }
12890
+ function elevenLabsUrl(ctx, path) {
12891
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12892
+ }
12893
+ var errorDetail = import_zod21.z.object({
12894
+ detail: import_zod21.z.object({ status: import_zod21.z.string(), message: import_zod21.z.string().optional() })
12895
+ });
12896
+ function errorStatus(body) {
12897
+ const parsed = errorDetail.safeParse(body);
12898
+ return parsed.success ? parsed.data.detail : void 0;
12899
+ }
12900
+ function classifyResponse(ctx, status, body) {
12901
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12902
+ const detail = errorStatus(body);
12903
+ if (detail?.status === "voice_limit_reached") {
12904
+ return new ModelKitError({
12905
+ code: "provider_rejected",
12906
+ message: detail.message ?? "ElevenLabs voice limit reached",
12907
+ provider: "elevenlabs",
12908
+ model: ctx.model.id,
12909
+ status,
12910
+ body,
12911
+ cause: error,
12912
+ retryable: false
12913
+ });
12914
+ }
12915
+ if (detail?.status === "quota_exceeded") {
12916
+ return new ModelKitError({
12917
+ code: "provider_billing",
12918
+ message: error.message,
12919
+ provider: "elevenlabs",
12920
+ model: ctx.model.id,
12921
+ status,
12922
+ body,
12923
+ cause: error,
12924
+ retryable: false
12925
+ });
12926
+ }
12927
+ return error;
12928
+ }
12929
+ async function elevenLabsFetch(ctx, path, init) {
12930
+ throwIfAborted(ctx.signal);
12931
+ const request = {
12932
+ method: init.method,
12933
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12934
+ };
12935
+ if (init.body !== void 0) request.body = init.body;
12936
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12937
+ let res;
12938
+ try {
12939
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12940
+ } catch (cause) {
12941
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12942
+ }
12943
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12944
+ return res;
12945
+ }
12946
+ function usage2(ctx) {
12947
+ return {
12948
+ model: ctx.model.id,
12949
+ provider: "elevenlabs",
12950
+ modality: "AUDIO",
12951
+ unit: ctx.model.usage.unit,
12952
+ quantity: 1
12953
+ };
12954
+ }
12955
+ function audioMime(res) {
12956
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12957
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12958
+ }
12959
+ async function generateSpeech(req, ctx) {
12960
+ checkRow(ctx, "speech");
12961
+ const voice = req.customVoice ?? req.voice;
12962
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12963
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12964
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12965
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12966
+ if (req.language !== void 0) body.language_code = req.language;
12967
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12968
+ const { bytes, mime } = await withRetry(
12969
+ async () => {
12970
+ const res = await elevenLabsFetch(ctx, path, {
12971
+ method: "POST",
12972
+ headers: { "Content-Type": "application/json" },
12973
+ body: JSON.stringify(body)
12974
+ });
12975
+ let audio;
12976
+ try {
12977
+ audio = new Uint8Array(await res.arrayBuffer());
12978
+ } catch (cause) {
12979
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12980
+ }
12981
+ return { bytes: audio, mime: audioMime(res) };
12982
+ },
12983
+ mediaRetryOptions(ctx.call, ctx.signal)
12984
+ );
12985
+ if (bytes.byteLength === 0)
12986
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12987
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12988
+ }
12989
+ var createdVoiceSchema = import_zod21.z.object({
12990
+ voice_id: import_zod21.z.string().min(1),
12991
+ requires_verification: import_zod21.z.boolean().optional().catch(void 0)
12992
+ });
12993
+ function sampleMime(mime) {
12994
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12995
+ }
12996
+ function fileName(index, mime, ref) {
12997
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12998
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
12999
+ const ext = fromMime || fromUrl?.toLowerCase();
13000
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
13001
+ }
13002
+ async function cloneForm(req, ctx) {
13003
+ if (req.samples.length === 0)
13004
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
13005
+ if (req.samples.some((s) => s.designSignature?.trim())) {
13006
+ throw elevenLabsError(
13007
+ ctx,
13008
+ "unsupported_option",
13009
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
13010
+ );
13011
+ }
13012
+ const form = new FormData();
13013
+ form.append("name", req.title.trim());
13014
+ if (req.description?.trim()) form.append("description", req.description.trim());
13015
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
13016
+ for (const [index, sample] of req.samples.entries()) {
13017
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
13018
+ signal: ctx.signal,
13019
+ provider: "elevenlabs",
13020
+ model: ctx.model.id
13021
+ });
13022
+ const type = sampleMime(mime);
13023
+ const audio = new Blob([new Uint8Array(bytes)], { type });
13024
+ form.append("files", audio, fileName(index, type, sample.audio));
13025
+ }
13026
+ return form;
13027
+ }
13028
+ async function onlyRateLimitRetries(fn) {
13029
+ try {
13030
+ return await fn();
13031
+ } catch (cause) {
13032
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
13033
+ throw cause;
13034
+ throw new ModelKitError({
13035
+ code: cause.code,
13036
+ message: cause.message,
13037
+ ...cause.provider !== void 0 && { provider: cause.provider },
13038
+ ...cause.model !== void 0 && { model: cause.model },
13039
+ ...cause.status !== void 0 && { status: cause.status },
13040
+ ...cause.body !== void 0 && { body: cause.body },
13041
+ cause,
13042
+ retryable: false
13043
+ });
13044
+ }
13045
+ }
13046
+ async function createVoice(req, ctx) {
13047
+ checkRow(ctx, "voice-clone");
13048
+ const form = await cloneForm(req, ctx);
13049
+ const res = await withRetry(
13050
+ () => onlyRateLimitRetries(
13051
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
13052
+ ),
13053
+ mediaRetryOptions(ctx.call, ctx.signal)
13054
+ );
13055
+ const raw = await readBody(res);
13056
+ const parsed = createdVoiceSchema.safeParse(raw);
13057
+ if (!parsed.success) {
13058
+ throw new ModelKitError({
13059
+ code: "provider_rejected",
13060
+ message: "ElevenLabs returned no voice id",
13061
+ provider: "elevenlabs",
13062
+ model: ctx.model.id,
13063
+ status: res.status,
13064
+ body: raw,
13065
+ retryable: false
13066
+ });
13067
+ }
13068
+ return {
13069
+ voiceId: parsed.data.voice_id,
13070
+ state: parsed.data.requires_verification === true ? "created" : "trained",
13071
+ usage: usage2(ctx),
13072
+ raw
13073
+ };
13074
+ }
13075
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
13076
+ "voice_not_found",
13077
+ "voice_does_not_exist"
13078
+ ]);
13079
+ function notFound(cause) {
13080
+ if (cause.status === 404) return true;
13081
+ const status = errorStatus(cause.body)?.status;
13082
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
13083
+ }
13084
+ async function deleteVoice(req, ctx) {
13085
+ checkRow(ctx, "voice-clone");
13086
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13087
+ let attempts = 0;
13088
+ await withRetry(
13089
+ async () => {
13090
+ attempts += 1;
13091
+ try {
13092
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
13093
+ } catch (cause) {
13094
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
13095
+ if (attempts > 1) return;
13096
+ throw new ModelKitError({
13097
+ code: "provider_rejected",
13098
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13099
+ provider: "elevenlabs",
13100
+ model: ctx.model.id,
13101
+ ...cause.status !== void 0 && { status: cause.status },
13102
+ cause,
13103
+ retryable: false
13104
+ });
13105
+ }
13106
+ },
13107
+ mediaRetryOptions(ctx.call, ctx.signal)
13108
+ );
13109
+ }
13110
+ var elevenLabsAdapter = {
13111
+ id: "elevenlabs",
13112
+ generateSpeech,
13113
+ createVoice,
13114
+ deleteVoice
13115
+ };
13116
+
13117
+ // src/adapters/fish.ts
13118
+ var import_zod22 = require("zod");
13119
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
12778
13120
  var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12779
13121
  "s2.1-pro",
12780
13122
  "s2.1-pro-free",
@@ -12782,7 +13124,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12782
13124
  ]);
12783
13125
  var FISH_VOICE_CLONE = "voice-clone";
12784
13126
  var FISH_VOICE_DESIGN = "voice-design-1";
12785
- var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
13127
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
12786
13128
  function fishRowRefusal(row2) {
12787
13129
  const id = row2.providerModelId;
12788
13130
  if (row2.type === "speech") {
@@ -12805,7 +13147,7 @@ function fishError(ctx, code, message) {
12805
13147
  retryable: false
12806
13148
  });
12807
13149
  }
12808
- function checkRow(ctx, type) {
13150
+ function checkRow2(ctx, type) {
12809
13151
  const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12810
13152
  if (ctx.model.type !== type || refusal2 !== void 0) {
12811
13153
  throw fishError(
@@ -12815,8 +13157,8 @@ function checkRow(ctx, type) {
12815
13157
  );
12816
13158
  }
12817
13159
  }
12818
- function checkVoiceId(ctx, field, id) {
12819
- if (!VOICE_ID.test(id))
13160
+ function checkVoiceId2(ctx, field, id) {
13161
+ if (!VOICE_ID2.test(id))
12820
13162
  throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12821
13163
  return id;
12822
13164
  }
@@ -12826,7 +13168,7 @@ function fishKey(ctx) {
12826
13168
  return key;
12827
13169
  }
12828
13170
  function fishUrl(ctx, path) {
12829
- return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
13171
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
12830
13172
  }
12831
13173
  async function fishFetch(ctx, path, init) {
12832
13174
  throwIfAborted(ctx.signal);
@@ -12845,7 +13187,7 @@ async function fishFetch(ctx, path, init) {
12845
13187
  if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12846
13188
  return res;
12847
13189
  }
12848
- function usage2(ctx) {
13190
+ function usage3(ctx) {
12849
13191
  return {
12850
13192
  model: ctx.model.id,
12851
13193
  provider: "fish",
@@ -12854,18 +13196,18 @@ function usage2(ctx) {
12854
13196
  quantity: 1
12855
13197
  };
12856
13198
  }
12857
- function audioMime(res, format) {
13199
+ function audioMime2(res, format) {
12858
13200
  const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12859
13201
  if (header?.startsWith("audio/")) return header;
12860
13202
  return format === "wav" ? "audio/wav" : "audio/mpeg";
12861
13203
  }
12862
- async function generateSpeech(req, ctx) {
12863
- checkRow(ctx, "speech");
13204
+ async function generateSpeech2(req, ctx) {
13205
+ checkRow2(ctx, "speech");
12864
13206
  const format = req.outputFormat ?? "mp3";
12865
13207
  const body = { text: req.text, format };
12866
13208
  const voice = req.customVoice ?? req.voice;
12867
13209
  if (voice !== void 0) {
12868
- body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
13210
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
12869
13211
  }
12870
13212
  if (req.language !== void 0) body.language = req.language;
12871
13213
  const { bytes, mime } = await withRetry(
@@ -12881,19 +13223,19 @@ async function generateSpeech(req, ctx) {
12881
13223
  } catch (cause) {
12882
13224
  throw classifyThrown("fish", cause, ctx.model.id);
12883
13225
  }
12884
- return { bytes: audio, mime: audioMime(res, format) };
13226
+ return { bytes: audio, mime: audioMime2(res, format) };
12885
13227
  },
12886
13228
  mediaRetryOptions(ctx.call, ctx.signal)
12887
13229
  );
12888
13230
  if (bytes.byteLength === 0)
12889
13231
  throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12890
- return { audio: { bytes, mime }, usage: usage2(ctx) };
13232
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
12891
13233
  }
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)
13234
+ var createdModelSchema = import_zod22.z.object({
13235
+ _id: import_zod22.z.string().min(1),
13236
+ state: import_zod22.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12895
13237
  });
12896
- function fileName(index, mime) {
13238
+ function fileName2(index, mime) {
12897
13239
  const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12898
13240
  return `sample-${index + 1}.${ext}`;
12899
13241
  }
@@ -12905,7 +13247,7 @@ function allOrNone(ctx, field, values) {
12905
13247
  }
12906
13248
  return set;
12907
13249
  }
12908
- async function cloneForm(req, ctx) {
13250
+ async function cloneForm2(req, ctx) {
12909
13251
  if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12910
13252
  const transcripts = allOrNone(
12911
13253
  ctx,
@@ -12931,13 +13273,13 @@ async function cloneForm(req, ctx) {
12931
13273
  model: ctx.model.id
12932
13274
  });
12933
13275
  const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12934
- form.append("voices", audio, fileName(index, mime));
13276
+ form.append("voices", audio, fileName2(index, mime));
12935
13277
  }
12936
13278
  for (const text2 of transcripts) form.append("texts", text2.trim());
12937
13279
  for (const signature of signatures) form.append("voice_design_signatures", signature);
12938
13280
  return form;
12939
13281
  }
12940
- async function onlyRateLimitRetries(fn) {
13282
+ async function onlyRateLimitRetries2(fn) {
12941
13283
  try {
12942
13284
  return await fn();
12943
13285
  } catch (cause) {
@@ -12955,11 +13297,11 @@ async function onlyRateLimitRetries(fn) {
12955
13297
  });
12956
13298
  }
12957
13299
  }
12958
- async function createVoice(req, ctx) {
12959
- checkRow(ctx, "voice-clone");
12960
- const form = await cloneForm(req, ctx);
13300
+ async function createVoice2(req, ctx) {
13301
+ checkRow2(ctx, "voice-clone");
13302
+ const form = await cloneForm2(req, ctx);
12961
13303
  const res = await withRetry(
12962
- () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13304
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12963
13305
  mediaRetryOptions(ctx.call, ctx.signal)
12964
13306
  );
12965
13307
  const raw = await readBody(res);
@@ -12975,23 +13317,23 @@ async function createVoice(req, ctx) {
12975
13317
  retryable: false
12976
13318
  });
12977
13319
  }
12978
- const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
13320
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
12979
13321
  if (parsed.data.state !== void 0) result.state = parsed.data.state;
12980
13322
  return result;
12981
13323
  }
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()
13324
+ var designSchema = import_zod22.z.object({
13325
+ candidates: import_zod22.z.array(
13326
+ import_zod22.z.looseObject({
13327
+ id: import_zod22.z.string().min(1),
13328
+ index: import_zod22.z.number().int(),
13329
+ audio_base64: import_zod22.z.string().min(1),
13330
+ duration_ms: import_zod22.z.number().nonnegative(),
13331
+ signature: import_zod22.z.string().min(1).optional()
12990
13332
  })
12991
13333
  ).min(1)
12992
13334
  });
12993
13335
  async function designVoice(req, ctx) {
12994
- checkRow(ctx, "voice-design");
13336
+ checkRow2(ctx, "voice-design");
12995
13337
  const body = { instruction: req.prompt.trim() };
12996
13338
  if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12997
13339
  if (req.language !== void 0) body.language = req.language;
@@ -13019,11 +13361,11 @@ async function designVoice(req, ctx) {
13019
13361
  // rejects a clone whose signature does not verify, so a wrong one fails loudly.
13020
13362
  signature: c.signature ?? c.id
13021
13363
  }));
13022
- return { candidates, usage: usage2(ctx) };
13364
+ return { candidates, usage: usage3(ctx) };
13023
13365
  }
13024
- async function deleteVoice(req, ctx) {
13025
- checkRow(ctx, "voice-clone");
13026
- const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13366
+ async function deleteVoice2(req, ctx) {
13367
+ checkRow2(ctx, "voice-clone");
13368
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
13027
13369
  let attempts = 0;
13028
13370
  await withRetry(
13029
13371
  async () => {
@@ -13049,18 +13391,18 @@ async function deleteVoice(req, ctx) {
13049
13391
  }
13050
13392
  var fishAdapter = {
13051
13393
  id: "fish",
13052
- generateSpeech,
13053
- createVoice,
13394
+ generateSpeech: generateSpeech2,
13395
+ createVoice: createVoice2,
13054
13396
  designVoice,
13055
- deleteVoice
13397
+ deleteVoice: deleteVoice2
13056
13398
  };
13057
13399
 
13058
13400
  // src/adapters/google-genai.ts
13059
- var import_zod23 = require("zod");
13401
+ var import_zod24 = require("zod");
13060
13402
  var import_genai = require("@google/genai");
13061
13403
 
13062
13404
  // src/adapters/google-files.ts
13063
- var import_zod22 = require("zod");
13405
+ var import_zod23 = require("zod");
13064
13406
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
13065
13407
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
13066
13408
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -13070,17 +13412,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
13070
13412
  "binary/octet-stream",
13071
13413
  "application/binary"
13072
13414
  ]);
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()
13415
+ var uploadedFileSchema = import_zod23.z.object({
13416
+ file: import_zod23.z.object({
13417
+ uri: import_zod23.z.string().optional(),
13418
+ name: import_zod23.z.string().optional(),
13419
+ state: import_zod23.z.string().optional(),
13420
+ mimeType: import_zod23.z.string().optional()
13079
13421
  }).optional()
13080
13422
  });
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()
13423
+ var fileStateSchema = import_zod23.z.object({
13424
+ state: import_zod23.z.string().optional(),
13425
+ error: import_zod23.z.object({ message: import_zod23.z.string().optional() }).optional()
13084
13426
  });
13085
13427
  function resolveMime(declared, fallback) {
13086
13428
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -13187,7 +13529,7 @@ async function startAndUpload(bytes, mimeType, opts) {
13187
13529
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
13188
13530
  return ref;
13189
13531
  }
13190
- async function waitForActive(fileName2, opts) {
13532
+ async function waitForActive(fileName3, opts) {
13191
13533
  const pollOptions2 = {
13192
13534
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
13193
13535
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -13200,14 +13542,14 @@ async function waitForActive(fileName2, opts) {
13200
13542
  retryInit.signal = opts.signal;
13201
13543
  }
13202
13544
  await pollUntil(async () => {
13203
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
13545
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
13204
13546
  if (res.ok) {
13205
13547
  const json = fileStateSchema.parse(await res.json());
13206
13548
  if (json.state === "ACTIVE") return true;
13207
13549
  if (json.state === "FAILED") {
13208
13550
  throw classifyHttpError(
13209
13551
  void 0,
13210
- `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
13552
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
13211
13553
  "google-genai",
13212
13554
  opts.model
13213
13555
  );
@@ -13219,9 +13561,9 @@ async function waitForActive(fileName2, opts) {
13219
13561
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
13220
13562
  }, pollOptions2);
13221
13563
  }
13222
- async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
13564
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
13223
13565
  try {
13224
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
13566
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
13225
13567
  method: "DELETE",
13226
13568
  headers: { "x-goog-api-key": apiKey }
13227
13569
  });
@@ -13301,7 +13643,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
13301
13643
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
13302
13644
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
13303
13645
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
13304
- var errorTextSchema = import_zod23.z.string();
13646
+ var errorTextSchema = import_zod24.z.string();
13305
13647
  function isGoogleGenaiVideoKnown(providerModelId) {
13306
13648
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
13307
13649
  }
@@ -13496,7 +13838,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13496
13838
  }
13497
13839
  };
13498
13840
  const jobId = operation.name ?? crypto.randomUUID();
13499
- const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13841
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13500
13842
  return {
13501
13843
  jobId,
13502
13844
  async poll() {
@@ -13534,7 +13876,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13534
13876
  modelId
13535
13877
  );
13536
13878
  }
13537
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
13879
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
13538
13880
  }
13539
13881
  };
13540
13882
  }
@@ -13645,7 +13987,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13645
13987
  return file.fileUri;
13646
13988
  };
13647
13989
  const cleanupUploads = async () => {
13648
- for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
13990
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
13649
13991
  };
13650
13992
  const callCreate = (input) => client2.interactions.create(
13651
13993
  previousId !== void 0 ? {
@@ -13739,7 +14081,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13739
14081
  if (!(extend && !chained)) await cleanupUploads();
13740
14082
  }
13741
14083
  const jobId = interaction.id ?? crypto.randomUUID();
13742
- const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
14084
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13743
14085
  const getInteraction = async () => {
13744
14086
  try {
13745
14087
  const getParams = { stream: false };
@@ -13787,7 +14129,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13787
14129
  bytes: Buffer.from(video.data, "base64"),
13788
14130
  mime: video.mime_type ?? "video/mp4"
13789
14131
  },
13790
- usage: usage4,
14132
+ usage: usage5,
13791
14133
  raw: done,
13792
14134
  providerRef
13793
14135
  };
@@ -13795,7 +14137,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13795
14137
  if (video.uri)
13796
14138
  return {
13797
14139
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13798
- usage: usage4,
14140
+ usage: usage5,
13799
14141
  raw: done,
13800
14142
  providerRef
13801
14143
  };
@@ -13965,15 +14307,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13965
14307
  // src/adapters/google-image.ts
13966
14308
  var import_google2 = require("@ai-sdk/google");
13967
14309
  var import_ai2 = require("ai");
13968
- var import_zod24 = require("zod");
14310
+ var import_zod25 = require("zod");
13969
14311
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13970
14312
  var defaultGoogleImageDeps = {
13971
14313
  createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
13972
14314
  runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
13973
14315
  };
13974
- var causeChainNodeSchema = import_zod24.z.object({
13975
- message: import_zod24.z.string().optional(),
13976
- cause: import_zod24.z.unknown().optional()
14316
+ var causeChainNodeSchema = import_zod25.z.object({
14317
+ message: import_zod25.z.string().optional(),
14318
+ cause: import_zod25.z.unknown().optional()
13977
14319
  });
13978
14320
  function extractBlockReason(cause) {
13979
14321
  let current = cause;
@@ -14073,7 +14415,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
14073
14415
  retryable: false
14074
14416
  });
14075
14417
  }
14076
- const usage4 = {
14418
+ const usage5 = {
14077
14419
  model: ctx.model.id,
14078
14420
  provider: "google-image",
14079
14421
  modality: "IMAGE",
@@ -14081,19 +14423,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
14081
14423
  quantity: images.length,
14082
14424
  imageQuality: "auto"
14083
14425
  };
14084
- if (req.size !== void 0) usage4.imageSize = req.size;
14426
+ if (req.size !== void 0) usage5.imageSize = req.size;
14085
14427
  if (result.usage?.inputTokens !== void 0)
14086
- usage4.inputTokens = result.usage.inputTokens;
14428
+ usage5.inputTokens = result.usage.inputTokens;
14087
14429
  if (result.usage?.outputTokens !== void 0)
14088
- usage4.outputTokens = result.usage.outputTokens;
14089
- return { images, usage: usage4, raw: result };
14430
+ usage5.outputTokens = result.usage.outputTokens;
14431
+ return { images, usage: usage5, raw: result };
14090
14432
  }
14091
14433
  };
14092
14434
  }
14093
14435
  var googleImageAdapter = createGoogleImageAdapter();
14094
14436
 
14095
14437
  // src/adapters/higgsfield.ts
14096
- var import_zod25 = require("zod");
14438
+ var import_zod26 = require("zod");
14097
14439
 
14098
14440
  // src/adapters/higgsfield-motions.ts
14099
14441
  var MOTION_MAP = {
@@ -14312,14 +14654,14 @@ function klingEndpointFields(providerModelId) {
14312
14654
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
14313
14655
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
14314
14656
  }
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(),
14657
+ var klingCreateSchema = import_zod26.z.object({ status_url: import_zod26.z.string() });
14658
+ var klingStatusSchema = import_zod26.z.object({
14659
+ status: import_zod26.z.string().optional(),
14660
+ video: import_zod26.z.object({ url: import_zod26.z.string().optional() }).optional(),
14319
14661
  error: JsonValueSchema.optional()
14320
14662
  });
14321
- var errorMessageSchema = import_zod25.z.object({ message: import_zod25.z.string().optional() });
14322
- var textValueSchema = import_zod25.z.string();
14663
+ var errorMessageSchema = import_zod26.z.object({ message: import_zod26.z.string().optional() });
14664
+ var textValueSchema = import_zod26.z.string();
14323
14665
  function klingErrorDetail(error) {
14324
14666
  if (error === void 0) return "unknown_error";
14325
14667
  const asText = textValueSchema.safeParse(error);
@@ -14475,8 +14817,8 @@ async function generateKlingVideo(req, ctx) {
14475
14817
  }
14476
14818
  };
14477
14819
  }
14478
- var dopMotionOptionsSchema = import_zod25.z.object({
14479
- modelkit: import_zod25.z.object({ motion: import_zod25.z.string().optional() }).optional()
14820
+ var dopMotionOptionsSchema = import_zod26.z.object({
14821
+ modelkit: import_zod26.z.object({ motion: import_zod26.z.string().optional() }).optional()
14480
14822
  });
14481
14823
  function dopMotionId(ctx) {
14482
14824
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -14492,7 +14834,7 @@ function dopMotionId(ctx) {
14492
14834
  });
14493
14835
  return id;
14494
14836
  }
14495
- var jsonRecordSchema = import_zod25.z.record(import_zod25.z.string(), JsonValueSchema);
14837
+ var jsonRecordSchema = import_zod26.z.record(import_zod26.z.string(), JsonValueSchema);
14496
14838
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
14497
14839
  var DOP_NESTED_KEYS = ["video", "result", "results"];
14498
14840
  function dopUrl(body) {
@@ -14520,8 +14862,8 @@ function dopUrl(body) {
14520
14862
  }
14521
14863
  return void 0;
14522
14864
  }
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() });
14865
+ var dopCreateSchema = import_zod26.z.object({ id: import_zod26.z.string() });
14866
+ var dopStatusSchema = import_zod26.z.object({ status: import_zod26.z.string().optional() });
14525
14867
  async function generateDopVideo(req, ctx) {
14526
14868
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
14527
14869
  if (!firstFrame) {
@@ -14648,7 +14990,7 @@ var higgsfieldAdapter = {
14648
14990
  };
14649
14991
 
14650
14992
  // src/adapters/luma.ts
14651
- var import_zod26 = require("zod");
14993
+ var import_zod27 = require("zod");
14652
14994
 
14653
14995
  // src/adapters/mp4-duration.ts
14654
14996
  function mp4DurationSeconds(bytes) {
@@ -14704,7 +15046,7 @@ function findBox(bytes, from, to, type) {
14704
15046
  }
14705
15047
 
14706
15048
  // src/adapters/luma.ts
14707
- var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
15049
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
14708
15050
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14709
15051
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14710
15052
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14733,7 +15075,7 @@ function lumaModel(ctx) {
14733
15075
  return ctx.model.providerModelId.toLowerCase();
14734
15076
  }
14735
15077
  function lumaBase(ctx) {
14736
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
15078
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14737
15079
  }
14738
15080
  function lumaKey(ctx) {
14739
15081
  const key = ctx.keys.luma;
@@ -14865,17 +15207,17 @@ function lumaReframeResolution(req, ctx) {
14865
15207
  });
14866
15208
  return "720p";
14867
15209
  }
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()
15210
+ var lumaGenerationSchema = import_zod27.z.looseObject({
15211
+ id: import_zod27.z.string(),
15212
+ state: import_zod27.z.string().optional(),
15213
+ output: import_zod27.z.array(
15214
+ import_zod27.z.looseObject({
15215
+ type: import_zod27.z.string().optional(),
15216
+ url: import_zod27.z.string().optional()
14875
15217
  })
14876
15218
  ).optional(),
14877
- failure_reason: import_zod26.z.string().optional().nullable(),
14878
- failure_code: import_zod26.z.string().optional().nullable()
15219
+ failure_reason: import_zod27.z.string().optional().nullable(),
15220
+ failure_code: import_zod27.z.string().optional().nullable()
14879
15221
  });
14880
15222
  function lumaFailure(ctx, code, reason) {
14881
15223
  const detail = reason ?? code ?? "unknown_error";
@@ -15307,7 +15649,7 @@ var lumaAdapter = {
15307
15649
 
15308
15650
  // src/adapters/openai-image.ts
15309
15651
  var import_openai2 = __toESM(require("openai"), 1);
15310
- var import_zod27 = require("zod");
15652
+ var import_zod28 = require("zod");
15311
15653
  var MAX_EDIT_REFERENCES = 16;
15312
15654
  function aspectRatioToSize(ratio, tier) {
15313
15655
  const TIER_LONG_EDGE = {
@@ -15390,9 +15732,9 @@ function toProviderError2(cause, ctx) {
15390
15732
  ctx.model.id
15391
15733
  );
15392
15734
  }
15393
- var openaiUsageSchema = import_zod27.z.object({
15394
- input_tokens: import_zod27.z.number().optional(),
15395
- output_tokens: import_zod27.z.number().optional()
15735
+ var openaiUsageSchema = import_zod28.z.object({
15736
+ input_tokens: import_zod28.z.number().optional(),
15737
+ output_tokens: import_zod28.z.number().optional()
15396
15738
  });
15397
15739
  var openaiImageAdapter = {
15398
15740
  id: "openai-image",
@@ -15517,7 +15859,7 @@ var openaiImageAdapter = {
15517
15859
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
15518
15860
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
15519
15861
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
15520
- const usage4 = {
15862
+ const usage5 = {
15521
15863
  model: ctx.model.id,
15522
15864
  provider: "openai-image",
15523
15865
  modality: "IMAGE",
@@ -15525,10 +15867,10 @@ var openaiImageAdapter = {
15525
15867
  quantity: images.length,
15526
15868
  imageQuality: quality
15527
15869
  };
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 };
15870
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15871
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15872
+ if (req.size !== void 0) usage5.imageSize = req.size;
15873
+ return { images, usage: usage5, raw: response };
15532
15874
  }
15533
15875
  };
15534
15876
 
@@ -15784,16 +16126,16 @@ async function generateProdiaImage(req, ctx) {
15784
16126
  new Uint8Array(await res.arrayBuffer()),
15785
16127
  res.headers.get("content-type")
15786
16128
  );
15787
- const usage4 = {
16129
+ const usage5 = {
15788
16130
  model: ctx.model.id,
15789
16131
  provider: "prodia",
15790
16132
  modality: "IMAGE",
15791
16133
  unit: "images",
15792
16134
  quantity: 1
15793
16135
  };
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 };
16136
+ if (req.size !== void 0) usage5.imageSize = req.size;
16137
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
16138
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15797
16139
  }
15798
16140
  var prodiaAdapter = {
15799
16141
  id: "prodia",
@@ -15804,13 +16146,13 @@ var prodiaAdapter = {
15804
16146
  var import_replicate = __toESM(require("replicate"), 1);
15805
16147
 
15806
16148
  // 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(),
16149
+ var import_zod29 = require("zod");
16150
+ var predictionSchema = import_zod29.z.object({
16151
+ id: import_zod29.z.string(),
16152
+ status: import_zod29.z.string(),
15811
16153
  output: JsonValueSchema.optional(),
15812
16154
  error: JsonValueSchema.optional(),
15813
- metrics: import_zod28.z.object({ predict_time: import_zod28.z.number().optional() }).optional()
16155
+ metrics: import_zod29.z.object({ predict_time: import_zod29.z.number().optional() }).optional()
15814
16156
  });
15815
16157
  function createReplicateHttpClient(opts) {
15816
16158
  async function request(path, body, signal) {
@@ -15861,7 +16203,7 @@ function createReplicateHttpClient(opts) {
15861
16203
  }
15862
16204
 
15863
16205
  // src/adapters/replicate.ts
15864
- var import_zod29 = require("zod");
16206
+ var import_zod30 = require("zod");
15865
16207
  var POLL_INTERVAL_MS = 1e3;
15866
16208
  var POLL_TIMEOUT_MS = 15 * 6e4;
15867
16209
  var defaultReplicateDeps = {
@@ -15901,8 +16243,8 @@ function route(providerModelId) {
15901
16243
  if (!providerModelId.includes("/")) return { version: providerModelId };
15902
16244
  return { model: providerModelId };
15903
16245
  }
15904
- var replicateResponseStatusSchema = import_zod29.z.object({
15905
- response: import_zod29.z.object({ status: import_zod29.z.number() }).partial()
16246
+ var replicateResponseStatusSchema = import_zod30.z.object({
16247
+ response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
15906
16248
  });
15907
16249
  function replicateError(cause, ctx) {
15908
16250
  if (isModelKitError(cause)) return cause;
@@ -15925,7 +16267,7 @@ function isUrlFn(value) {
15925
16267
  function extractOutputUrl(output) {
15926
16268
  const root = Array.isArray(output) ? output[0] : output;
15927
16269
  if (root === void 0) throw noOutput();
15928
- const asString = import_zod29.z.string().safeParse(root);
16270
+ const asString = import_zod30.z.string().safeParse(root);
15929
16271
  if (asString.success && asString.data) return asString.data;
15930
16272
  if (root instanceof URL) return root.href;
15931
16273
  if (isObjectOutput(root)) {
@@ -15934,15 +16276,15 @@ function extractOutputUrl(output) {
15934
16276
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15935
16277
  const called = urlValue();
15936
16278
  if (called instanceof URL) return called.href;
15937
- const calledString = import_zod29.z.string().safeParse(called);
16279
+ const calledString = import_zod30.z.string().safeParse(called);
15938
16280
  if (calledString.success && calledString.data) return calledString.data;
15939
16281
  } else {
15940
- const direct = import_zod29.z.string().safeParse(urlValue);
16282
+ const direct = import_zod30.z.string().safeParse(urlValue);
15941
16283
  if (direct.success && direct.data) return direct.data;
15942
16284
  }
15943
16285
  }
15944
16286
  if ("default" in root) {
15945
- const fallback = import_zod29.z.string().safeParse(root.default);
16287
+ const fallback = import_zod30.z.string().safeParse(root.default);
15946
16288
  if (fallback.success && fallback.data) return fallback.data;
15947
16289
  }
15948
16290
  }
@@ -16003,7 +16345,7 @@ async function runPrediction(ctx, input, deps) {
16003
16345
  }
16004
16346
  return void 0;
16005
16347
  }, pollOpts);
16006
- const predictTime = import_zod29.z.number().safeParse(done.metrics?.predict_time);
16348
+ const predictTime = import_zod30.z.number().safeParse(done.metrics?.predict_time);
16007
16349
  if (done.output === void 0) throw noOutput();
16008
16350
  return {
16009
16351
  url: extractOutputUrl(done.output),
@@ -16249,9 +16591,9 @@ async function generateReplicateImage(req, ctx, deps) {
16249
16591
  }
16250
16592
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16251
16593
  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 };
16594
+ const usage5 = imageUsage3(ctx, req);
16595
+ usage5.quantity = predictTime;
16596
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
16255
16597
  }
16256
16598
  function klingInput(req) {
16257
16599
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -16356,7 +16698,7 @@ async function generateReplicateVideo(req, ctx, deps) {
16356
16698
  throw replicateError(cause, ctx);
16357
16699
  }
16358
16700
  if (current.status === "succeeded") {
16359
- const predictTime = import_zod29.z.number().safeParse(current.metrics?.predict_time);
16701
+ const predictTime = import_zod30.z.number().safeParse(current.metrics?.predict_time);
16360
16702
  if (current.output === void 0) throw noOutput();
16361
16703
  return {
16362
16704
  url: extractOutputUrl(current.output),
@@ -16375,9 +16717,9 @@ async function generateReplicateVideo(req, ctx, deps) {
16375
16717
  return void 0;
16376
16718
  };
16377
16719
  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 };
16720
+ const usage5 = videoUsage5(ctx, req);
16721
+ usage5.quantity = done.predictTime;
16722
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
16381
16723
  };
16382
16724
  return {
16383
16725
  jobId,
@@ -16484,21 +16826,21 @@ async function generateReplicateAudio(req, ctx, deps) {
16484
16826
  input = specResult.input;
16485
16827
  }
16486
16828
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16487
- const usage4 = audioUsage(ctx, req);
16829
+ const usage5 = audioUsage(ctx, req);
16488
16830
  if (ctx.model.usage.unit === "seconds") {
16489
16831
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
16490
- usage4.quantity = seconds3;
16491
- usage4.durationSeconds = seconds3;
16832
+ usage5.quantity = seconds3;
16833
+ usage5.durationSeconds = seconds3;
16492
16834
  } else {
16493
- usage4.quantity = predictTime;
16835
+ usage5.quantity = predictTime;
16494
16836
  }
16495
- return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
16837
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
16496
16838
  }
16497
16839
 
16498
16840
  // src/adapters/xai-video.ts
16499
16841
  var import_ai3 = require("ai");
16500
16842
  var import_xai2 = require("@ai-sdk/xai");
16501
- var import_zod30 = require("zod");
16843
+ var import_zod31 = require("zod");
16502
16844
  var POLL_INTERVAL_MS2 = 1e4;
16503
16845
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
16504
16846
  var defaultXaiDeps = {
@@ -16511,8 +16853,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
16511
16853
  };
16512
16854
  }
16513
16855
  var xaiVideoAdapter = createXaiVideoAdapter();
16514
- var xaiResponseStatusSchema = import_zod30.z.object({
16515
- response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
16856
+ var xaiResponseStatusSchema = import_zod31.z.object({
16857
+ response: import_zod31.z.object({ status: import_zod31.z.number() }).partial()
16516
16858
  });
16517
16859
  function xaiError(cause, ctx) {
16518
16860
  const info = describeThrown(cause);
@@ -16520,12 +16862,12 @@ function xaiError(cause, ctx) {
16520
16862
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
16521
16863
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
16522
16864
  }
16523
- var xaiMetaSchema = import_zod30.z.object({
16865
+ var xaiMetaSchema = import_zod31.z.object({
16524
16866
  videoUrl: JsonValueSchema.optional(),
16525
16867
  costInUsdTicks: JsonValueSchema.optional(),
16526
16868
  duration: JsonValueSchema.optional()
16527
16869
  });
16528
- var xaiProviderMetadataSchema = import_zod30.z.object({ xai: xaiMetaSchema });
16870
+ var xaiProviderMetadataSchema = import_zod31.z.object({ xai: xaiMetaSchema });
16529
16871
  function metaOf(result) {
16530
16872
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
16531
16873
  if (!parsed.success) return {};
@@ -16637,12 +16979,12 @@ async function mapResult(ctx, req, result) {
16637
16979
  if (first) {
16638
16980
  return {
16639
16981
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16640
- usage: usage3(ctx, req, metaOf(result)),
16982
+ usage: usage4(ctx, req, metaOf(result)),
16641
16983
  raw: result.providerMetadata
16642
16984
  };
16643
16985
  }
16644
16986
  const meta = metaOf(result);
16645
- const videoUrl = import_zod30.z.string().safeParse(meta.videoUrl);
16987
+ const videoUrl = import_zod31.z.string().safeParse(meta.videoUrl);
16646
16988
  if (videoUrl.success && videoUrl.data) {
16647
16989
  const res = await ctx.fetch(videoUrl.data);
16648
16990
  if (!res.ok) {
@@ -16652,7 +16994,7 @@ async function mapResult(ctx, req, result) {
16652
16994
  const mime = res.headers.get("content-type") ?? "video/mp4";
16653
16995
  return {
16654
16996
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16655
- usage: usage3(ctx, req, meta),
16997
+ usage: usage4(ctx, req, meta),
16656
16998
  raw: result.providerMetadata
16657
16999
  };
16658
17000
  }
@@ -16664,8 +17006,8 @@ async function mapResult(ctx, req, result) {
16664
17006
  retryable: false
16665
17007
  });
16666
17008
  }
16667
- function usage3(ctx, req, meta) {
16668
- const costTicks = import_zod30.z.number().safeParse(meta.costInUsdTicks);
17009
+ function usage4(ctx, req, meta) {
17010
+ const costTicks = import_zod31.z.number().safeParse(meta.costInUsdTicks);
16669
17011
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16670
17012
  const event = {
16671
17013
  model: ctx.model.id,
@@ -16705,7 +17047,8 @@ var DEFAULT_ADAPTERS = {
16705
17047
  higgsfield: higgsfieldAdapter,
16706
17048
  "xai-video": xaiVideoAdapter,
16707
17049
  luma: lumaAdapter,
16708
- fish: fishAdapter
17050
+ fish: fishAdapter,
17051
+ elevenlabs: elevenLabsAdapter
16709
17052
  };
16710
17053
 
16711
17054
  // src/catalog/data-only.ts
@@ -16744,15 +17087,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16744
17087
  "transcription",
16745
17088
  "mask"
16746
17089
  ]);
16747
- function fishSpeech(row2) {
16748
- return row2.adapter === "fish" && row2.type === "speech";
17090
+ function directSpeech(row2) {
17091
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
16749
17092
  }
16750
17093
  function dataOnlyCapable(row2) {
16751
17094
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16752
17095
  if (!adapterServesType(adapter, row2.type)) {
16753
17096
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16754
17097
  }
16755
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
17098
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16756
17099
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16757
17100
  }
16758
17101
  switch (row2.adapter) {
@@ -16834,6 +17177,10 @@ function dataOnlyCapable(row2) {
16834
17177
  const reason = fishRowRefusal(row2);
16835
17178
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16836
17179
  }
17180
+ case "elevenlabs": {
17181
+ const reason = elevenLabsRowRefusal(row2);
17182
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17183
+ }
16837
17184
  default: {
16838
17185
  return assertNever(row2.adapter);
16839
17186
  }
@@ -16853,22 +17200,22 @@ var liveState = store[KEY] ??= {
16853
17200
  var liveCatalog = liveState.catalog;
16854
17201
 
16855
17202
  // src/catalog/load.ts
16856
- var import_zod31 = require("zod");
17203
+ var import_zod32 = require("zod");
16857
17204
  function rowCount() {
16858
17205
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16859
17206
  }
16860
17207
  function authHeaders(auth) {
16861
17208
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16862
17209
  }
16863
- var EnvelopeSchema = import_zod31.z.object({
16864
- rows: import_zod31.z.array(JsonValueSchema),
16865
- revision: import_zod31.z.string().optional()
17210
+ var EnvelopeSchema = import_zod32.z.object({
17211
+ rows: import_zod32.z.array(JsonValueSchema),
17212
+ revision: import_zod32.z.string().optional()
16866
17213
  });
16867
17214
  function dropReason(path, message) {
16868
17215
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16869
17216
  }
16870
17217
  function rowId(raw) {
16871
- const parsed = import_zod31.z.object({ id: import_zod31.z.string().min(1) }).loose().safeParse(raw);
17218
+ const parsed = import_zod32.z.object({ id: import_zod32.z.string().min(1) }).loose().safeParse(raw);
16872
17219
  if (!parsed.success) return "?";
16873
17220
  return parsed.data.id;
16874
17221
  }
@@ -18029,7 +18376,8 @@ var ADAPTER_KEYS = {
18029
18376
  higgsfield: ["higgsfield"],
18030
18377
  "xai-video": ["xai"],
18031
18378
  luma: ["luma"],
18032
- fish: ["fish"]
18379
+ fish: ["fish"],
18380
+ elevenlabs: ["elevenlabs"]
18033
18381
  };
18034
18382
  function hasAll(keys, names) {
18035
18383
  if (!keys) return false;
@@ -18089,6 +18437,7 @@ function keysFromEnv(env, prefix = "") {
18089
18437
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
18090
18438
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
18091
18439
  set("fish", pick2("FISH_AUDIO_API_KEY"));
18440
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
18092
18441
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
18093
18442
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
18094
18443
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -18111,7 +18460,7 @@ function keysFromEnv(env, prefix = "") {
18111
18460
 
18112
18461
  // src/text.ts
18113
18462
  var import_ai4 = require("ai");
18114
- var import_zod32 = require("zod");
18463
+ var import_zod33 = require("zod");
18115
18464
  function mergeTextProviderOptions(catalog, caller) {
18116
18465
  const merged = {};
18117
18466
  const catalogOptions = catalog.providerOptions ?? {};
@@ -18150,17 +18499,17 @@ function passthroughTextModel(model) {
18150
18499
  pricingKind: "token"
18151
18500
  };
18152
18501
  }
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() }) })
18502
+ var perplexityCostSchema = import_zod33.z.object({
18503
+ perplexity: import_zod33.z.object({ cost: import_zod33.z.object({ totalCost: import_zod33.z.number().finite().nonnegative() }) })
18155
18504
  });
18156
18505
  function reportedCostUsd(metadata) {
18157
18506
  const parsed = perplexityCostSchema.safeParse(metadata);
18158
18507
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
18159
18508
  }
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;
18509
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18510
+ const inputTokens = usage5.inputTokens ?? 0;
18511
+ const outputTokens = usage5.outputTokens ?? 0;
18512
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
18164
18513
  const event = {
18165
18514
  model: model.id,
18166
18515
  provider,
@@ -18195,7 +18544,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18195
18544
  return { ...prepared, providerOptions };
18196
18545
  };
18197
18546
  }
18198
- function usage4(results) {
18547
+ function usage5(results) {
18199
18548
  const grouped = /* @__PURE__ */ new Map();
18200
18549
  for (const [index, step] of results.entries()) {
18201
18550
  const target = steps.get(index) ?? initial;
@@ -18219,12 +18568,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18219
18568
  }
18220
18569
  return [...grouped.values()];
18221
18570
  }
18222
- return { wrap, usage: usage4 };
18571
+ return { wrap, usage: usage5 };
18223
18572
  }
18224
18573
 
18225
18574
  // src/client.ts
18226
18575
  var import_ai5 = require("ai");
18227
- var import_zod33 = require("zod");
18576
+ var import_zod34 = require("zod");
18228
18577
 
18229
18578
  // src/generated-image.ts
18230
18579
  function toGeneratedImage(image) {
@@ -18346,9 +18695,9 @@ function providerJobMethods(kind, deps) {
18346
18695
  if (!methods.result) throw missing3(adapter, ctx.model);
18347
18696
  const result = await methods.result(sub, ctx, webhook);
18348
18697
  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 };
18698
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18699
+ await deps.emit(usage5);
18700
+ return { ...result, usage: usage5 };
18352
18701
  },
18353
18702
  async cancel(sub, call = {}) {
18354
18703
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -18588,10 +18937,10 @@ function audioNodeMethods(deps) {
18588
18937
  const startedAt = Date.now();
18589
18938
  const outcome = await adapter.dub(resolved, ctx);
18590
18939
  if (outcome.kind === "audio") {
18591
- const { audio, usage: usage4, raw } = outcome.result;
18940
+ const { audio, usage: usage5, raw } = outcome.result;
18592
18941
  return {
18593
18942
  audio,
18594
- usage: await deps.settle(model, usage4, startedAt),
18943
+ usage: await deps.settle(model, usage5, startedAt),
18595
18944
  ...raw !== void 0 && { raw }
18596
18945
  };
18597
18946
  }
@@ -18629,10 +18978,10 @@ function textAbortOptions(sdk, context) {
18629
18978
  if (abortSignal) return { abortSignal };
18630
18979
  return {};
18631
18980
  }
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"]);
18981
+ var catalogId = import_zod34.z.string();
18982
+ var exactSize = import_zod34.z.templateLiteral([import_zod34.z.number(), "x", import_zod34.z.number()]);
18983
+ var sdkRatio = import_zod34.z.templateLiteral([import_zod34.z.number(), ":", import_zod34.z.number()]);
18984
+ var sizeTier = import_zod34.z.enum(["512", "1K", "2K", "4K"]);
18636
18985
  function isCatalogId(model) {
18637
18986
  return catalogId.safeParse(model).success;
18638
18987
  }
@@ -18845,7 +19194,7 @@ function createModelKit(config, adapters) {
18845
19194
  const images = result.images.map(
18846
19195
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18847
19196
  );
18848
- const usage4 = timed(
19197
+ const usage5 = timed(
18849
19198
  {
18850
19199
  model: model.modelId,
18851
19200
  provider: model.provider,
@@ -18855,8 +19204,8 @@ function createModelKit(config, adapters) {
18855
19204
  },
18856
19205
  startedAt
18857
19206
  );
18858
- await emit(usage4);
18859
- return { image: images[0], images, usage: usage4, raw: result, warnings };
19207
+ await emit(usage5);
19208
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
18860
19209
  }
18861
19210
  function passthroughVideo(req, call) {
18862
19211
  const {
@@ -18932,7 +19281,7 @@ function createModelKit(config, adapters) {
18932
19281
  let settled;
18933
19282
  let failed = false;
18934
19283
  const done = pending.then(async (result) => {
18935
- const usage4 = timed(
19284
+ const usage5 = timed(
18936
19285
  {
18937
19286
  model: model.modelId,
18938
19287
  provider: model.provider,
@@ -18945,10 +19294,10 @@ function createModelKit(config, adapters) {
18945
19294
  );
18946
19295
  settled = {
18947
19296
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18948
- usage: usage4,
19297
+ usage: usage5,
18949
19298
  raw: result
18950
19299
  };
18951
- await emit(usage4);
19300
+ await emit(usage5);
18952
19301
  return settled;
18953
19302
  });
18954
19303
  done.catch(() => {
@@ -18975,12 +19324,12 @@ function createModelKit(config, adapters) {
18975
19324
  if (settled) return settled;
18976
19325
  const pending = result(opts).then(
18977
19326
  async (out) => {
18978
- const usage4 = timed(
19327
+ const usage5 = timed(
18979
19328
  { ...out.usage, model: model.id, unit: model.usage.unit },
18980
19329
  startedAt
18981
19330
  );
18982
- await emit(usage4);
18983
- return { ...out, usage: usage4 };
19331
+ await emit(usage5);
19332
+ return { ...out, usage: usage5 };
18984
19333
  },
18985
19334
  (cause) => {
18986
19335
  settled = void 0;
@@ -19000,9 +19349,9 @@ function createModelKit(config, adapters) {
19000
19349
  return context(model, signal ? { ...call, signal } : call, warnings);
19001
19350
  },
19002
19351
  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;
19352
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19353
+ await emit(usage5);
19354
+ return usage5;
19006
19355
  },
19007
19356
  wrapVideoJob
19008
19357
  });
@@ -19038,11 +19387,11 @@ function createModelKit(config, adapters) {
19038
19387
  });
19039
19388
  const startedAt = Date.now();
19040
19389
  const result = await adapter.generateImage(request, ctx);
19041
- const usage4 = timed(
19390
+ const usage5 = timed(
19042
19391
  { ...result.usage, model: model.id, unit: model.usage.unit },
19043
19392
  startedAt
19044
19393
  );
19045
- await emit(usage4);
19394
+ await emit(usage5);
19046
19395
  const images = result.images.map(toGeneratedImage);
19047
19396
  const first = images[0];
19048
19397
  if (!first)
@@ -19051,7 +19400,7 @@ function createModelKit(config, adapters) {
19051
19400
  message: `${model.id} returned no image`,
19052
19401
  model: model.id
19053
19402
  });
19054
- return { ...result, usage: usage4, image: first, images, warnings };
19403
+ return { ...result, usage: usage5, image: first, images, warnings };
19055
19404
  },
19056
19405
  async generateVideo(req, call = {}) {
19057
19406
  mediaRetryOptions(call);
@@ -19150,12 +19499,12 @@ function createModelKit(config, adapters) {
19150
19499
  }
19151
19500
  const startedAt = Date.now();
19152
19501
  const result = await adapter.generateAudio(resolved, ctx);
19153
- const usage4 = timed(
19502
+ const usage5 = timed(
19154
19503
  { ...result.usage, model: model.id, unit: model.usage.unit },
19155
19504
  startedAt
19156
19505
  );
19157
- await emit(usage4);
19158
- return { ...result, usage: usage4 };
19506
+ await emit(usage5);
19507
+ return { ...result, usage: usage5 };
19159
19508
  },
19160
19509
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
19161
19510
  mediaRetryOptions(call);
@@ -19235,8 +19584,8 @@ function createModelKit(config, adapters) {
19235
19584
  options.prepareStep ?? options.experimental_prepareStep
19236
19585
  ),
19237
19586
  onFinish: async (event) => {
19238
- for (const usage4 of steps.usage(event.steps))
19239
- await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
19587
+ for (const usage5 of steps.usage(event.steps))
19588
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
19240
19589
  await callerOnFinish?.(event);
19241
19590
  }
19242
19591
  });
@@ -19355,6 +19704,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
19355
19704
  dataOnlyCapable,
19356
19705
  describe,
19357
19706
  describeThrown,
19707
+ elevenLabsAdapter,
19358
19708
  experimental_generateImage,
19359
19709
  falAdapter,
19360
19710
  falWebhookBodySchema,