@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.js CHANGED
@@ -1230,303 +1230,6 @@ var VEED_SUBTITLES = {
1230
1230
  }
1231
1231
  };
1232
1232
 
1233
- // src/catalog/voices-fish.ts
1234
- var FISH_VOICES = [
1235
- {
1236
- id: "933563129e564b19a115bedd57b7406a",
1237
- name: "Sarah",
1238
- gender: "female",
1239
- languages: ["en"],
1240
- description: "An engaged speaker.",
1241
- previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
1242
- },
1243
- {
1244
- id: "bf322df2096a46f18c579d0baa36f41d",
1245
- name: "Adrian",
1246
- gender: "male",
1247
- languages: ["en"],
1248
- description: "A steady and reliable narrator.",
1249
- previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
1250
- },
1251
- {
1252
- id: "536d3a5e000945adb7038665781a4aca",
1253
- name: "Ethan",
1254
- gender: "male",
1255
- languages: ["en"],
1256
- description: "A curious explainer.",
1257
- previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
1258
- },
1259
- {
1260
- id: "b347db033a6549378b48d00acb0d06cd",
1261
- name: "Selene",
1262
- gender: "female",
1263
- languages: ["en"],
1264
- description: "A meditative female voice.",
1265
- previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
1266
- },
1267
- {
1268
- id: "9a9cf47702da476aa4629e2506d4a857",
1269
- name: "Hannah",
1270
- gender: "female",
1271
- languages: ["en"],
1272
- description: "A conversation specialist.",
1273
- previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
1274
- },
1275
- {
1276
- id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
1277
- name: "Jordan",
1278
- gender: "male",
1279
- languages: ["en"],
1280
- description: "A motivational speaker.",
1281
- previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
1282
- },
1283
- {
1284
- id: "e3cd384158934cc9a01029cd7d278634",
1285
- name: "Laura",
1286
- gender: "female",
1287
- languages: ["en"],
1288
- description: "A confident female narrator.",
1289
- previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
1290
- },
1291
- {
1292
- id: "f3a2b90078d54a65af4b95f63bc7798e",
1293
- name: "Sheila",
1294
- gender: "female",
1295
- accent: "american",
1296
- languages: ["en"],
1297
- description: "A young American English woman's voice.",
1298
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
1299
- },
1300
- {
1301
- id: "0db6e93af420470b9d9b9a886dbaa954",
1302
- name: "Kai",
1303
- gender: "male",
1304
- languages: ["en"],
1305
- description: "A friendly English man's voice for companion apps and everyday conversation.",
1306
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
1307
- },
1308
- {
1309
- id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
1310
- name: "Freya",
1311
- gender: "female",
1312
- accent: "british",
1313
- languages: ["en"],
1314
- 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.",
1315
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
1316
- },
1317
- {
1318
- id: "2f64e528a4f2406691925ab1e0ed5b7f",
1319
- name: "Ananya",
1320
- gender: "female",
1321
- languages: ["hi"],
1322
- 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",
1323
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
1324
- },
1325
- {
1326
- id: "cefd91a07b99468f9148e2580990082d",
1327
- name: "Arjun",
1328
- gender: "male",
1329
- languages: ["hi"],
1330
- 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",
1331
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
1332
- },
1333
- {
1334
- id: "3f065d660212478a9c697fa965b4d098",
1335
- name: "Carmen",
1336
- gender: "female",
1337
- languages: ["es"],
1338
- description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1339
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
1340
- },
1341
- {
1342
- id: "ec0718028a2445fb9be8e8bfb56a0150",
1343
- name: "Rodrigo",
1344
- gender: "male",
1345
- languages: ["es"],
1346
- description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1347
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
1348
- },
1349
- {
1350
- id: "10a3a20742114a4ea6dd441e7591850f",
1351
- name: "Manon",
1352
- gender: "female",
1353
- languages: ["fr"],
1354
- description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
1355
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
1356
- },
1357
- {
1358
- id: "f69bca092b674168a8d02d61ca20943c",
1359
- name: "Lucas",
1360
- gender: "male",
1361
- languages: ["fr"],
1362
- description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
1363
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
1364
- },
1365
- {
1366
- id: "3937b44b604249f18b94913daef94043",
1367
- name: "Lena",
1368
- gender: "female",
1369
- languages: ["de"],
1370
- description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1371
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
1372
- },
1373
- {
1374
- id: "c1e7cc926aa5469aa966c353094d4b0b",
1375
- name: "Lukas",
1376
- gender: "male",
1377
- languages: ["de"],
1378
- description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1379
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
1380
- },
1381
- {
1382
- id: "b3c060cc41544a7da94a2c487647c902",
1383
- name: "Let\xEDcia",
1384
- gender: "female",
1385
- accent: "brazilian",
1386
- languages: ["pt"],
1387
- 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.",
1388
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
1389
- },
1390
- {
1391
- id: "add7bcb8d3c8423bbfa152ca232aad6e",
1392
- name: "Ricardo",
1393
- gender: "male",
1394
- accent: "brazilian",
1395
- languages: ["pt"],
1396
- 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.",
1397
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
1398
- },
1399
- {
1400
- id: "b2d9d8db057042688a5e318b8f405bc2",
1401
- name: "Kyoko",
1402
- gender: "female",
1403
- languages: ["ja"],
1404
- 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",
1405
- previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
1406
- },
1407
- {
1408
- id: "297a6fd278df47c3b9da9bfdf55ac89a",
1409
- name: "Satoru",
1410
- gender: "male",
1411
- languages: ["ja"],
1412
- 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",
1413
- previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
1414
- },
1415
- {
1416
- id: "0b14f34a13a94ed88fe6113193749bb0",
1417
- name: "Fatima",
1418
- gender: "female",
1419
- languages: ["ar"],
1420
- 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.",
1421
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
1422
- },
1423
- {
1424
- id: "74c6aba5cbf94a15bbdc547ffce5cb38",
1425
- name: "Yutong",
1426
- gender: "female",
1427
- languages: ["zh"],
1428
- 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",
1429
- previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
1430
- }
1431
- ];
1432
-
1433
- // src/catalog/speech-fish.ts
1434
- var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
1435
- var PER_CALL = { unit: "images" };
1436
- var PER_REQUEST = { unit: "requests" };
1437
- var TTS_MAX_CHARS = 1e4;
1438
- function fishTts(id, label, providerModelId, description) {
1439
- return {
1440
- id,
1441
- aliases: [],
1442
- label,
1443
- type: "speech",
1444
- adapter: "fish",
1445
- providerModelId,
1446
- lifecycle: "active",
1447
- exposure: [],
1448
- constraints: {
1449
- voices: FISH_VOICES,
1450
- outputFormats: ["mp3", "wav"],
1451
- supports: [],
1452
- prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
1453
- },
1454
- defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
1455
- usage: PER_CALL,
1456
- pricingKind: "flat",
1457
- display: { provider: "fishaudio", logo: FISH_LOGO, description },
1458
- capabilities: { customVoices: true }
1459
- };
1460
- }
1461
- var FISH_MODELS = [
1462
- fishTts(
1463
- "fish-s2.1-pro",
1464
- "Fish Audio S2.1 Pro",
1465
- "s2.1-pro",
1466
- "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
1467
- ),
1468
- fishTts(
1469
- "fish-s2.1-pro-free",
1470
- "Fish Audio S2.1 Pro Free",
1471
- "s2.1-pro-free",
1472
- "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
1473
- ),
1474
- fishTts(
1475
- "fish-drama-3",
1476
- "Fish Audio Drama 3",
1477
- "drama-3",
1478
- "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
1479
- ),
1480
- {
1481
- id: "fish-voice-clone",
1482
- aliases: [],
1483
- label: "Fish Audio Voice Clone",
1484
- type: "voice-clone",
1485
- adapter: "fish",
1486
- providerModelId: "voice-clone",
1487
- lifecycle: "active",
1488
- exposure: [],
1489
- constraints: {
1490
- // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
1491
- references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
1492
- supports: []
1493
- },
1494
- defaults: {},
1495
- usage: PER_REQUEST,
1496
- pricingKind: "flat",
1497
- display: {
1498
- provider: "fishaudio",
1499
- logo: FISH_LOGO,
1500
- description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
1501
- },
1502
- capabilities: {}
1503
- },
1504
- {
1505
- id: "fish-voice-design-1",
1506
- aliases: [],
1507
- label: "Fish Audio Voice Design",
1508
- type: "voice-design",
1509
- adapter: "fish",
1510
- providerModelId: "voice-design-1",
1511
- lifecycle: "active",
1512
- exposure: [],
1513
- constraints: {
1514
- voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
1515
- supports: [],
1516
- prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
1517
- },
1518
- defaults: {},
1519
- usage: PER_REQUEST,
1520
- pricingKind: "flat",
1521
- display: {
1522
- provider: "fishaudio",
1523
- logo: FISH_LOGO,
1524
- description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
1525
- },
1526
- capabilities: {}
1527
- }
1528
- ];
1529
-
1530
1233
  // src/catalog/languages-audio.ts
1531
1234
  var ELEVENLABS_V4_LANGUAGES = [
1532
1235
  { code: "af", name: "Afrikaans" },
@@ -1901,131 +1604,494 @@ var ELEVENLABS_VOICES = [
1901
1604
  previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/IKne3meq5aSn9XLyUdCD/102de6f2-22ed-43e0-a1f1-111fa75c5481.mp3"
1902
1605
  },
1903
1606
  {
1904
- id: "George",
1905
- name: "George",
1906
- gender: "male",
1607
+ id: "George",
1608
+ name: "George",
1609
+ gender: "male",
1610
+ accent: "british",
1611
+ languages: ["en", "fr", "ar", "ja", "cs", "fil", "es", "hi"],
1612
+ description: "Warm resonance that instantly captivates listeners.",
1613
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3"
1614
+ },
1615
+ {
1616
+ id: "Callum",
1617
+ name: "Callum",
1618
+ gender: "male",
1619
+ accent: "american",
1620
+ languages: ["en", "fr", "hi"],
1621
+ description: "Deceptively gravelly, yet unsettling edge.",
1622
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
1623
+ },
1624
+ {
1625
+ id: "River",
1626
+ name: "River",
1627
+ gender: "neutral",
1628
+ accent: "american",
1629
+ languages: ["en", "it", "fr", "pt", "zh"],
1630
+ description: "A relaxed, neutral voice ready for narrations or conversational projects.",
1631
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
1632
+ },
1633
+ {
1634
+ id: "Liam",
1635
+ name: "Liam",
1636
+ gender: "male",
1637
+ accent: "american",
1638
+ languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
1639
+ description: "A young adult with energy and warmth - suitable for reels and shorts.",
1640
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
1641
+ },
1642
+ { id: "Charlotte", name: "Charlotte" },
1643
+ {
1644
+ id: "Alice",
1645
+ name: "Alice",
1646
+ gender: "female",
1647
+ accent: "british",
1648
+ languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
1649
+ description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
1650
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
1651
+ },
1652
+ {
1653
+ id: "Matilda",
1654
+ name: "Matilda",
1655
+ gender: "female",
1656
+ accent: "american",
1657
+ languages: ["en", "it", "fr", "de", "ar", "es"],
1658
+ description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
1659
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
1660
+ },
1661
+ {
1662
+ id: "Will",
1663
+ name: "Will",
1664
+ gender: "male",
1665
+ accent: "american",
1666
+ languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
1667
+ description: "Conversational and laid back.",
1668
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
1669
+ },
1670
+ {
1671
+ id: "Jessica",
1672
+ name: "Jessica",
1673
+ gender: "female",
1674
+ accent: "american",
1675
+ languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
1676
+ description: "Young and popular, this playful American female voice is perfect for trendy content.",
1677
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
1678
+ },
1679
+ {
1680
+ id: "Eric",
1681
+ name: "Eric",
1682
+ gender: "male",
1683
+ accent: "american",
1684
+ languages: ["en", "fr", "pt", "de", "sk", "es"],
1685
+ description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
1686
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
1687
+ },
1688
+ {
1689
+ id: "Chris",
1690
+ name: "Chris",
1691
+ gender: "male",
1692
+ accent: "american",
1693
+ languages: ["en", "fr", "ar", "pt", "sv", "hi"],
1694
+ description: "Natural and real, this down-to-earth voice is great across many use-cases.",
1695
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
1696
+ },
1697
+ {
1698
+ id: "Brian",
1699
+ name: "Brian",
1700
+ gender: "male",
1701
+ accent: "american",
1702
+ languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
1703
+ description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
1704
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
1705
+ },
1706
+ {
1707
+ id: "Daniel",
1708
+ name: "Daniel",
1709
+ gender: "male",
1710
+ accent: "british",
1711
+ languages: ["en", "de", "tr"],
1712
+ description: "A strong voice perfect for delivering a professional broadcast or news story.",
1713
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
1714
+ },
1715
+ {
1716
+ id: "Lily",
1717
+ name: "Lily",
1718
+ gender: "female",
1719
+ accent: "british",
1720
+ languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
1721
+ description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
1722
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
1723
+ },
1724
+ {
1725
+ id: "Bill",
1726
+ name: "Bill",
1727
+ gender: "male",
1728
+ accent: "american",
1729
+ languages: ["en", "fr", "ar", "zh", "de", "cs"],
1730
+ description: "Friendly and comforting voice ready to narrate your stories.",
1731
+ previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
1732
+ }
1733
+ ];
1734
+ var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
1735
+ var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
1736
+ const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
1737
+ return id ? [{ ...v, id }] : [];
1738
+ });
1739
+ var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
1740
+
1741
+ // src/catalog/speech-elevenlabs-direct.ts
1742
+ var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
1743
+ var PER_CALL = { unit: "images" };
1744
+ var PER_REQUEST = { unit: "requests" };
1745
+ var ELEVENLABS_DIRECT_MODELS = [
1746
+ {
1747
+ id: "elevenlabs-v4-direct",
1748
+ aliases: [],
1749
+ label: "ElevenLabs v4 (direct)",
1750
+ type: "speech",
1751
+ adapter: "elevenlabs",
1752
+ providerModelId: "eleven_v4",
1753
+ lifecycle: "active",
1754
+ exposure: [],
1755
+ constraints: {
1756
+ // Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
1757
+ voices: ELEVENLABS_DIRECT_VOICES,
1758
+ languages: ELEVENLABS_V4_LANGUAGES,
1759
+ outputFormats: ELEVENLABS_MP3_FORMATS,
1760
+ supports: [],
1761
+ // ElevenLabs docs: 10,000 characters per request.
1762
+ prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
1763
+ },
1764
+ defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
1765
+ usage: PER_CALL,
1766
+ pricingKind: "flat",
1767
+ display: {
1768
+ provider: "elevenlabs",
1769
+ logo: ELEVENLABS_LOGO,
1770
+ description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
1771
+ },
1772
+ capabilities: { customVoices: true }
1773
+ },
1774
+ {
1775
+ id: "elevenlabs-ivc",
1776
+ aliases: [],
1777
+ label: "ElevenLabs Instant Voice Clone",
1778
+ type: "voice-clone",
1779
+ adapter: "elevenlabs",
1780
+ providerModelId: "ivc",
1781
+ lifecycle: "active",
1782
+ exposure: [],
1783
+ constraints: {
1784
+ // POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
1785
+ // clean speech in total. Each clone uses a voice slot on our plan until deleted.
1786
+ references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
1787
+ supports: []
1788
+ },
1789
+ defaults: {},
1790
+ usage: PER_REQUEST,
1791
+ pricingKind: "flat",
1792
+ display: {
1793
+ provider: "elevenlabs",
1794
+ logo: ELEVENLABS_LOGO,
1795
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
1796
+ },
1797
+ capabilities: {}
1798
+ }
1799
+ ];
1800
+
1801
+ // src/catalog/voices-fish.ts
1802
+ var FISH_VOICES = [
1803
+ {
1804
+ id: "933563129e564b19a115bedd57b7406a",
1805
+ name: "Sarah",
1806
+ gender: "female",
1807
+ languages: ["en"],
1808
+ description: "An engaged speaker.",
1809
+ previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
1810
+ },
1811
+ {
1812
+ id: "bf322df2096a46f18c579d0baa36f41d",
1813
+ name: "Adrian",
1814
+ gender: "male",
1815
+ languages: ["en"],
1816
+ description: "A steady and reliable narrator.",
1817
+ previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
1818
+ },
1819
+ {
1820
+ id: "536d3a5e000945adb7038665781a4aca",
1821
+ name: "Ethan",
1822
+ gender: "male",
1823
+ languages: ["en"],
1824
+ description: "A curious explainer.",
1825
+ previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
1826
+ },
1827
+ {
1828
+ id: "b347db033a6549378b48d00acb0d06cd",
1829
+ name: "Selene",
1830
+ gender: "female",
1831
+ languages: ["en"],
1832
+ description: "A meditative female voice.",
1833
+ previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
1834
+ },
1835
+ {
1836
+ id: "9a9cf47702da476aa4629e2506d4a857",
1837
+ name: "Hannah",
1838
+ gender: "female",
1839
+ languages: ["en"],
1840
+ description: "A conversation specialist.",
1841
+ previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
1842
+ },
1843
+ {
1844
+ id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
1845
+ name: "Jordan",
1846
+ gender: "male",
1847
+ languages: ["en"],
1848
+ description: "A motivational speaker.",
1849
+ previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
1850
+ },
1851
+ {
1852
+ id: "e3cd384158934cc9a01029cd7d278634",
1853
+ name: "Laura",
1854
+ gender: "female",
1855
+ languages: ["en"],
1856
+ description: "A confident female narrator.",
1857
+ previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
1858
+ },
1859
+ {
1860
+ id: "f3a2b90078d54a65af4b95f63bc7798e",
1861
+ name: "Sheila",
1862
+ gender: "female",
1863
+ accent: "american",
1864
+ languages: ["en"],
1865
+ description: "A young American English woman's voice.",
1866
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
1867
+ },
1868
+ {
1869
+ id: "0db6e93af420470b9d9b9a886dbaa954",
1870
+ name: "Kai",
1871
+ gender: "male",
1872
+ languages: ["en"],
1873
+ description: "A friendly English man's voice for companion apps and everyday conversation.",
1874
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
1875
+ },
1876
+ {
1877
+ id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
1878
+ name: "Freya",
1879
+ gender: "female",
1907
1880
  accent: "british",
1908
- languages: ["en", "fr", "ar", "ja", "cs", "fil", "es", "hi"],
1909
- description: "Warm resonance that instantly captivates listeners.",
1910
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3"
1881
+ languages: ["en"],
1882
+ 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.",
1883
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
1911
1884
  },
1912
1885
  {
1913
- id: "Callum",
1914
- name: "Callum",
1886
+ id: "2f64e528a4f2406691925ab1e0ed5b7f",
1887
+ name: "Ananya",
1888
+ gender: "female",
1889
+ languages: ["hi"],
1890
+ 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",
1891
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
1892
+ },
1893
+ {
1894
+ id: "cefd91a07b99468f9148e2580990082d",
1895
+ name: "Arjun",
1915
1896
  gender: "male",
1916
- accent: "american",
1917
- languages: ["en", "fr", "hi"],
1918
- description: "Deceptively gravelly, yet unsettling edge.",
1919
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
1897
+ languages: ["hi"],
1898
+ 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",
1899
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
1920
1900
  },
1921
1901
  {
1922
- id: "River",
1923
- name: "River",
1924
- gender: "neutral",
1925
- accent: "american",
1926
- languages: ["en", "it", "fr", "pt", "zh"],
1927
- description: "A relaxed, neutral voice ready for narrations or conversational projects.",
1928
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
1902
+ id: "3f065d660212478a9c697fa965b4d098",
1903
+ name: "Carmen",
1904
+ gender: "female",
1905
+ languages: ["es"],
1906
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1907
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
1929
1908
  },
1930
1909
  {
1931
- id: "Liam",
1932
- name: "Liam",
1910
+ id: "ec0718028a2445fb9be8e8bfb56a0150",
1911
+ name: "Rodrigo",
1933
1912
  gender: "male",
1934
- accent: "american",
1935
- languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
1936
- description: "A young adult with energy and warmth - suitable for reels and shorts.",
1937
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
1913
+ languages: ["es"],
1914
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
1915
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
1938
1916
  },
1939
- { id: "Charlotte", name: "Charlotte" },
1940
1917
  {
1941
- id: "Alice",
1942
- name: "Alice",
1918
+ id: "10a3a20742114a4ea6dd441e7591850f",
1919
+ name: "Manon",
1943
1920
  gender: "female",
1944
- accent: "british",
1945
- languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
1946
- description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
1947
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
1921
+ languages: ["fr"],
1922
+ description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
1923
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
1948
1924
  },
1949
1925
  {
1950
- id: "Matilda",
1951
- name: "Matilda",
1926
+ id: "f69bca092b674168a8d02d61ca20943c",
1927
+ name: "Lucas",
1928
+ gender: "male",
1929
+ languages: ["fr"],
1930
+ description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
1931
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
1932
+ },
1933
+ {
1934
+ id: "3937b44b604249f18b94913daef94043",
1935
+ name: "Lena",
1952
1936
  gender: "female",
1953
- accent: "american",
1954
- languages: ["en", "it", "fr", "de", "ar", "es"],
1955
- description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
1956
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
1937
+ languages: ["de"],
1938
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1939
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
1957
1940
  },
1958
1941
  {
1959
- id: "Will",
1960
- name: "Will",
1942
+ id: "c1e7cc926aa5469aa966c353094d4b0b",
1943
+ name: "Lukas",
1961
1944
  gender: "male",
1962
- accent: "american",
1963
- languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
1964
- description: "Conversational and laid back.",
1965
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
1945
+ languages: ["de"],
1946
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
1947
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
1966
1948
  },
1967
1949
  {
1968
- id: "Jessica",
1969
- name: "Jessica",
1950
+ id: "b3c060cc41544a7da94a2c487647c902",
1951
+ name: "Let\xEDcia",
1970
1952
  gender: "female",
1971
- accent: "american",
1972
- languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
1973
- description: "Young and popular, this playful American female voice is perfect for trendy content.",
1974
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
1953
+ accent: "brazilian",
1954
+ languages: ["pt"],
1955
+ 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.",
1956
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
1975
1957
  },
1976
1958
  {
1977
- id: "Eric",
1978
- name: "Eric",
1959
+ id: "add7bcb8d3c8423bbfa152ca232aad6e",
1960
+ name: "Ricardo",
1979
1961
  gender: "male",
1980
- accent: "american",
1981
- languages: ["en", "fr", "pt", "de", "sk", "es"],
1982
- description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
1983
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
1962
+ accent: "brazilian",
1963
+ languages: ["pt"],
1964
+ 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.",
1965
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
1984
1966
  },
1985
1967
  {
1986
- id: "Chris",
1987
- name: "Chris",
1988
- gender: "male",
1989
- accent: "american",
1990
- languages: ["en", "fr", "ar", "pt", "sv", "hi"],
1991
- description: "Natural and real, this down-to-earth voice is great across many use-cases.",
1992
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
1968
+ id: "b2d9d8db057042688a5e318b8f405bc2",
1969
+ name: "Kyoko",
1970
+ gender: "female",
1971
+ languages: ["ja"],
1972
+ 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",
1973
+ previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
1993
1974
  },
1994
1975
  {
1995
- id: "Brian",
1996
- name: "Brian",
1976
+ id: "297a6fd278df47c3b9da9bfdf55ac89a",
1977
+ name: "Satoru",
1997
1978
  gender: "male",
1998
- accent: "american",
1999
- languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
2000
- description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
2001
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
1979
+ languages: ["ja"],
1980
+ 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",
1981
+ previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
2002
1982
  },
2003
1983
  {
2004
- id: "Daniel",
2005
- name: "Daniel",
2006
- gender: "male",
2007
- accent: "british",
2008
- languages: ["en", "de", "tr"],
2009
- description: "A strong voice perfect for delivering a professional broadcast or news story.",
2010
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
1984
+ id: "0b14f34a13a94ed88fe6113193749bb0",
1985
+ name: "Fatima",
1986
+ gender: "female",
1987
+ languages: ["ar"],
1988
+ 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.",
1989
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
2011
1990
  },
2012
1991
  {
2013
- id: "Lily",
2014
- name: "Lily",
1992
+ id: "74c6aba5cbf94a15bbdc547ffce5cb38",
1993
+ name: "Yutong",
2015
1994
  gender: "female",
2016
- accent: "british",
2017
- languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
2018
- description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
2019
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
1995
+ languages: ["zh"],
1996
+ 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",
1997
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
1998
+ }
1999
+ ];
2000
+
2001
+ // src/catalog/speech-fish.ts
2002
+ var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
2003
+ var PER_CALL2 = { unit: "images" };
2004
+ var PER_REQUEST2 = { unit: "requests" };
2005
+ var TTS_MAX_CHARS = 1e4;
2006
+ function fishTts(id, label, providerModelId, description) {
2007
+ return {
2008
+ id,
2009
+ aliases: [],
2010
+ label,
2011
+ type: "speech",
2012
+ adapter: "fish",
2013
+ providerModelId,
2014
+ lifecycle: "active",
2015
+ exposure: [],
2016
+ constraints: {
2017
+ voices: FISH_VOICES,
2018
+ outputFormats: ["mp3", "wav"],
2019
+ supports: [],
2020
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2021
+ },
2022
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2023
+ usage: PER_CALL2,
2024
+ pricingKind: "flat",
2025
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2026
+ capabilities: { customVoices: true }
2027
+ };
2028
+ }
2029
+ var FISH_MODELS = [
2030
+ fishTts(
2031
+ "fish-s2.1-pro",
2032
+ "Fish Audio S2.1 Pro",
2033
+ "s2.1-pro",
2034
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2035
+ ),
2036
+ fishTts(
2037
+ "fish-s2.1-pro-free",
2038
+ "Fish Audio S2.1 Pro Free",
2039
+ "s2.1-pro-free",
2040
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2041
+ ),
2042
+ fishTts(
2043
+ "fish-drama-3",
2044
+ "Fish Audio Drama 3",
2045
+ "drama-3",
2046
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2047
+ ),
2048
+ {
2049
+ id: "fish-voice-clone",
2050
+ aliases: [],
2051
+ label: "Fish Audio Voice Clone",
2052
+ type: "voice-clone",
2053
+ adapter: "fish",
2054
+ providerModelId: "voice-clone",
2055
+ lifecycle: "active",
2056
+ exposure: [],
2057
+ constraints: {
2058
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2059
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2060
+ supports: []
2061
+ },
2062
+ defaults: {},
2063
+ usage: PER_REQUEST2,
2064
+ pricingKind: "flat",
2065
+ display: {
2066
+ provider: "fishaudio",
2067
+ logo: FISH_LOGO,
2068
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2069
+ },
2070
+ capabilities: {}
2020
2071
  },
2021
2072
  {
2022
- id: "Bill",
2023
- name: "Bill",
2024
- gender: "male",
2025
- accent: "american",
2026
- languages: ["en", "fr", "ar", "zh", "de", "cs"],
2027
- description: "Friendly and comforting voice ready to narrate your stories.",
2028
- previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
2073
+ id: "fish-voice-design-1",
2074
+ aliases: [],
2075
+ label: "Fish Audio Voice Design",
2076
+ type: "voice-design",
2077
+ adapter: "fish",
2078
+ providerModelId: "voice-design-1",
2079
+ lifecycle: "active",
2080
+ exposure: [],
2081
+ constraints: {
2082
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2083
+ supports: [],
2084
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2085
+ },
2086
+ defaults: {},
2087
+ usage: PER_REQUEST2,
2088
+ pricingKind: "flat",
2089
+ display: {
2090
+ provider: "fishaudio",
2091
+ logo: FISH_LOGO,
2092
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2093
+ },
2094
+ capabilities: {}
2029
2095
  }
2030
2096
  ];
2031
2097
 
@@ -3604,11 +3670,11 @@ var MINIMAX_VOICES = [
3604
3670
  ];
3605
3671
 
3606
3672
  // src/catalog/media-nodes.ts
3607
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3673
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3608
3674
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3609
3675
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3610
3676
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3611
- var PER_CALL2 = { unit: "images" };
3677
+ var PER_CALL3 = { unit: "images" };
3612
3678
  var EXPOSURE4 = ["cowork", "space_builder"];
3613
3679
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3614
3680
  function elevenLabsTts(tts) {
@@ -3629,9 +3695,9 @@ function elevenLabsTts(tts) {
3629
3695
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3630
3696
  },
3631
3697
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3632
- usage: PER_CALL2,
3698
+ usage: PER_CALL3,
3633
3699
  pricingKind: "flat",
3634
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3700
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3635
3701
  capabilities: {}
3636
3702
  };
3637
3703
  }
@@ -3653,7 +3719,7 @@ function geminiTts(id, label, description) {
3653
3719
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3654
3720
  },
3655
3721
  defaults: { voice: "Kore" },
3656
- usage: PER_CALL2,
3722
+ usage: PER_CALL3,
3657
3723
  pricingKind: "flat",
3658
3724
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3659
3725
  capabilities: {}
@@ -3676,7 +3742,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3676
3742
  },
3677
3743
  defaults: {},
3678
3744
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3679
- usage: PER_CALL2,
3745
+ usage: PER_CALL3,
3680
3746
  pricingKind: "flat",
3681
3747
  display: { provider: "sync", logo: SYNC_LOGO, description },
3682
3748
  capabilities: { acceptsSourceVideo: true }
@@ -3737,7 +3803,7 @@ var MEDIA_NODE_MODELS = [
3737
3803
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3738
3804
  },
3739
3805
  defaults: { voice: "Wise_Woman" },
3740
- usage: PER_CALL2,
3806
+ usage: PER_CALL3,
3741
3807
  pricingKind: "flat",
3742
3808
  display: {
3743
3809
  provider: "minimax",
@@ -3764,11 +3830,11 @@ var MEDIA_NODE_MODELS = [
3764
3830
  supports: []
3765
3831
  },
3766
3832
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3767
- usage: PER_CALL2,
3833
+ usage: PER_CALL3,
3768
3834
  pricingKind: "flat",
3769
3835
  display: {
3770
3836
  provider: "elevenlabs",
3771
- logo: ELEVENLABS_LOGO,
3837
+ logo: ELEVENLABS_LOGO2,
3772
3838
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3773
3839
  },
3774
3840
  capabilities: {}
@@ -3791,11 +3857,11 @@ var MEDIA_NODE_MODELS = [
3791
3857
  supports: []
3792
3858
  },
3793
3859
  defaults: {},
3794
- usage: PER_CALL2,
3860
+ usage: PER_CALL3,
3795
3861
  pricingKind: "flat",
3796
3862
  display: {
3797
3863
  provider: "elevenlabs",
3798
- logo: ELEVENLABS_LOGO,
3864
+ logo: ELEVENLABS_LOGO2,
3799
3865
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3800
3866
  },
3801
3867
  capabilities: { acceptsSourceVideo: true }
@@ -3838,7 +3904,7 @@ var MEDIA_NODE_MODELS = [
3838
3904
  supports: []
3839
3905
  },
3840
3906
  defaults: {},
3841
- usage: PER_CALL2,
3907
+ usage: PER_CALL3,
3842
3908
  pricingKind: "flat",
3843
3909
  display: {
3844
3910
  provider: "veed",
@@ -3890,17 +3956,18 @@ var MEDIA_NODE_MODELS = [
3890
3956
  supports: []
3891
3957
  },
3892
3958
  defaults: {},
3893
- usage: PER_CALL2,
3959
+ usage: PER_CALL3,
3894
3960
  pricingKind: "flat",
3895
3961
  display: {
3896
3962
  provider: "elevenlabs",
3897
- logo: ELEVENLABS_LOGO,
3963
+ logo: ELEVENLABS_LOGO2,
3898
3964
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
3899
3965
  },
3900
3966
  capabilities: {}
3901
3967
  },
3902
3968
  SAM_3_IMAGE,
3903
- ...FISH_MODELS
3969
+ ...FISH_MODELS,
3970
+ ...ELEVENLABS_DIRECT_MODELS
3904
3971
  ];
3905
3972
 
3906
3973
  // src/catalog/model3d.ts
@@ -4096,7 +4163,7 @@ var MODEL3D_MODELS = [
4096
4163
 
4097
4164
  // src/catalog/other.ts
4098
4165
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
4099
- var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4166
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4100
4167
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
4101
4168
  var OTHER_MODELS = [
4102
4169
  {
@@ -4261,7 +4328,7 @@ var OTHER_MODELS = [
4261
4328
  pricingKind: "flat",
4262
4329
  display: {
4263
4330
  provider: "elevenlabs",
4264
- logo: ELEVENLABS_LOGO2,
4331
+ logo: ELEVENLABS_LOGO3,
4265
4332
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
4266
4333
  },
4267
4334
  capabilities: {}
@@ -4313,7 +4380,7 @@ var OTHER_MODELS = [
4313
4380
  pricingKind: "flat",
4314
4381
  display: {
4315
4382
  provider: "elevenlabs",
4316
- logo: ELEVENLABS_LOGO2,
4383
+ logo: ELEVENLABS_LOGO3,
4317
4384
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4318
4385
  },
4319
4386
  capabilities: {}
@@ -7536,7 +7603,8 @@ var ADAPTER_IDS = [
7536
7603
  "higgsfield",
7537
7604
  "xai-video",
7538
7605
  "luma",
7539
- "fish"
7606
+ "fish",
7607
+ "elevenlabs"
7540
7608
  ];
7541
7609
  var ModelTypeSchema = z3.enum([
7542
7610
  "text",
@@ -8749,16 +8817,16 @@ async function generateSeedreamImage(req, ctx) {
8749
8817
  } else {
8750
8818
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8751
8819
  }
8752
- const usage4 = {
8820
+ const usage5 = {
8753
8821
  model: modelId,
8754
8822
  provider: "ark",
8755
8823
  modality: "IMAGE",
8756
8824
  unit: "images",
8757
8825
  quantity: 1
8758
8826
  };
8759
- if (req.size !== void 0) usage4.imageSize = req.size;
8760
- if (req.quality !== void 0) usage4.imageQuality = req.quality;
8761
- return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage4, raw: data };
8827
+ if (req.size !== void 0) usage5.imageSize = req.size;
8828
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8829
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8762
8830
  }
8763
8831
  var SeedanceUsageSchema = z7.object({
8764
8832
  total_tokens: z7.number().optional(),
@@ -8799,7 +8867,7 @@ function seedanceErrorMessage(error, status) {
8799
8867
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8800
8868
  return `Seedance task ${status}`;
8801
8869
  }
8802
- function seedanceJob(ctx, key, jobId, usage4) {
8870
+ function seedanceJob(ctx, key, jobId, usage5) {
8803
8871
  const modelId = ctx.model.id;
8804
8872
  const fetchStatus = async () => {
8805
8873
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8849,21 +8917,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
8849
8917
  modelId
8850
8918
  );
8851
8919
  if (polled.duration !== void 0 && polled.duration > 0) {
8852
- usage4.quantity = polled.duration;
8853
- usage4.durationSeconds = polled.duration;
8920
+ usage5.quantity = polled.duration;
8921
+ usage5.durationSeconds = polled.duration;
8854
8922
  }
8855
8923
  const rendered = VideoResolutionSchema.safeParse(
8856
8924
  polled.resolution?.toLowerCase()
8857
8925
  );
8858
- if (rendered.success) usage4.resolution = rendered.data;
8926
+ if (rendered.success) usage5.resolution = rendered.data;
8859
8927
  const tokens = polled.usage;
8860
8928
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
8861
- usage4.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8862
- usage4.outputTokens = tokens.completion_tokens;
8929
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8930
+ usage5.outputTokens = tokens.completion_tokens;
8863
8931
  }
8864
8932
  return {
8865
8933
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8866
- usage: usage4,
8934
+ usage: usage5,
8867
8935
  raw: polled
8868
8936
  };
8869
8937
  }
@@ -8969,8 +9037,8 @@ async function generateSeedanceVideo(req, ctx) {
8969
9037
  );
8970
9038
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8971
9039
  const jobId = submit.id;
8972
- const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8973
- return seedanceJob(ctx, key, jobId, usage4);
9040
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9041
+ return seedanceJob(ctx, key, jobId, usage5);
8974
9042
  }
8975
9043
 
8976
9044
  // src/adapters/fal.ts
@@ -10458,7 +10526,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10458
10526
  return { bytes, mime: mime || "image/png" };
10459
10527
  })
10460
10528
  );
10461
- const usage4 = {
10529
+ const usage5 = {
10462
10530
  model: ctx.model.id,
10463
10531
  provider: "fal",
10464
10532
  modality: "IMAGE",
@@ -10466,9 +10534,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10466
10534
  quantity: images.length
10467
10535
  };
10468
10536
  const billedSize = plan4.imageSize ?? req.size;
10469
- if (billedSize !== void 0 && ctx.model.type === "image") usage4.imageSize = billedSize;
10470
- if (plan4.imageQuality !== void 0) usage4.imageQuality = plan4.imageQuality;
10471
- const result = { images, usage: usage4, raw: payload };
10537
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10538
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10539
+ const result = { images, usage: usage5, raw: payload };
10472
10540
  const remote = files.find((f) => !f.url.startsWith("data:"));
10473
10541
  if (remote !== void 0) result.outputUrl = remote.url;
10474
10542
  return result;
@@ -12631,9 +12699,282 @@ function planUsage(ctx, plan4) {
12631
12699
  };
12632
12700
  }
12633
12701
 
12634
- // src/adapters/fish.ts
12702
+ // src/adapters/elevenlabs.ts
12635
12703
  import { z as z21 } from "zod";
12636
- var DEFAULT_BASE_URL = "https://api.fish.audio";
12704
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12705
+ var DEFAULT_FORMAT = "mp3_44100_128";
12706
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12707
+ var ELEVENLABS_IVC = "ivc";
12708
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12709
+ function elevenLabsRowRefusal(row2) {
12710
+ const id = row2.providerModelId;
12711
+ if (row2.type === "speech") {
12712
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12713
+ }
12714
+ if (row2.type === "voice-clone") {
12715
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12716
+ }
12717
+ return `elevenlabs has no ${row2.type} rows`;
12718
+ }
12719
+ function elevenLabsError(ctx, code, message) {
12720
+ return new ModelKitError({
12721
+ code,
12722
+ message,
12723
+ provider: "elevenlabs",
12724
+ model: ctx.model.id,
12725
+ retryable: false
12726
+ });
12727
+ }
12728
+ function checkRow(ctx, type) {
12729
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12730
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12731
+ throw elevenLabsError(
12732
+ ctx,
12733
+ "unsupported_option",
12734
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12735
+ );
12736
+ }
12737
+ }
12738
+ function checkVoiceId(ctx, field, id) {
12739
+ if (!VOICE_ID.test(id))
12740
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12741
+ return id;
12742
+ }
12743
+ function elevenLabsKey(ctx) {
12744
+ const key = ctx.keys.elevenlabs;
12745
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12746
+ return key;
12747
+ }
12748
+ function elevenLabsUrl(ctx, path) {
12749
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12750
+ }
12751
+ var errorDetail = z21.object({
12752
+ detail: z21.object({ status: z21.string(), message: z21.string().optional() })
12753
+ });
12754
+ function errorStatus(body) {
12755
+ const parsed = errorDetail.safeParse(body);
12756
+ return parsed.success ? parsed.data.detail : void 0;
12757
+ }
12758
+ function classifyResponse(ctx, status, body) {
12759
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12760
+ const detail = errorStatus(body);
12761
+ if (detail?.status === "voice_limit_reached") {
12762
+ return new ModelKitError({
12763
+ code: "provider_rejected",
12764
+ message: detail.message ?? "ElevenLabs voice limit reached",
12765
+ provider: "elevenlabs",
12766
+ model: ctx.model.id,
12767
+ status,
12768
+ body,
12769
+ cause: error,
12770
+ retryable: false
12771
+ });
12772
+ }
12773
+ if (detail?.status === "quota_exceeded") {
12774
+ return new ModelKitError({
12775
+ code: "provider_billing",
12776
+ message: error.message,
12777
+ provider: "elevenlabs",
12778
+ model: ctx.model.id,
12779
+ status,
12780
+ body,
12781
+ cause: error,
12782
+ retryable: false
12783
+ });
12784
+ }
12785
+ return error;
12786
+ }
12787
+ async function elevenLabsFetch(ctx, path, init) {
12788
+ throwIfAborted(ctx.signal);
12789
+ const request = {
12790
+ method: init.method,
12791
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12792
+ };
12793
+ if (init.body !== void 0) request.body = init.body;
12794
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12795
+ let res;
12796
+ try {
12797
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12798
+ } catch (cause) {
12799
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12800
+ }
12801
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12802
+ return res;
12803
+ }
12804
+ function usage2(ctx) {
12805
+ return {
12806
+ model: ctx.model.id,
12807
+ provider: "elevenlabs",
12808
+ modality: "AUDIO",
12809
+ unit: ctx.model.usage.unit,
12810
+ quantity: 1
12811
+ };
12812
+ }
12813
+ function audioMime(res) {
12814
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12815
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12816
+ }
12817
+ async function generateSpeech(req, ctx) {
12818
+ checkRow(ctx, "speech");
12819
+ const voice = req.customVoice ?? req.voice;
12820
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12821
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12822
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12823
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12824
+ if (req.language !== void 0) body.language_code = req.language;
12825
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12826
+ const { bytes, mime } = await withRetry(
12827
+ async () => {
12828
+ const res = await elevenLabsFetch(ctx, path, {
12829
+ method: "POST",
12830
+ headers: { "Content-Type": "application/json" },
12831
+ body: JSON.stringify(body)
12832
+ });
12833
+ let audio;
12834
+ try {
12835
+ audio = new Uint8Array(await res.arrayBuffer());
12836
+ } catch (cause) {
12837
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12838
+ }
12839
+ return { bytes: audio, mime: audioMime(res) };
12840
+ },
12841
+ mediaRetryOptions(ctx.call, ctx.signal)
12842
+ );
12843
+ if (bytes.byteLength === 0)
12844
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12845
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12846
+ }
12847
+ var createdVoiceSchema = z21.object({
12848
+ voice_id: z21.string().min(1),
12849
+ requires_verification: z21.boolean().optional().catch(void 0)
12850
+ });
12851
+ function sampleMime(mime) {
12852
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12853
+ }
12854
+ function fileName(index, mime, ref) {
12855
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12856
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
12857
+ const ext = fromMime || fromUrl?.toLowerCase();
12858
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
12859
+ }
12860
+ async function cloneForm(req, ctx) {
12861
+ if (req.samples.length === 0)
12862
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
12863
+ if (req.samples.some((s) => s.designSignature?.trim())) {
12864
+ throw elevenLabsError(
12865
+ ctx,
12866
+ "unsupported_option",
12867
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
12868
+ );
12869
+ }
12870
+ const form = new FormData();
12871
+ form.append("name", req.title.trim());
12872
+ if (req.description?.trim()) form.append("description", req.description.trim());
12873
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
12874
+ for (const [index, sample] of req.samples.entries()) {
12875
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
12876
+ signal: ctx.signal,
12877
+ provider: "elevenlabs",
12878
+ model: ctx.model.id
12879
+ });
12880
+ const type = sampleMime(mime);
12881
+ const audio = new Blob([new Uint8Array(bytes)], { type });
12882
+ form.append("files", audio, fileName(index, type, sample.audio));
12883
+ }
12884
+ return form;
12885
+ }
12886
+ async function onlyRateLimitRetries(fn) {
12887
+ try {
12888
+ return await fn();
12889
+ } catch (cause) {
12890
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
12891
+ throw cause;
12892
+ throw new ModelKitError({
12893
+ code: cause.code,
12894
+ message: cause.message,
12895
+ ...cause.provider !== void 0 && { provider: cause.provider },
12896
+ ...cause.model !== void 0 && { model: cause.model },
12897
+ ...cause.status !== void 0 && { status: cause.status },
12898
+ ...cause.body !== void 0 && { body: cause.body },
12899
+ cause,
12900
+ retryable: false
12901
+ });
12902
+ }
12903
+ }
12904
+ async function createVoice(req, ctx) {
12905
+ checkRow(ctx, "voice-clone");
12906
+ const form = await cloneForm(req, ctx);
12907
+ const res = await withRetry(
12908
+ () => onlyRateLimitRetries(
12909
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
12910
+ ),
12911
+ mediaRetryOptions(ctx.call, ctx.signal)
12912
+ );
12913
+ const raw = await readBody(res);
12914
+ const parsed = createdVoiceSchema.safeParse(raw);
12915
+ if (!parsed.success) {
12916
+ throw new ModelKitError({
12917
+ code: "provider_rejected",
12918
+ message: "ElevenLabs returned no voice id",
12919
+ provider: "elevenlabs",
12920
+ model: ctx.model.id,
12921
+ status: res.status,
12922
+ body: raw,
12923
+ retryable: false
12924
+ });
12925
+ }
12926
+ return {
12927
+ voiceId: parsed.data.voice_id,
12928
+ state: parsed.data.requires_verification === true ? "created" : "trained",
12929
+ usage: usage2(ctx),
12930
+ raw
12931
+ };
12932
+ }
12933
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
12934
+ "voice_not_found",
12935
+ "voice_does_not_exist"
12936
+ ]);
12937
+ function notFound(cause) {
12938
+ if (cause.status === 404) return true;
12939
+ const status = errorStatus(cause.body)?.status;
12940
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
12941
+ }
12942
+ async function deleteVoice(req, ctx) {
12943
+ checkRow(ctx, "voice-clone");
12944
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
12945
+ let attempts = 0;
12946
+ await withRetry(
12947
+ async () => {
12948
+ attempts += 1;
12949
+ try {
12950
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
12951
+ } catch (cause) {
12952
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
12953
+ if (attempts > 1) return;
12954
+ throw new ModelKitError({
12955
+ code: "provider_rejected",
12956
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
12957
+ provider: "elevenlabs",
12958
+ model: ctx.model.id,
12959
+ ...cause.status !== void 0 && { status: cause.status },
12960
+ cause,
12961
+ retryable: false
12962
+ });
12963
+ }
12964
+ },
12965
+ mediaRetryOptions(ctx.call, ctx.signal)
12966
+ );
12967
+ }
12968
+ var elevenLabsAdapter = {
12969
+ id: "elevenlabs",
12970
+ generateSpeech,
12971
+ createVoice,
12972
+ deleteVoice
12973
+ };
12974
+
12975
+ // src/adapters/fish.ts
12976
+ import { z as z22 } from "zod";
12977
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
12637
12978
  var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12638
12979
  "s2.1-pro",
12639
12980
  "s2.1-pro-free",
@@ -12641,7 +12982,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12641
12982
  ]);
12642
12983
  var FISH_VOICE_CLONE = "voice-clone";
12643
12984
  var FISH_VOICE_DESIGN = "voice-design-1";
12644
- var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12985
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
12645
12986
  function fishRowRefusal(row2) {
12646
12987
  const id = row2.providerModelId;
12647
12988
  if (row2.type === "speech") {
@@ -12664,7 +13005,7 @@ function fishError(ctx, code, message) {
12664
13005
  retryable: false
12665
13006
  });
12666
13007
  }
12667
- function checkRow(ctx, type) {
13008
+ function checkRow2(ctx, type) {
12668
13009
  const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12669
13010
  if (ctx.model.type !== type || refusal2 !== void 0) {
12670
13011
  throw fishError(
@@ -12674,8 +13015,8 @@ function checkRow(ctx, type) {
12674
13015
  );
12675
13016
  }
12676
13017
  }
12677
- function checkVoiceId(ctx, field, id) {
12678
- if (!VOICE_ID.test(id))
13018
+ function checkVoiceId2(ctx, field, id) {
13019
+ if (!VOICE_ID2.test(id))
12679
13020
  throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12680
13021
  return id;
12681
13022
  }
@@ -12685,7 +13026,7 @@ function fishKey(ctx) {
12685
13026
  return key;
12686
13027
  }
12687
13028
  function fishUrl(ctx, path) {
12688
- return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
13029
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
12689
13030
  }
12690
13031
  async function fishFetch(ctx, path, init) {
12691
13032
  throwIfAborted(ctx.signal);
@@ -12704,7 +13045,7 @@ async function fishFetch(ctx, path, init) {
12704
13045
  if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12705
13046
  return res;
12706
13047
  }
12707
- function usage2(ctx) {
13048
+ function usage3(ctx) {
12708
13049
  return {
12709
13050
  model: ctx.model.id,
12710
13051
  provider: "fish",
@@ -12713,18 +13054,18 @@ function usage2(ctx) {
12713
13054
  quantity: 1
12714
13055
  };
12715
13056
  }
12716
- function audioMime(res, format) {
13057
+ function audioMime2(res, format) {
12717
13058
  const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12718
13059
  if (header?.startsWith("audio/")) return header;
12719
13060
  return format === "wav" ? "audio/wav" : "audio/mpeg";
12720
13061
  }
12721
- async function generateSpeech(req, ctx) {
12722
- checkRow(ctx, "speech");
13062
+ async function generateSpeech2(req, ctx) {
13063
+ checkRow2(ctx, "speech");
12723
13064
  const format = req.outputFormat ?? "mp3";
12724
13065
  const body = { text: req.text, format };
12725
13066
  const voice = req.customVoice ?? req.voice;
12726
13067
  if (voice !== void 0) {
12727
- body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
13068
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
12728
13069
  }
12729
13070
  if (req.language !== void 0) body.language = req.language;
12730
13071
  const { bytes, mime } = await withRetry(
@@ -12740,19 +13081,19 @@ async function generateSpeech(req, ctx) {
12740
13081
  } catch (cause) {
12741
13082
  throw classifyThrown("fish", cause, ctx.model.id);
12742
13083
  }
12743
- return { bytes: audio, mime: audioMime(res, format) };
13084
+ return { bytes: audio, mime: audioMime2(res, format) };
12744
13085
  },
12745
13086
  mediaRetryOptions(ctx.call, ctx.signal)
12746
13087
  );
12747
13088
  if (bytes.byteLength === 0)
12748
13089
  throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12749
- return { audio: { bytes, mime }, usage: usage2(ctx) };
13090
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
12750
13091
  }
12751
- var createdModelSchema = z21.object({
12752
- _id: z21.string().min(1),
12753
- state: z21.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
13092
+ var createdModelSchema = z22.object({
13093
+ _id: z22.string().min(1),
13094
+ state: z22.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12754
13095
  });
12755
- function fileName(index, mime) {
13096
+ function fileName2(index, mime) {
12756
13097
  const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12757
13098
  return `sample-${index + 1}.${ext}`;
12758
13099
  }
@@ -12764,7 +13105,7 @@ function allOrNone(ctx, field, values) {
12764
13105
  }
12765
13106
  return set;
12766
13107
  }
12767
- async function cloneForm(req, ctx) {
13108
+ async function cloneForm2(req, ctx) {
12768
13109
  if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12769
13110
  const transcripts = allOrNone(
12770
13111
  ctx,
@@ -12790,13 +13131,13 @@ async function cloneForm(req, ctx) {
12790
13131
  model: ctx.model.id
12791
13132
  });
12792
13133
  const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12793
- form.append("voices", audio, fileName(index, mime));
13134
+ form.append("voices", audio, fileName2(index, mime));
12794
13135
  }
12795
13136
  for (const text2 of transcripts) form.append("texts", text2.trim());
12796
13137
  for (const signature of signatures) form.append("voice_design_signatures", signature);
12797
13138
  return form;
12798
13139
  }
12799
- async function onlyRateLimitRetries(fn) {
13140
+ async function onlyRateLimitRetries2(fn) {
12800
13141
  try {
12801
13142
  return await fn();
12802
13143
  } catch (cause) {
@@ -12814,11 +13155,11 @@ async function onlyRateLimitRetries(fn) {
12814
13155
  });
12815
13156
  }
12816
13157
  }
12817
- async function createVoice(req, ctx) {
12818
- checkRow(ctx, "voice-clone");
12819
- const form = await cloneForm(req, ctx);
13158
+ async function createVoice2(req, ctx) {
13159
+ checkRow2(ctx, "voice-clone");
13160
+ const form = await cloneForm2(req, ctx);
12820
13161
  const res = await withRetry(
12821
- () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13162
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12822
13163
  mediaRetryOptions(ctx.call, ctx.signal)
12823
13164
  );
12824
13165
  const raw = await readBody(res);
@@ -12834,23 +13175,23 @@ async function createVoice(req, ctx) {
12834
13175
  retryable: false
12835
13176
  });
12836
13177
  }
12837
- const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
13178
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
12838
13179
  if (parsed.data.state !== void 0) result.state = parsed.data.state;
12839
13180
  return result;
12840
13181
  }
12841
- var designSchema = z21.object({
12842
- candidates: z21.array(
12843
- z21.looseObject({
12844
- id: z21.string().min(1),
12845
- index: z21.number().int(),
12846
- audio_base64: z21.string().min(1),
12847
- duration_ms: z21.number().nonnegative(),
12848
- signature: z21.string().min(1).optional()
13182
+ var designSchema = z22.object({
13183
+ candidates: z22.array(
13184
+ z22.looseObject({
13185
+ id: z22.string().min(1),
13186
+ index: z22.number().int(),
13187
+ audio_base64: z22.string().min(1),
13188
+ duration_ms: z22.number().nonnegative(),
13189
+ signature: z22.string().min(1).optional()
12849
13190
  })
12850
13191
  ).min(1)
12851
13192
  });
12852
13193
  async function designVoice(req, ctx) {
12853
- checkRow(ctx, "voice-design");
13194
+ checkRow2(ctx, "voice-design");
12854
13195
  const body = { instruction: req.prompt.trim() };
12855
13196
  if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12856
13197
  if (req.language !== void 0) body.language = req.language;
@@ -12878,11 +13219,11 @@ async function designVoice(req, ctx) {
12878
13219
  // rejects a clone whose signature does not verify, so a wrong one fails loudly.
12879
13220
  signature: c.signature ?? c.id
12880
13221
  }));
12881
- return { candidates, usage: usage2(ctx) };
13222
+ return { candidates, usage: usage3(ctx) };
12882
13223
  }
12883
- async function deleteVoice(req, ctx) {
12884
- checkRow(ctx, "voice-clone");
12885
- const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13224
+ async function deleteVoice2(req, ctx) {
13225
+ checkRow2(ctx, "voice-clone");
13226
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
12886
13227
  let attempts = 0;
12887
13228
  await withRetry(
12888
13229
  async () => {
@@ -12908,20 +13249,20 @@ async function deleteVoice(req, ctx) {
12908
13249
  }
12909
13250
  var fishAdapter = {
12910
13251
  id: "fish",
12911
- generateSpeech,
12912
- createVoice,
13252
+ generateSpeech: generateSpeech2,
13253
+ createVoice: createVoice2,
12913
13254
  designVoice,
12914
- deleteVoice
13255
+ deleteVoice: deleteVoice2
12915
13256
  };
12916
13257
 
12917
13258
  // src/adapters/google-genai.ts
12918
- import { z as z23 } from "zod";
13259
+ import { z as z24 } from "zod";
12919
13260
  import {
12920
13261
  GoogleGenAI
12921
13262
  } from "@google/genai";
12922
13263
 
12923
13264
  // src/adapters/google-files.ts
12924
- import { z as z22 } from "zod";
13265
+ import { z as z23 } from "zod";
12925
13266
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12926
13267
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12927
13268
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12931,17 +13272,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12931
13272
  "binary/octet-stream",
12932
13273
  "application/binary"
12933
13274
  ]);
12934
- var uploadedFileSchema = z22.object({
12935
- file: z22.object({
12936
- uri: z22.string().optional(),
12937
- name: z22.string().optional(),
12938
- state: z22.string().optional(),
12939
- mimeType: z22.string().optional()
13275
+ var uploadedFileSchema = z23.object({
13276
+ file: z23.object({
13277
+ uri: z23.string().optional(),
13278
+ name: z23.string().optional(),
13279
+ state: z23.string().optional(),
13280
+ mimeType: z23.string().optional()
12940
13281
  }).optional()
12941
13282
  });
12942
- var fileStateSchema = z22.object({
12943
- state: z22.string().optional(),
12944
- error: z22.object({ message: z22.string().optional() }).optional()
13283
+ var fileStateSchema = z23.object({
13284
+ state: z23.string().optional(),
13285
+ error: z23.object({ message: z23.string().optional() }).optional()
12945
13286
  });
12946
13287
  function resolveMime(declared, fallback) {
12947
13288
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -13048,7 +13389,7 @@ async function startAndUpload(bytes, mimeType, opts) {
13048
13389
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
13049
13390
  return ref;
13050
13391
  }
13051
- async function waitForActive(fileName2, opts) {
13392
+ async function waitForActive(fileName3, opts) {
13052
13393
  const pollOptions2 = {
13053
13394
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
13054
13395
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -13061,14 +13402,14 @@ async function waitForActive(fileName2, opts) {
13061
13402
  retryInit.signal = opts.signal;
13062
13403
  }
13063
13404
  await pollUntil(async () => {
13064
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
13405
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
13065
13406
  if (res.ok) {
13066
13407
  const json = fileStateSchema.parse(await res.json());
13067
13408
  if (json.state === "ACTIVE") return true;
13068
13409
  if (json.state === "FAILED") {
13069
13410
  throw classifyHttpError(
13070
13411
  void 0,
13071
- `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
13412
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
13072
13413
  "google-genai",
13073
13414
  opts.model
13074
13415
  );
@@ -13080,9 +13421,9 @@ async function waitForActive(fileName2, opts) {
13080
13421
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
13081
13422
  }, pollOptions2);
13082
13423
  }
13083
- async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
13424
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
13084
13425
  try {
13085
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
13426
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
13086
13427
  method: "DELETE",
13087
13428
  headers: { "x-goog-api-key": apiKey }
13088
13429
  });
@@ -13162,7 +13503,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
13162
13503
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
13163
13504
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
13164
13505
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
13165
- var errorTextSchema = z23.string();
13506
+ var errorTextSchema = z24.string();
13166
13507
  function isGoogleGenaiVideoKnown(providerModelId) {
13167
13508
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
13168
13509
  }
@@ -13357,7 +13698,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13357
13698
  }
13358
13699
  };
13359
13700
  const jobId = operation.name ?? crypto.randomUUID();
13360
- const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13701
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13361
13702
  return {
13362
13703
  jobId,
13363
13704
  async poll() {
@@ -13395,7 +13736,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13395
13736
  modelId
13396
13737
  );
13397
13738
  }
13398
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
13739
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
13399
13740
  }
13400
13741
  };
13401
13742
  }
@@ -13506,7 +13847,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13506
13847
  return file.fileUri;
13507
13848
  };
13508
13849
  const cleanupUploads = async () => {
13509
- for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
13850
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
13510
13851
  };
13511
13852
  const callCreate = (input) => client2.interactions.create(
13512
13853
  previousId !== void 0 ? {
@@ -13600,7 +13941,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13600
13941
  if (!(extend && !chained)) await cleanupUploads();
13601
13942
  }
13602
13943
  const jobId = interaction.id ?? crypto.randomUUID();
13603
- const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13944
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13604
13945
  const getInteraction = async () => {
13605
13946
  try {
13606
13947
  const getParams = { stream: false };
@@ -13648,7 +13989,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13648
13989
  bytes: Buffer.from(video.data, "base64"),
13649
13990
  mime: video.mime_type ?? "video/mp4"
13650
13991
  },
13651
- usage: usage4,
13992
+ usage: usage5,
13652
13993
  raw: done,
13653
13994
  providerRef
13654
13995
  };
@@ -13656,7 +13997,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13656
13997
  if (video.uri)
13657
13998
  return {
13658
13999
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13659
- usage: usage4,
14000
+ usage: usage5,
13660
14001
  raw: done,
13661
14002
  providerRef
13662
14003
  };
@@ -13826,15 +14167,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13826
14167
  // src/adapters/google-image.ts
13827
14168
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
13828
14169
  import { generateText } from "ai";
13829
- import { z as z24 } from "zod";
14170
+ import { z as z25 } from "zod";
13830
14171
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13831
14172
  var defaultGoogleImageDeps = {
13832
14173
  createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
13833
14174
  runTextGeneration: (opts) => generateText(opts)
13834
14175
  };
13835
- var causeChainNodeSchema = z24.object({
13836
- message: z24.string().optional(),
13837
- cause: z24.unknown().optional()
14176
+ var causeChainNodeSchema = z25.object({
14177
+ message: z25.string().optional(),
14178
+ cause: z25.unknown().optional()
13838
14179
  });
13839
14180
  function extractBlockReason(cause) {
13840
14181
  let current = cause;
@@ -13934,7 +14275,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13934
14275
  retryable: false
13935
14276
  });
13936
14277
  }
13937
- const usage4 = {
14278
+ const usage5 = {
13938
14279
  model: ctx.model.id,
13939
14280
  provider: "google-image",
13940
14281
  modality: "IMAGE",
@@ -13942,19 +14283,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13942
14283
  quantity: images.length,
13943
14284
  imageQuality: "auto"
13944
14285
  };
13945
- if (req.size !== void 0) usage4.imageSize = req.size;
14286
+ if (req.size !== void 0) usage5.imageSize = req.size;
13946
14287
  if (result.usage?.inputTokens !== void 0)
13947
- usage4.inputTokens = result.usage.inputTokens;
14288
+ usage5.inputTokens = result.usage.inputTokens;
13948
14289
  if (result.usage?.outputTokens !== void 0)
13949
- usage4.outputTokens = result.usage.outputTokens;
13950
- return { images, usage: usage4, raw: result };
14290
+ usage5.outputTokens = result.usage.outputTokens;
14291
+ return { images, usage: usage5, raw: result };
13951
14292
  }
13952
14293
  };
13953
14294
  }
13954
14295
  var googleImageAdapter = createGoogleImageAdapter();
13955
14296
 
13956
14297
  // src/adapters/higgsfield.ts
13957
- import { z as z25 } from "zod";
14298
+ import { z as z26 } from "zod";
13958
14299
 
13959
14300
  // src/adapters/higgsfield-motions.ts
13960
14301
  var MOTION_MAP = {
@@ -14173,14 +14514,14 @@ function klingEndpointFields(providerModelId) {
14173
14514
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
14174
14515
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
14175
14516
  }
14176
- var klingCreateSchema = z25.object({ status_url: z25.string() });
14177
- var klingStatusSchema = z25.object({
14178
- status: z25.string().optional(),
14179
- video: z25.object({ url: z25.string().optional() }).optional(),
14517
+ var klingCreateSchema = z26.object({ status_url: z26.string() });
14518
+ var klingStatusSchema = z26.object({
14519
+ status: z26.string().optional(),
14520
+ video: z26.object({ url: z26.string().optional() }).optional(),
14180
14521
  error: JsonValueSchema.optional()
14181
14522
  });
14182
- var errorMessageSchema = z25.object({ message: z25.string().optional() });
14183
- var textValueSchema = z25.string();
14523
+ var errorMessageSchema = z26.object({ message: z26.string().optional() });
14524
+ var textValueSchema = z26.string();
14184
14525
  function klingErrorDetail(error) {
14185
14526
  if (error === void 0) return "unknown_error";
14186
14527
  const asText = textValueSchema.safeParse(error);
@@ -14336,8 +14677,8 @@ async function generateKlingVideo(req, ctx) {
14336
14677
  }
14337
14678
  };
14338
14679
  }
14339
- var dopMotionOptionsSchema = z25.object({
14340
- modelkit: z25.object({ motion: z25.string().optional() }).optional()
14680
+ var dopMotionOptionsSchema = z26.object({
14681
+ modelkit: z26.object({ motion: z26.string().optional() }).optional()
14341
14682
  });
14342
14683
  function dopMotionId(ctx) {
14343
14684
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -14353,7 +14694,7 @@ function dopMotionId(ctx) {
14353
14694
  });
14354
14695
  return id;
14355
14696
  }
14356
- var jsonRecordSchema = z25.record(z25.string(), JsonValueSchema);
14697
+ var jsonRecordSchema = z26.record(z26.string(), JsonValueSchema);
14357
14698
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
14358
14699
  var DOP_NESTED_KEYS = ["video", "result", "results"];
14359
14700
  function dopUrl(body) {
@@ -14381,8 +14722,8 @@ function dopUrl(body) {
14381
14722
  }
14382
14723
  return void 0;
14383
14724
  }
14384
- var dopCreateSchema = z25.object({ id: z25.string() });
14385
- var dopStatusSchema = z25.object({ status: z25.string().optional() });
14725
+ var dopCreateSchema = z26.object({ id: z26.string() });
14726
+ var dopStatusSchema = z26.object({ status: z26.string().optional() });
14386
14727
  async function generateDopVideo(req, ctx) {
14387
14728
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
14388
14729
  if (!firstFrame) {
@@ -14509,7 +14850,7 @@ var higgsfieldAdapter = {
14509
14850
  };
14510
14851
 
14511
14852
  // src/adapters/luma.ts
14512
- import { z as z26 } from "zod";
14853
+ import { z as z27 } from "zod";
14513
14854
 
14514
14855
  // src/adapters/mp4-duration.ts
14515
14856
  function mp4DurationSeconds(bytes) {
@@ -14565,7 +14906,7 @@ function findBox(bytes, from, to, type) {
14565
14906
  }
14566
14907
 
14567
14908
  // src/adapters/luma.ts
14568
- var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
14909
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
14569
14910
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14570
14911
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14571
14912
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14594,7 +14935,7 @@ function lumaModel(ctx) {
14594
14935
  return ctx.model.providerModelId.toLowerCase();
14595
14936
  }
14596
14937
  function lumaBase(ctx) {
14597
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
14938
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14598
14939
  }
14599
14940
  function lumaKey(ctx) {
14600
14941
  const key = ctx.keys.luma;
@@ -14726,17 +15067,17 @@ function lumaReframeResolution(req, ctx) {
14726
15067
  });
14727
15068
  return "720p";
14728
15069
  }
14729
- var lumaGenerationSchema = z26.looseObject({
14730
- id: z26.string(),
14731
- state: z26.string().optional(),
14732
- output: z26.array(
14733
- z26.looseObject({
14734
- type: z26.string().optional(),
14735
- url: z26.string().optional()
15070
+ var lumaGenerationSchema = z27.looseObject({
15071
+ id: z27.string(),
15072
+ state: z27.string().optional(),
15073
+ output: z27.array(
15074
+ z27.looseObject({
15075
+ type: z27.string().optional(),
15076
+ url: z27.string().optional()
14736
15077
  })
14737
15078
  ).optional(),
14738
- failure_reason: z26.string().optional().nullable(),
14739
- failure_code: z26.string().optional().nullable()
15079
+ failure_reason: z27.string().optional().nullable(),
15080
+ failure_code: z27.string().optional().nullable()
14740
15081
  });
14741
15082
  function lumaFailure(ctx, code, reason) {
14742
15083
  const detail = reason ?? code ?? "unknown_error";
@@ -15168,7 +15509,7 @@ var lumaAdapter = {
15168
15509
 
15169
15510
  // src/adapters/openai-image.ts
15170
15511
  import OpenAI from "openai";
15171
- import { z as z27 } from "zod";
15512
+ import { z as z28 } from "zod";
15172
15513
  var MAX_EDIT_REFERENCES = 16;
15173
15514
  function aspectRatioToSize(ratio, tier) {
15174
15515
  const TIER_LONG_EDGE = {
@@ -15251,9 +15592,9 @@ function toProviderError2(cause, ctx) {
15251
15592
  ctx.model.id
15252
15593
  );
15253
15594
  }
15254
- var openaiUsageSchema = z27.object({
15255
- input_tokens: z27.number().optional(),
15256
- output_tokens: z27.number().optional()
15595
+ var openaiUsageSchema = z28.object({
15596
+ input_tokens: z28.number().optional(),
15597
+ output_tokens: z28.number().optional()
15257
15598
  });
15258
15599
  var openaiImageAdapter = {
15259
15600
  id: "openai-image",
@@ -15378,7 +15719,7 @@ var openaiImageAdapter = {
15378
15719
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
15379
15720
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
15380
15721
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
15381
- const usage4 = {
15722
+ const usage5 = {
15382
15723
  model: ctx.model.id,
15383
15724
  provider: "openai-image",
15384
15725
  modality: "IMAGE",
@@ -15386,10 +15727,10 @@ var openaiImageAdapter = {
15386
15727
  quantity: images.length,
15387
15728
  imageQuality: quality
15388
15729
  };
15389
- if (inputTokens !== void 0) usage4.inputTokens = inputTokens;
15390
- if (outputTokens !== void 0) usage4.outputTokens = outputTokens;
15391
- if (req.size !== void 0) usage4.imageSize = req.size;
15392
- return { images, usage: usage4, raw: response };
15730
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15731
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15732
+ if (req.size !== void 0) usage5.imageSize = req.size;
15733
+ return { images, usage: usage5, raw: response };
15393
15734
  }
15394
15735
  };
15395
15736
 
@@ -15645,16 +15986,16 @@ async function generateProdiaImage(req, ctx) {
15645
15986
  new Uint8Array(await res.arrayBuffer()),
15646
15987
  res.headers.get("content-type")
15647
15988
  );
15648
- const usage4 = {
15989
+ const usage5 = {
15649
15990
  model: ctx.model.id,
15650
15991
  provider: "prodia",
15651
15992
  modality: "IMAGE",
15652
15993
  unit: "images",
15653
15994
  quantity: 1
15654
15995
  };
15655
- if (req.size !== void 0) usage4.imageSize = req.size;
15656
- if (req.quality !== void 0) usage4.imageQuality = req.quality;
15657
- return { images: [{ bytes, mime }], usage: usage4, raw: void 0 };
15996
+ if (req.size !== void 0) usage5.imageSize = req.size;
15997
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
15998
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15658
15999
  }
15659
16000
  var prodiaAdapter = {
15660
16001
  id: "prodia",
@@ -15665,13 +16006,13 @@ var prodiaAdapter = {
15665
16006
  import Replicate from "replicate";
15666
16007
 
15667
16008
  // src/adapters/replicate-http.ts
15668
- import { z as z28 } from "zod";
15669
- var predictionSchema = z28.object({
15670
- id: z28.string(),
15671
- status: z28.string(),
16009
+ import { z as z29 } from "zod";
16010
+ var predictionSchema = z29.object({
16011
+ id: z29.string(),
16012
+ status: z29.string(),
15672
16013
  output: JsonValueSchema.optional(),
15673
16014
  error: JsonValueSchema.optional(),
15674
- metrics: z28.object({ predict_time: z28.number().optional() }).optional()
16015
+ metrics: z29.object({ predict_time: z29.number().optional() }).optional()
15675
16016
  });
15676
16017
  function createReplicateHttpClient(opts) {
15677
16018
  async function request(path, body, signal) {
@@ -15722,7 +16063,7 @@ function createReplicateHttpClient(opts) {
15722
16063
  }
15723
16064
 
15724
16065
  // src/adapters/replicate.ts
15725
- import { z as z29 } from "zod";
16066
+ import { z as z30 } from "zod";
15726
16067
  var POLL_INTERVAL_MS = 1e3;
15727
16068
  var POLL_TIMEOUT_MS = 15 * 6e4;
15728
16069
  var defaultReplicateDeps = {
@@ -15762,8 +16103,8 @@ function route(providerModelId) {
15762
16103
  if (!providerModelId.includes("/")) return { version: providerModelId };
15763
16104
  return { model: providerModelId };
15764
16105
  }
15765
- var replicateResponseStatusSchema = z29.object({
15766
- response: z29.object({ status: z29.number() }).partial()
16106
+ var replicateResponseStatusSchema = z30.object({
16107
+ response: z30.object({ status: z30.number() }).partial()
15767
16108
  });
15768
16109
  function replicateError(cause, ctx) {
15769
16110
  if (isModelKitError(cause)) return cause;
@@ -15786,7 +16127,7 @@ function isUrlFn(value) {
15786
16127
  function extractOutputUrl(output) {
15787
16128
  const root = Array.isArray(output) ? output[0] : output;
15788
16129
  if (root === void 0) throw noOutput();
15789
- const asString = z29.string().safeParse(root);
16130
+ const asString = z30.string().safeParse(root);
15790
16131
  if (asString.success && asString.data) return asString.data;
15791
16132
  if (root instanceof URL) return root.href;
15792
16133
  if (isObjectOutput(root)) {
@@ -15795,15 +16136,15 @@ function extractOutputUrl(output) {
15795
16136
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15796
16137
  const called = urlValue();
15797
16138
  if (called instanceof URL) return called.href;
15798
- const calledString = z29.string().safeParse(called);
16139
+ const calledString = z30.string().safeParse(called);
15799
16140
  if (calledString.success && calledString.data) return calledString.data;
15800
16141
  } else {
15801
- const direct = z29.string().safeParse(urlValue);
16142
+ const direct = z30.string().safeParse(urlValue);
15802
16143
  if (direct.success && direct.data) return direct.data;
15803
16144
  }
15804
16145
  }
15805
16146
  if ("default" in root) {
15806
- const fallback = z29.string().safeParse(root.default);
16147
+ const fallback = z30.string().safeParse(root.default);
15807
16148
  if (fallback.success && fallback.data) return fallback.data;
15808
16149
  }
15809
16150
  }
@@ -15864,7 +16205,7 @@ async function runPrediction(ctx, input, deps) {
15864
16205
  }
15865
16206
  return void 0;
15866
16207
  }, pollOpts);
15867
- const predictTime = z29.number().safeParse(done.metrics?.predict_time);
16208
+ const predictTime = z30.number().safeParse(done.metrics?.predict_time);
15868
16209
  if (done.output === void 0) throw noOutput();
15869
16210
  return {
15870
16211
  url: extractOutputUrl(done.output),
@@ -16110,9 +16451,9 @@ async function generateReplicateImage(req, ctx, deps) {
16110
16451
  }
16111
16452
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16112
16453
  const file = await download(ctx, url);
16113
- const usage4 = imageUsage3(ctx, req);
16114
- usage4.quantity = predictTime;
16115
- return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage4, raw, outputUrl: url };
16454
+ const usage5 = imageUsage3(ctx, req);
16455
+ usage5.quantity = predictTime;
16456
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
16116
16457
  }
16117
16458
  function klingInput(req) {
16118
16459
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -16217,7 +16558,7 @@ async function generateReplicateVideo(req, ctx, deps) {
16217
16558
  throw replicateError(cause, ctx);
16218
16559
  }
16219
16560
  if (current.status === "succeeded") {
16220
- const predictTime = z29.number().safeParse(current.metrics?.predict_time);
16561
+ const predictTime = z30.number().safeParse(current.metrics?.predict_time);
16221
16562
  if (current.output === void 0) throw noOutput();
16222
16563
  return {
16223
16564
  url: extractOutputUrl(current.output),
@@ -16236,9 +16577,9 @@ async function generateReplicateVideo(req, ctx, deps) {
16236
16577
  return void 0;
16237
16578
  };
16238
16579
  const toResult = (done) => {
16239
- const usage4 = videoUsage5(ctx, req);
16240
- usage4.quantity = done.predictTime;
16241
- return { video: { url: done.url }, usage: usage4, raw: done.raw };
16580
+ const usage5 = videoUsage5(ctx, req);
16581
+ usage5.quantity = done.predictTime;
16582
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
16242
16583
  };
16243
16584
  return {
16244
16585
  jobId,
@@ -16345,21 +16686,21 @@ async function generateReplicateAudio(req, ctx, deps) {
16345
16686
  input = specResult.input;
16346
16687
  }
16347
16688
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16348
- const usage4 = audioUsage(ctx, req);
16689
+ const usage5 = audioUsage(ctx, req);
16349
16690
  if (ctx.model.usage.unit === "seconds") {
16350
16691
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
16351
- usage4.quantity = seconds3;
16352
- usage4.durationSeconds = seconds3;
16692
+ usage5.quantity = seconds3;
16693
+ usage5.durationSeconds = seconds3;
16353
16694
  } else {
16354
- usage4.quantity = predictTime;
16695
+ usage5.quantity = predictTime;
16355
16696
  }
16356
- return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
16697
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
16357
16698
  }
16358
16699
 
16359
16700
  // src/adapters/xai-video.ts
16360
16701
  import { experimental_generateVideo } from "ai";
16361
16702
  import { createXai as createXai2 } from "@ai-sdk/xai";
16362
- import { z as z30 } from "zod";
16703
+ import { z as z31 } from "zod";
16363
16704
  var POLL_INTERVAL_MS2 = 1e4;
16364
16705
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
16365
16706
  var defaultXaiDeps = {
@@ -16372,8 +16713,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
16372
16713
  };
16373
16714
  }
16374
16715
  var xaiVideoAdapter = createXaiVideoAdapter();
16375
- var xaiResponseStatusSchema = z30.object({
16376
- response: z30.object({ status: z30.number() }).partial()
16716
+ var xaiResponseStatusSchema = z31.object({
16717
+ response: z31.object({ status: z31.number() }).partial()
16377
16718
  });
16378
16719
  function xaiError(cause, ctx) {
16379
16720
  const info = describeThrown(cause);
@@ -16381,12 +16722,12 @@ function xaiError(cause, ctx) {
16381
16722
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
16382
16723
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
16383
16724
  }
16384
- var xaiMetaSchema = z30.object({
16725
+ var xaiMetaSchema = z31.object({
16385
16726
  videoUrl: JsonValueSchema.optional(),
16386
16727
  costInUsdTicks: JsonValueSchema.optional(),
16387
16728
  duration: JsonValueSchema.optional()
16388
16729
  });
16389
- var xaiProviderMetadataSchema = z30.object({ xai: xaiMetaSchema });
16730
+ var xaiProviderMetadataSchema = z31.object({ xai: xaiMetaSchema });
16390
16731
  function metaOf(result) {
16391
16732
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
16392
16733
  if (!parsed.success) return {};
@@ -16498,12 +16839,12 @@ async function mapResult(ctx, req, result) {
16498
16839
  if (first) {
16499
16840
  return {
16500
16841
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16501
- usage: usage3(ctx, req, metaOf(result)),
16842
+ usage: usage4(ctx, req, metaOf(result)),
16502
16843
  raw: result.providerMetadata
16503
16844
  };
16504
16845
  }
16505
16846
  const meta = metaOf(result);
16506
- const videoUrl = z30.string().safeParse(meta.videoUrl);
16847
+ const videoUrl = z31.string().safeParse(meta.videoUrl);
16507
16848
  if (videoUrl.success && videoUrl.data) {
16508
16849
  const res = await ctx.fetch(videoUrl.data);
16509
16850
  if (!res.ok) {
@@ -16513,7 +16854,7 @@ async function mapResult(ctx, req, result) {
16513
16854
  const mime = res.headers.get("content-type") ?? "video/mp4";
16514
16855
  return {
16515
16856
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16516
- usage: usage3(ctx, req, meta),
16857
+ usage: usage4(ctx, req, meta),
16517
16858
  raw: result.providerMetadata
16518
16859
  };
16519
16860
  }
@@ -16525,8 +16866,8 @@ async function mapResult(ctx, req, result) {
16525
16866
  retryable: false
16526
16867
  });
16527
16868
  }
16528
- function usage3(ctx, req, meta) {
16529
- const costTicks = z30.number().safeParse(meta.costInUsdTicks);
16869
+ function usage4(ctx, req, meta) {
16870
+ const costTicks = z31.number().safeParse(meta.costInUsdTicks);
16530
16871
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16531
16872
  const event = {
16532
16873
  model: ctx.model.id,
@@ -16566,7 +16907,8 @@ var DEFAULT_ADAPTERS = {
16566
16907
  higgsfield: higgsfieldAdapter,
16567
16908
  "xai-video": xaiVideoAdapter,
16568
16909
  luma: lumaAdapter,
16569
- fish: fishAdapter
16910
+ fish: fishAdapter,
16911
+ elevenlabs: elevenLabsAdapter
16570
16912
  };
16571
16913
 
16572
16914
  // src/catalog/data-only.ts
@@ -16605,15 +16947,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16605
16947
  "transcription",
16606
16948
  "mask"
16607
16949
  ]);
16608
- function fishSpeech(row2) {
16609
- return row2.adapter === "fish" && row2.type === "speech";
16950
+ function directSpeech(row2) {
16951
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
16610
16952
  }
16611
16953
  function dataOnlyCapable(row2) {
16612
16954
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16613
16955
  if (!adapterServesType(adapter, row2.type)) {
16614
16956
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16615
16957
  }
16616
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
16958
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16617
16959
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16618
16960
  }
16619
16961
  switch (row2.adapter) {
@@ -16695,6 +17037,10 @@ function dataOnlyCapable(row2) {
16695
17037
  const reason = fishRowRefusal(row2);
16696
17038
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16697
17039
  }
17040
+ case "elevenlabs": {
17041
+ const reason = elevenLabsRowRefusal(row2);
17042
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17043
+ }
16698
17044
  default: {
16699
17045
  return assertNever(row2.adapter);
16700
17046
  }
@@ -16714,22 +17060,22 @@ var liveState = store[KEY] ??= {
16714
17060
  var liveCatalog = liveState.catalog;
16715
17061
 
16716
17062
  // src/catalog/load.ts
16717
- import { z as z31 } from "zod";
17063
+ import { z as z32 } from "zod";
16718
17064
  function rowCount() {
16719
17065
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16720
17066
  }
16721
17067
  function authHeaders(auth) {
16722
17068
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16723
17069
  }
16724
- var EnvelopeSchema = z31.object({
16725
- rows: z31.array(JsonValueSchema),
16726
- revision: z31.string().optional()
17070
+ var EnvelopeSchema = z32.object({
17071
+ rows: z32.array(JsonValueSchema),
17072
+ revision: z32.string().optional()
16727
17073
  });
16728
17074
  function dropReason(path, message) {
16729
17075
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16730
17076
  }
16731
17077
  function rowId(raw) {
16732
- const parsed = z31.object({ id: z31.string().min(1) }).loose().safeParse(raw);
17078
+ const parsed = z32.object({ id: z32.string().min(1) }).loose().safeParse(raw);
16733
17079
  if (!parsed.success) return "?";
16734
17080
  return parsed.data.id;
16735
17081
  }
@@ -17890,7 +18236,8 @@ var ADAPTER_KEYS = {
17890
18236
  higgsfield: ["higgsfield"],
17891
18237
  "xai-video": ["xai"],
17892
18238
  luma: ["luma"],
17893
- fish: ["fish"]
18239
+ fish: ["fish"],
18240
+ elevenlabs: ["elevenlabs"]
17894
18241
  };
17895
18242
  function hasAll(keys, names) {
17896
18243
  if (!keys) return false;
@@ -17950,6 +18297,7 @@ function keysFromEnv(env, prefix = "") {
17950
18297
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17951
18298
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
17952
18299
  set("fish", pick2("FISH_AUDIO_API_KEY"));
18300
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
17953
18301
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17954
18302
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17955
18303
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17972,7 +18320,7 @@ function keysFromEnv(env, prefix = "") {
17972
18320
 
17973
18321
  // src/text.ts
17974
18322
  import "ai";
17975
- import { z as z32 } from "zod";
18323
+ import { z as z33 } from "zod";
17976
18324
  function mergeTextProviderOptions(catalog, caller) {
17977
18325
  const merged = {};
17978
18326
  const catalogOptions = catalog.providerOptions ?? {};
@@ -18011,17 +18359,17 @@ function passthroughTextModel(model) {
18011
18359
  pricingKind: "token"
18012
18360
  };
18013
18361
  }
18014
- var perplexityCostSchema = z32.object({
18015
- perplexity: z32.object({ cost: z32.object({ totalCost: z32.number().finite().nonnegative() }) })
18362
+ var perplexityCostSchema = z33.object({
18363
+ perplexity: z33.object({ cost: z33.object({ totalCost: z33.number().finite().nonnegative() }) })
18016
18364
  });
18017
18365
  function reportedCostUsd(metadata) {
18018
18366
  const parsed = perplexityCostSchema.safeParse(metadata);
18019
18367
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
18020
18368
  }
18021
- function textUsageEvent(model, provider, usage4, providerMetadata) {
18022
- const inputTokens = usage4.inputTokens ?? 0;
18023
- const outputTokens = usage4.outputTokens ?? 0;
18024
- const total = usage4.totalTokens ?? inputTokens + outputTokens;
18369
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18370
+ const inputTokens = usage5.inputTokens ?? 0;
18371
+ const outputTokens = usage5.outputTokens ?? 0;
18372
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
18025
18373
  const event = {
18026
18374
  model: model.id,
18027
18375
  provider,
@@ -18056,7 +18404,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18056
18404
  return { ...prepared, providerOptions };
18057
18405
  };
18058
18406
  }
18059
- function usage4(results) {
18407
+ function usage5(results) {
18060
18408
  const grouped = /* @__PURE__ */ new Map();
18061
18409
  for (const [index, step] of results.entries()) {
18062
18410
  const target = steps.get(index) ?? initial;
@@ -18080,7 +18428,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18080
18428
  }
18081
18429
  return [...grouped.values()];
18082
18430
  }
18083
- return { wrap, usage: usage4 };
18431
+ return { wrap, usage: usage5 };
18084
18432
  }
18085
18433
 
18086
18434
  // src/client.ts
@@ -18092,7 +18440,7 @@ import {
18092
18440
  streamObject as aiStreamObject2,
18093
18441
  streamText as aiStreamText2
18094
18442
  } from "ai";
18095
- import { z as z33 } from "zod";
18443
+ import { z as z34 } from "zod";
18096
18444
 
18097
18445
  // src/generated-image.ts
18098
18446
  function toGeneratedImage(image) {
@@ -18214,9 +18562,9 @@ function providerJobMethods(kind, deps) {
18214
18562
  if (!methods.result) throw missing3(adapter, ctx.model);
18215
18563
  const result = await methods.result(sub, ctx, webhook);
18216
18564
  const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
18217
- const usage4 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18218
- await deps.emit(usage4);
18219
- return { ...result, usage: usage4 };
18565
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18566
+ await deps.emit(usage5);
18567
+ return { ...result, usage: usage5 };
18220
18568
  },
18221
18569
  async cancel(sub, call = {}) {
18222
18570
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -18456,10 +18804,10 @@ function audioNodeMethods(deps) {
18456
18804
  const startedAt = Date.now();
18457
18805
  const outcome = await adapter.dub(resolved, ctx);
18458
18806
  if (outcome.kind === "audio") {
18459
- const { audio, usage: usage4, raw } = outcome.result;
18807
+ const { audio, usage: usage5, raw } = outcome.result;
18460
18808
  return {
18461
18809
  audio,
18462
- usage: await deps.settle(model, usage4, startedAt),
18810
+ usage: await deps.settle(model, usage5, startedAt),
18463
18811
  ...raw !== void 0 && { raw }
18464
18812
  };
18465
18813
  }
@@ -18497,10 +18845,10 @@ function textAbortOptions(sdk, context) {
18497
18845
  if (abortSignal) return { abortSignal };
18498
18846
  return {};
18499
18847
  }
18500
- var catalogId = z33.string();
18501
- var exactSize = z33.templateLiteral([z33.number(), "x", z33.number()]);
18502
- var sdkRatio = z33.templateLiteral([z33.number(), ":", z33.number()]);
18503
- var sizeTier = z33.enum(["512", "1K", "2K", "4K"]);
18848
+ var catalogId = z34.string();
18849
+ var exactSize = z34.templateLiteral([z34.number(), "x", z34.number()]);
18850
+ var sdkRatio = z34.templateLiteral([z34.number(), ":", z34.number()]);
18851
+ var sizeTier = z34.enum(["512", "1K", "2K", "4K"]);
18504
18852
  function isCatalogId(model) {
18505
18853
  return catalogId.safeParse(model).success;
18506
18854
  }
@@ -18713,7 +19061,7 @@ function createModelKit(config, adapters) {
18713
19061
  const images = result.images.map(
18714
19062
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18715
19063
  );
18716
- const usage4 = timed(
19064
+ const usage5 = timed(
18717
19065
  {
18718
19066
  model: model.modelId,
18719
19067
  provider: model.provider,
@@ -18723,8 +19071,8 @@ function createModelKit(config, adapters) {
18723
19071
  },
18724
19072
  startedAt
18725
19073
  );
18726
- await emit(usage4);
18727
- return { image: images[0], images, usage: usage4, raw: result, warnings };
19074
+ await emit(usage5);
19075
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
18728
19076
  }
18729
19077
  function passthroughVideo(req, call) {
18730
19078
  const {
@@ -18800,7 +19148,7 @@ function createModelKit(config, adapters) {
18800
19148
  let settled;
18801
19149
  let failed = false;
18802
19150
  const done = pending.then(async (result) => {
18803
- const usage4 = timed(
19151
+ const usage5 = timed(
18804
19152
  {
18805
19153
  model: model.modelId,
18806
19154
  provider: model.provider,
@@ -18813,10 +19161,10 @@ function createModelKit(config, adapters) {
18813
19161
  );
18814
19162
  settled = {
18815
19163
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18816
- usage: usage4,
19164
+ usage: usage5,
18817
19165
  raw: result
18818
19166
  };
18819
- await emit(usage4);
19167
+ await emit(usage5);
18820
19168
  return settled;
18821
19169
  });
18822
19170
  done.catch(() => {
@@ -18843,12 +19191,12 @@ function createModelKit(config, adapters) {
18843
19191
  if (settled) return settled;
18844
19192
  const pending = result(opts).then(
18845
19193
  async (out) => {
18846
- const usage4 = timed(
19194
+ const usage5 = timed(
18847
19195
  { ...out.usage, model: model.id, unit: model.usage.unit },
18848
19196
  startedAt
18849
19197
  );
18850
- await emit(usage4);
18851
- return { ...out, usage: usage4 };
19198
+ await emit(usage5);
19199
+ return { ...out, usage: usage5 };
18852
19200
  },
18853
19201
  (cause) => {
18854
19202
  settled = void 0;
@@ -18868,9 +19216,9 @@ function createModelKit(config, adapters) {
18868
19216
  return context(model, signal ? { ...call, signal } : call, warnings);
18869
19217
  },
18870
19218
  async settle(model, event, startedAt) {
18871
- const usage4 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
18872
- await emit(usage4);
18873
- return usage4;
19219
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19220
+ await emit(usage5);
19221
+ return usage5;
18874
19222
  },
18875
19223
  wrapVideoJob
18876
19224
  });
@@ -18906,11 +19254,11 @@ function createModelKit(config, adapters) {
18906
19254
  });
18907
19255
  const startedAt = Date.now();
18908
19256
  const result = await adapter.generateImage(request, ctx);
18909
- const usage4 = timed(
19257
+ const usage5 = timed(
18910
19258
  { ...result.usage, model: model.id, unit: model.usage.unit },
18911
19259
  startedAt
18912
19260
  );
18913
- await emit(usage4);
19261
+ await emit(usage5);
18914
19262
  const images = result.images.map(toGeneratedImage);
18915
19263
  const first = images[0];
18916
19264
  if (!first)
@@ -18919,7 +19267,7 @@ function createModelKit(config, adapters) {
18919
19267
  message: `${model.id} returned no image`,
18920
19268
  model: model.id
18921
19269
  });
18922
- return { ...result, usage: usage4, image: first, images, warnings };
19270
+ return { ...result, usage: usage5, image: first, images, warnings };
18923
19271
  },
18924
19272
  async generateVideo(req, call = {}) {
18925
19273
  mediaRetryOptions(call);
@@ -19018,12 +19366,12 @@ function createModelKit(config, adapters) {
19018
19366
  }
19019
19367
  const startedAt = Date.now();
19020
19368
  const result = await adapter.generateAudio(resolved, ctx);
19021
- const usage4 = timed(
19369
+ const usage5 = timed(
19022
19370
  { ...result.usage, model: model.id, unit: model.usage.unit },
19023
19371
  startedAt
19024
19372
  );
19025
- await emit(usage4);
19026
- return { ...result, usage: usage4 };
19373
+ await emit(usage5);
19374
+ return { ...result, usage: usage5 };
19027
19375
  },
19028
19376
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
19029
19377
  mediaRetryOptions(call);
@@ -19103,8 +19451,8 @@ function createModelKit(config, adapters) {
19103
19451
  options.prepareStep ?? options.experimental_prepareStep
19104
19452
  ),
19105
19453
  onFinish: async (event) => {
19106
- for (const usage4 of steps.usage(event.steps))
19107
- await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
19454
+ for (const usage5 of steps.usage(event.steps))
19455
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
19108
19456
  await callerOnFinish?.(event);
19109
19457
  }
19110
19458
  });
@@ -19222,6 +19570,7 @@ export {
19222
19570
  dataOnlyCapable,
19223
19571
  describe,
19224
19572
  describeThrown,
19573
+ elevenLabsAdapter,
19225
19574
  generateImage as experimental_generateImage,
19226
19575
  falAdapter,
19227
19576
  falWebhookBodySchema,