@shop-os/modelkit 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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" },
@@ -1913,119 +1616,483 @@ var ELEVENLABS_VOICES = [
1913
1616
  id: "Callum",
1914
1617
  name: "Callum",
1915
1618
  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"
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",
1880
+ accent: "british",
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"
1884
+ },
1885
+ {
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",
1896
+ gender: "male",
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 EXPOSURE4 = ["cowork", "space_builder"];
2006
+ var TTS_MAX_CHARS = 1e4;
2007
+ function fishTts(id, label, providerModelId, description) {
2008
+ return {
2009
+ id,
2010
+ aliases: [],
2011
+ label,
2012
+ type: "speech",
2013
+ adapter: "fish",
2014
+ providerModelId,
2015
+ lifecycle: "active",
2016
+ exposure: EXPOSURE4,
2017
+ constraints: {
2018
+ voices: FISH_VOICES,
2019
+ outputFormats: ["mp3", "wav"],
2020
+ supports: [],
2021
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2022
+ },
2023
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2024
+ usage: PER_CALL2,
2025
+ pricingKind: "flat",
2026
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2027
+ capabilities: { customVoices: true }
2028
+ };
2029
+ }
2030
+ var FISH_MODELS = [
2031
+ fishTts(
2032
+ "fish-s2.1-pro",
2033
+ "Fish Audio S2.1 Pro",
2034
+ "s2.1-pro",
2035
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2036
+ ),
2037
+ fishTts(
2038
+ "fish-s2.1-pro-free",
2039
+ "Fish Audio S2.1 Pro Free",
2040
+ "s2.1-pro-free",
2041
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2042
+ ),
2043
+ fishTts(
2044
+ "fish-drama-3",
2045
+ "Fish Audio Drama 3",
2046
+ "drama-3",
2047
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2048
+ ),
2049
+ {
2050
+ id: "fish-voice-clone",
2051
+ aliases: [],
2052
+ label: "Fish Audio Voice Clone",
2053
+ type: "voice-clone",
2054
+ adapter: "fish",
2055
+ providerModelId: "voice-clone",
2056
+ lifecycle: "active",
2057
+ exposure: EXPOSURE4,
2058
+ constraints: {
2059
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2060
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2061
+ supports: []
2062
+ },
2063
+ defaults: {},
2064
+ usage: PER_REQUEST2,
2065
+ pricingKind: "flat",
2066
+ display: {
2067
+ provider: "fishaudio",
2068
+ logo: FISH_LOGO,
2069
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2070
+ },
2071
+ capabilities: {}
2020
2072
  },
2021
2073
  {
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"
2074
+ id: "fish-voice-design-1",
2075
+ aliases: [],
2076
+ label: "Fish Audio Voice Design",
2077
+ type: "voice-design",
2078
+ adapter: "fish",
2079
+ providerModelId: "voice-design-1",
2080
+ lifecycle: "active",
2081
+ exposure: EXPOSURE4,
2082
+ constraints: {
2083
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2084
+ supports: [],
2085
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2086
+ },
2087
+ defaults: {},
2088
+ usage: PER_REQUEST2,
2089
+ pricingKind: "flat",
2090
+ display: {
2091
+ provider: "fishaudio",
2092
+ logo: FISH_LOGO,
2093
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2094
+ },
2095
+ capabilities: {}
2029
2096
  }
2030
2097
  ];
2031
2098
 
@@ -3604,12 +3671,12 @@ var MINIMAX_VOICES = [
3604
3671
  ];
3605
3672
 
3606
3673
  // src/catalog/media-nodes.ts
3607
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3674
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3608
3675
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3609
3676
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3610
3677
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3611
- var PER_CALL2 = { unit: "images" };
3612
- var EXPOSURE4 = ["cowork", "space_builder"];
3678
+ var PER_CALL3 = { unit: "images" };
3679
+ var EXPOSURE5 = ["cowork", "space_builder"];
3613
3680
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3614
3681
  function elevenLabsTts(tts) {
3615
3682
  return {
@@ -3620,7 +3687,7 @@ function elevenLabsTts(tts) {
3620
3687
  adapter: "fal",
3621
3688
  providerModelId: tts.providerModelId,
3622
3689
  lifecycle: "active",
3623
- exposure: EXPOSURE4,
3690
+ exposure: EXPOSURE5,
3624
3691
  constraints: {
3625
3692
  voices: ELEVENLABS_VOICES,
3626
3693
  languages: tts.languages,
@@ -3629,9 +3696,9 @@ function elevenLabsTts(tts) {
3629
3696
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3630
3697
  },
3631
3698
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3632
- usage: PER_CALL2,
3699
+ usage: PER_CALL3,
3633
3700
  pricingKind: "flat",
3634
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3701
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3635
3702
  capabilities: {}
3636
3703
  };
3637
3704
  }
@@ -3645,7 +3712,7 @@ function geminiTts(id, label, description) {
3645
3712
  adapter: "fal",
3646
3713
  providerModelId,
3647
3714
  lifecycle: "active",
3648
- exposure: EXPOSURE4,
3715
+ exposure: EXPOSURE5,
3649
3716
  constraints: {
3650
3717
  voices: GEMINI_TTS_VOICES,
3651
3718
  supports: ["style"],
@@ -3653,7 +3720,7 @@ function geminiTts(id, label, description) {
3653
3720
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3654
3721
  },
3655
3722
  defaults: { voice: "Kore" },
3656
- usage: PER_CALL2,
3723
+ usage: PER_CALL3,
3657
3724
  pricingKind: "flat",
3658
3725
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3659
3726
  capabilities: {}
@@ -3668,7 +3735,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3668
3735
  adapter: "fal",
3669
3736
  providerModelId,
3670
3737
  lifecycle: "active",
3671
- exposure: EXPOSURE4,
3738
+ exposure: EXPOSURE5,
3672
3739
  constraints: {
3673
3740
  requires: ["sourceVideo", "sourceAudio"],
3674
3741
  references: LIPSYNC_AUDIO,
@@ -3676,7 +3743,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3676
3743
  },
3677
3744
  defaults: {},
3678
3745
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3679
- usage: PER_CALL2,
3746
+ usage: PER_CALL3,
3680
3747
  pricingKind: "flat",
3681
3748
  display: { provider: "sync", logo: SYNC_LOGO, description },
3682
3749
  capabilities: { acceptsSourceVideo: true }
@@ -3729,7 +3796,7 @@ var MEDIA_NODE_MODELS = [
3729
3796
  adapter: "fal",
3730
3797
  providerModelId: "fal-ai/minimax/speech-2.8-hd",
3731
3798
  lifecycle: "active",
3732
- exposure: EXPOSURE4,
3799
+ exposure: EXPOSURE5,
3733
3800
  constraints: {
3734
3801
  voices: MINIMAX_VOICES,
3735
3802
  languages: MINIMAX_SPEECH_LANGUAGES,
@@ -3737,7 +3804,7 @@ var MEDIA_NODE_MODELS = [
3737
3804
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3738
3805
  },
3739
3806
  defaults: { voice: "Wise_Woman" },
3740
- usage: PER_CALL2,
3807
+ usage: PER_CALL3,
3741
3808
  pricingKind: "flat",
3742
3809
  display: {
3743
3810
  provider: "minimax",
@@ -3754,7 +3821,7 @@ var MEDIA_NODE_MODELS = [
3754
3821
  adapter: "fal",
3755
3822
  providerModelId: "fal-ai/elevenlabs/voice-changer",
3756
3823
  lifecycle: "active",
3757
- exposure: EXPOSURE4,
3824
+ exposure: EXPOSURE5,
3758
3825
  constraints: {
3759
3826
  requires: ["sourceAudio"],
3760
3827
  // The flat price assumes at most a minute of speech.
@@ -3764,11 +3831,11 @@ var MEDIA_NODE_MODELS = [
3764
3831
  supports: []
3765
3832
  },
3766
3833
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3767
- usage: PER_CALL2,
3834
+ usage: PER_CALL3,
3768
3835
  pricingKind: "flat",
3769
3836
  display: {
3770
3837
  provider: "elevenlabs",
3771
- logo: ELEVENLABS_LOGO,
3838
+ logo: ELEVENLABS_LOGO2,
3772
3839
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3773
3840
  },
3774
3841
  capabilities: {}
@@ -3781,7 +3848,7 @@ var MEDIA_NODE_MODELS = [
3781
3848
  adapter: "fal",
3782
3849
  providerModelId: "fal-ai/elevenlabs/dubbing",
3783
3850
  lifecycle: "active",
3784
- exposure: EXPOSURE4,
3851
+ exposure: EXPOSURE5,
3785
3852
  constraints: {
3786
3853
  requiresOneOf: ["sourceVideo", "sourceAudio"],
3787
3854
  // The flat price covers 60 s of source.
@@ -3791,11 +3858,11 @@ var MEDIA_NODE_MODELS = [
3791
3858
  supports: []
3792
3859
  },
3793
3860
  defaults: {},
3794
- usage: PER_CALL2,
3861
+ usage: PER_CALL3,
3795
3862
  pricingKind: "flat",
3796
3863
  display: {
3797
3864
  provider: "elevenlabs",
3798
- logo: ELEVENLABS_LOGO,
3865
+ logo: ELEVENLABS_LOGO2,
3799
3866
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3800
3867
  },
3801
3868
  capabilities: { acceptsSourceVideo: true }
@@ -3829,7 +3896,7 @@ var MEDIA_NODE_MODELS = [
3829
3896
  adapter: "fal",
3830
3897
  providerModelId: "veed/lipsync/v2",
3831
3898
  lifecycle: "active",
3832
- exposure: EXPOSURE4,
3899
+ exposure: EXPOSURE5,
3833
3900
  constraints: {
3834
3901
  requires: ["sourceVideo", "sourceAudio"],
3835
3902
  references: LIPSYNC_AUDIO,
@@ -3838,7 +3905,7 @@ var MEDIA_NODE_MODELS = [
3838
3905
  supports: []
3839
3906
  },
3840
3907
  defaults: {},
3841
- usage: PER_CALL2,
3908
+ usage: PER_CALL3,
3842
3909
  pricingKind: "flat",
3843
3910
  display: {
3844
3911
  provider: "veed",
@@ -3855,7 +3922,7 @@ var MEDIA_NODE_MODELS = [
3855
3922
  adapter: "fal",
3856
3923
  providerModelId: "minimax/h3-max/lip-sync/image-to-video",
3857
3924
  lifecycle: "active",
3858
- exposure: EXPOSURE4,
3925
+ exposure: EXPOSURE5,
3859
3926
  constraints: {
3860
3927
  requires: ["firstFrame", "sourceAudio"],
3861
3928
  resolutions: ["480p", "768p", "1080p", "2k"],
@@ -3881,7 +3948,7 @@ var MEDIA_NODE_MODELS = [
3881
3948
  adapter: "fal",
3882
3949
  providerModelId: "fal-ai/elevenlabs/speech-to-text/scribe-v2",
3883
3950
  lifecycle: "active",
3884
- exposure: EXPOSURE4,
3951
+ exposure: EXPOSURE5,
3885
3952
  constraints: {
3886
3953
  requires: ["sourceAudio"],
3887
3954
  // The flat price covers 10 minutes of audio.
@@ -3890,17 +3957,18 @@ var MEDIA_NODE_MODELS = [
3890
3957
  supports: []
3891
3958
  },
3892
3959
  defaults: {},
3893
- usage: PER_CALL2,
3960
+ usage: PER_CALL3,
3894
3961
  pricingKind: "flat",
3895
3962
  display: {
3896
3963
  provider: "elevenlabs",
3897
- logo: ELEVENLABS_LOGO,
3964
+ logo: ELEVENLABS_LOGO2,
3898
3965
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
3899
3966
  },
3900
3967
  capabilities: {}
3901
3968
  },
3902
3969
  SAM_3_IMAGE,
3903
- ...FISH_MODELS
3970
+ ...FISH_MODELS,
3971
+ ...ELEVENLABS_DIRECT_MODELS
3904
3972
  ];
3905
3973
 
3906
3974
  // src/catalog/model3d.ts
@@ -4096,7 +4164,7 @@ var MODEL3D_MODELS = [
4096
4164
 
4097
4165
  // src/catalog/other.ts
4098
4166
  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";
4167
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4100
4168
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
4101
4169
  var OTHER_MODELS = [
4102
4170
  {
@@ -4261,7 +4329,7 @@ var OTHER_MODELS = [
4261
4329
  pricingKind: "flat",
4262
4330
  display: {
4263
4331
  provider: "elevenlabs",
4264
- logo: ELEVENLABS_LOGO2,
4332
+ logo: ELEVENLABS_LOGO3,
4265
4333
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
4266
4334
  },
4267
4335
  capabilities: {}
@@ -4313,7 +4381,7 @@ var OTHER_MODELS = [
4313
4381
  pricingKind: "flat",
4314
4382
  display: {
4315
4383
  provider: "elevenlabs",
4316
- logo: ELEVENLABS_LOGO2,
4384
+ logo: ELEVENLABS_LOGO3,
4317
4385
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4318
4386
  },
4319
4387
  capabilities: {}
@@ -5495,7 +5563,7 @@ var VIDEO_FAMILY_MODELS = [
5495
5563
 
5496
5564
  // src/catalog/video-luma.ts
5497
5565
  var VIDEO_USAGE2 = { unit: "seconds" };
5498
- var EXPOSURE5 = ["cowork", "space_builder"];
5566
+ var EXPOSURE6 = ["cowork", "space_builder"];
5499
5567
  var LUMA_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/luma-color.png";
5500
5568
  var RAY_RATIOS = ["9:16", "3:4", "1:1", "4:3", "16:9", "21:9"];
5501
5569
  var RAY_RESOLUTIONS = ["360p", "720p", "1080p"];
@@ -5513,7 +5581,7 @@ var LUMA_VIDEO_MODELS = [
5513
5581
  adapter: "luma",
5514
5582
  providerModelId: "ray-3.2",
5515
5583
  lifecycle: "active",
5516
- exposure: EXPOSURE5,
5584
+ exposure: EXPOSURE6,
5517
5585
  constraints: {
5518
5586
  aspectRatios: ["adaptive", ...RAY_RATIOS],
5519
5587
  resolutions: [...RAY_RESOLUTIONS],
@@ -5545,7 +5613,7 @@ var LUMA_VIDEO_MODELS = [
5545
5613
  adapter: "luma",
5546
5614
  providerModelId: "ray-3.2",
5547
5615
  lifecycle: "active",
5548
- exposure: EXPOSURE5,
5616
+ exposure: EXPOSURE6,
5549
5617
  constraints: {
5550
5618
  resolutions: [...RAY_RESOLUTIONS],
5551
5619
  requires: ["sourceVideo"],
@@ -5578,7 +5646,7 @@ var LUMA_VIDEO_MODELS = [
5578
5646
  adapter: "luma",
5579
5647
  providerModelId: "ray-3.2",
5580
5648
  lifecycle: "active",
5581
- exposure: EXPOSURE5,
5649
+ exposure: EXPOSURE6,
5582
5650
  constraints: {
5583
5651
  aspectRatios: [...RAY_RATIOS],
5584
5652
  resolutions: [...RAY_RESOLUTIONS],
@@ -7536,7 +7604,8 @@ var ADAPTER_IDS = [
7536
7604
  "higgsfield",
7537
7605
  "xai-video",
7538
7606
  "luma",
7539
- "fish"
7607
+ "fish",
7608
+ "elevenlabs"
7540
7609
  ];
7541
7610
  var ModelTypeSchema = z3.enum([
7542
7611
  "text",
@@ -8749,16 +8818,16 @@ async function generateSeedreamImage(req, ctx) {
8749
8818
  } else {
8750
8819
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8751
8820
  }
8752
- const usage4 = {
8821
+ const usage5 = {
8753
8822
  model: modelId,
8754
8823
  provider: "ark",
8755
8824
  modality: "IMAGE",
8756
8825
  unit: "images",
8757
8826
  quantity: 1
8758
8827
  };
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 };
8828
+ if (req.size !== void 0) usage5.imageSize = req.size;
8829
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8830
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8762
8831
  }
8763
8832
  var SeedanceUsageSchema = z7.object({
8764
8833
  total_tokens: z7.number().optional(),
@@ -8799,7 +8868,7 @@ function seedanceErrorMessage(error, status) {
8799
8868
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8800
8869
  return `Seedance task ${status}`;
8801
8870
  }
8802
- function seedanceJob(ctx, key, jobId, usage4) {
8871
+ function seedanceJob(ctx, key, jobId, usage5) {
8803
8872
  const modelId = ctx.model.id;
8804
8873
  const fetchStatus = async () => {
8805
8874
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8849,21 +8918,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
8849
8918
  modelId
8850
8919
  );
8851
8920
  if (polled.duration !== void 0 && polled.duration > 0) {
8852
- usage4.quantity = polled.duration;
8853
- usage4.durationSeconds = polled.duration;
8921
+ usage5.quantity = polled.duration;
8922
+ usage5.durationSeconds = polled.duration;
8854
8923
  }
8855
8924
  const rendered = VideoResolutionSchema.safeParse(
8856
8925
  polled.resolution?.toLowerCase()
8857
8926
  );
8858
- if (rendered.success) usage4.resolution = rendered.data;
8927
+ if (rendered.success) usage5.resolution = rendered.data;
8859
8928
  const tokens = polled.usage;
8860
8929
  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;
8930
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8931
+ usage5.outputTokens = tokens.completion_tokens;
8863
8932
  }
8864
8933
  return {
8865
8934
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8866
- usage: usage4,
8935
+ usage: usage5,
8867
8936
  raw: polled
8868
8937
  };
8869
8938
  }
@@ -8969,8 +9038,8 @@ async function generateSeedanceVideo(req, ctx) {
8969
9038
  );
8970
9039
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8971
9040
  const jobId = submit.id;
8972
- const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8973
- return seedanceJob(ctx, key, jobId, usage4);
9041
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9042
+ return seedanceJob(ctx, key, jobId, usage5);
8974
9043
  }
8975
9044
 
8976
9045
  // src/adapters/fal.ts
@@ -10458,7 +10527,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10458
10527
  return { bytes, mime: mime || "image/png" };
10459
10528
  })
10460
10529
  );
10461
- const usage4 = {
10530
+ const usage5 = {
10462
10531
  model: ctx.model.id,
10463
10532
  provider: "fal",
10464
10533
  modality: "IMAGE",
@@ -10466,9 +10535,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10466
10535
  quantity: images.length
10467
10536
  };
10468
10537
  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 };
10538
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10539
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10540
+ const result = { images, usage: usage5, raw: payload };
10472
10541
  const remote = files.find((f) => !f.url.startsWith("data:"));
10473
10542
  if (remote !== void 0) result.outputUrl = remote.url;
10474
10543
  return result;
@@ -12631,9 +12700,282 @@ function planUsage(ctx, plan4) {
12631
12700
  };
12632
12701
  }
12633
12702
 
12634
- // src/adapters/fish.ts
12703
+ // src/adapters/elevenlabs.ts
12635
12704
  import { z as z21 } from "zod";
12636
- var DEFAULT_BASE_URL = "https://api.fish.audio";
12705
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12706
+ var DEFAULT_FORMAT = "mp3_44100_128";
12707
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12708
+ var ELEVENLABS_IVC = "ivc";
12709
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12710
+ function elevenLabsRowRefusal(row2) {
12711
+ const id = row2.providerModelId;
12712
+ if (row2.type === "speech") {
12713
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12714
+ }
12715
+ if (row2.type === "voice-clone") {
12716
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12717
+ }
12718
+ return `elevenlabs has no ${row2.type} rows`;
12719
+ }
12720
+ function elevenLabsError(ctx, code, message) {
12721
+ return new ModelKitError({
12722
+ code,
12723
+ message,
12724
+ provider: "elevenlabs",
12725
+ model: ctx.model.id,
12726
+ retryable: false
12727
+ });
12728
+ }
12729
+ function checkRow(ctx, type) {
12730
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12731
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12732
+ throw elevenLabsError(
12733
+ ctx,
12734
+ "unsupported_option",
12735
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12736
+ );
12737
+ }
12738
+ }
12739
+ function checkVoiceId(ctx, field, id) {
12740
+ if (!VOICE_ID.test(id))
12741
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12742
+ return id;
12743
+ }
12744
+ function elevenLabsKey(ctx) {
12745
+ const key = ctx.keys.elevenlabs;
12746
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12747
+ return key;
12748
+ }
12749
+ function elevenLabsUrl(ctx, path) {
12750
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12751
+ }
12752
+ var errorDetail = z21.object({
12753
+ detail: z21.object({ status: z21.string(), message: z21.string().optional() })
12754
+ });
12755
+ function errorStatus(body) {
12756
+ const parsed = errorDetail.safeParse(body);
12757
+ return parsed.success ? parsed.data.detail : void 0;
12758
+ }
12759
+ function classifyResponse(ctx, status, body) {
12760
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12761
+ const detail = errorStatus(body);
12762
+ if (detail?.status === "voice_limit_reached") {
12763
+ return new ModelKitError({
12764
+ code: "provider_rejected",
12765
+ message: detail.message ?? "ElevenLabs voice limit reached",
12766
+ provider: "elevenlabs",
12767
+ model: ctx.model.id,
12768
+ status,
12769
+ body,
12770
+ cause: error,
12771
+ retryable: false
12772
+ });
12773
+ }
12774
+ if (detail?.status === "quota_exceeded") {
12775
+ return new ModelKitError({
12776
+ code: "provider_billing",
12777
+ message: error.message,
12778
+ provider: "elevenlabs",
12779
+ model: ctx.model.id,
12780
+ status,
12781
+ body,
12782
+ cause: error,
12783
+ retryable: false
12784
+ });
12785
+ }
12786
+ return error;
12787
+ }
12788
+ async function elevenLabsFetch(ctx, path, init) {
12789
+ throwIfAborted(ctx.signal);
12790
+ const request = {
12791
+ method: init.method,
12792
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12793
+ };
12794
+ if (init.body !== void 0) request.body = init.body;
12795
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12796
+ let res;
12797
+ try {
12798
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12799
+ } catch (cause) {
12800
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12801
+ }
12802
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12803
+ return res;
12804
+ }
12805
+ function usage2(ctx) {
12806
+ return {
12807
+ model: ctx.model.id,
12808
+ provider: "elevenlabs",
12809
+ modality: "AUDIO",
12810
+ unit: ctx.model.usage.unit,
12811
+ quantity: 1
12812
+ };
12813
+ }
12814
+ function audioMime(res) {
12815
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12816
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12817
+ }
12818
+ async function generateSpeech(req, ctx) {
12819
+ checkRow(ctx, "speech");
12820
+ const voice = req.customVoice ?? req.voice;
12821
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12822
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12823
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12824
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12825
+ if (req.language !== void 0) body.language_code = req.language;
12826
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12827
+ const { bytes, mime } = await withRetry(
12828
+ async () => {
12829
+ const res = await elevenLabsFetch(ctx, path, {
12830
+ method: "POST",
12831
+ headers: { "Content-Type": "application/json" },
12832
+ body: JSON.stringify(body)
12833
+ });
12834
+ let audio;
12835
+ try {
12836
+ audio = new Uint8Array(await res.arrayBuffer());
12837
+ } catch (cause) {
12838
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12839
+ }
12840
+ return { bytes: audio, mime: audioMime(res) };
12841
+ },
12842
+ mediaRetryOptions(ctx.call, ctx.signal)
12843
+ );
12844
+ if (bytes.byteLength === 0)
12845
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12846
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12847
+ }
12848
+ var createdVoiceSchema = z21.object({
12849
+ voice_id: z21.string().min(1),
12850
+ requires_verification: z21.boolean().optional().catch(void 0)
12851
+ });
12852
+ function sampleMime(mime) {
12853
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12854
+ }
12855
+ function fileName(index, mime, ref) {
12856
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12857
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
12858
+ const ext = fromMime || fromUrl?.toLowerCase();
12859
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
12860
+ }
12861
+ async function cloneForm(req, ctx) {
12862
+ if (req.samples.length === 0)
12863
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
12864
+ if (req.samples.some((s) => s.designSignature?.trim())) {
12865
+ throw elevenLabsError(
12866
+ ctx,
12867
+ "unsupported_option",
12868
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
12869
+ );
12870
+ }
12871
+ const form = new FormData();
12872
+ form.append("name", req.title.trim());
12873
+ if (req.description?.trim()) form.append("description", req.description.trim());
12874
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
12875
+ for (const [index, sample] of req.samples.entries()) {
12876
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
12877
+ signal: ctx.signal,
12878
+ provider: "elevenlabs",
12879
+ model: ctx.model.id
12880
+ });
12881
+ const type = sampleMime(mime);
12882
+ const audio = new Blob([new Uint8Array(bytes)], { type });
12883
+ form.append("files", audio, fileName(index, type, sample.audio));
12884
+ }
12885
+ return form;
12886
+ }
12887
+ async function onlyRateLimitRetries(fn) {
12888
+ try {
12889
+ return await fn();
12890
+ } catch (cause) {
12891
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
12892
+ throw cause;
12893
+ throw new ModelKitError({
12894
+ code: cause.code,
12895
+ message: cause.message,
12896
+ ...cause.provider !== void 0 && { provider: cause.provider },
12897
+ ...cause.model !== void 0 && { model: cause.model },
12898
+ ...cause.status !== void 0 && { status: cause.status },
12899
+ ...cause.body !== void 0 && { body: cause.body },
12900
+ cause,
12901
+ retryable: false
12902
+ });
12903
+ }
12904
+ }
12905
+ async function createVoice(req, ctx) {
12906
+ checkRow(ctx, "voice-clone");
12907
+ const form = await cloneForm(req, ctx);
12908
+ const res = await withRetry(
12909
+ () => onlyRateLimitRetries(
12910
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
12911
+ ),
12912
+ mediaRetryOptions(ctx.call, ctx.signal)
12913
+ );
12914
+ const raw = await readBody(res);
12915
+ const parsed = createdVoiceSchema.safeParse(raw);
12916
+ if (!parsed.success) {
12917
+ throw new ModelKitError({
12918
+ code: "provider_rejected",
12919
+ message: "ElevenLabs returned no voice id",
12920
+ provider: "elevenlabs",
12921
+ model: ctx.model.id,
12922
+ status: res.status,
12923
+ body: raw,
12924
+ retryable: false
12925
+ });
12926
+ }
12927
+ return {
12928
+ voiceId: parsed.data.voice_id,
12929
+ state: parsed.data.requires_verification === true ? "created" : "trained",
12930
+ usage: usage2(ctx),
12931
+ raw
12932
+ };
12933
+ }
12934
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
12935
+ "voice_not_found",
12936
+ "voice_does_not_exist"
12937
+ ]);
12938
+ function notFound(cause) {
12939
+ if (cause.status === 404) return true;
12940
+ const status = errorStatus(cause.body)?.status;
12941
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
12942
+ }
12943
+ async function deleteVoice(req, ctx) {
12944
+ checkRow(ctx, "voice-clone");
12945
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
12946
+ let attempts = 0;
12947
+ await withRetry(
12948
+ async () => {
12949
+ attempts += 1;
12950
+ try {
12951
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
12952
+ } catch (cause) {
12953
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
12954
+ if (attempts > 1) return;
12955
+ throw new ModelKitError({
12956
+ code: "provider_rejected",
12957
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
12958
+ provider: "elevenlabs",
12959
+ model: ctx.model.id,
12960
+ ...cause.status !== void 0 && { status: cause.status },
12961
+ cause,
12962
+ retryable: false
12963
+ });
12964
+ }
12965
+ },
12966
+ mediaRetryOptions(ctx.call, ctx.signal)
12967
+ );
12968
+ }
12969
+ var elevenLabsAdapter = {
12970
+ id: "elevenlabs",
12971
+ generateSpeech,
12972
+ createVoice,
12973
+ deleteVoice
12974
+ };
12975
+
12976
+ // src/adapters/fish.ts
12977
+ import { z as z22 } from "zod";
12978
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
12637
12979
  var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12638
12980
  "s2.1-pro",
12639
12981
  "s2.1-pro-free",
@@ -12641,7 +12983,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12641
12983
  ]);
12642
12984
  var FISH_VOICE_CLONE = "voice-clone";
12643
12985
  var FISH_VOICE_DESIGN = "voice-design-1";
12644
- var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12986
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
12645
12987
  function fishRowRefusal(row2) {
12646
12988
  const id = row2.providerModelId;
12647
12989
  if (row2.type === "speech") {
@@ -12664,7 +13006,7 @@ function fishError(ctx, code, message) {
12664
13006
  retryable: false
12665
13007
  });
12666
13008
  }
12667
- function checkRow(ctx, type) {
13009
+ function checkRow2(ctx, type) {
12668
13010
  const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12669
13011
  if (ctx.model.type !== type || refusal2 !== void 0) {
12670
13012
  throw fishError(
@@ -12674,8 +13016,8 @@ function checkRow(ctx, type) {
12674
13016
  );
12675
13017
  }
12676
13018
  }
12677
- function checkVoiceId(ctx, field, id) {
12678
- if (!VOICE_ID.test(id))
13019
+ function checkVoiceId2(ctx, field, id) {
13020
+ if (!VOICE_ID2.test(id))
12679
13021
  throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12680
13022
  return id;
12681
13023
  }
@@ -12685,7 +13027,7 @@ function fishKey(ctx) {
12685
13027
  return key;
12686
13028
  }
12687
13029
  function fishUrl(ctx, path) {
12688
- return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
13030
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
12689
13031
  }
12690
13032
  async function fishFetch(ctx, path, init) {
12691
13033
  throwIfAborted(ctx.signal);
@@ -12704,7 +13046,7 @@ async function fishFetch(ctx, path, init) {
12704
13046
  if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12705
13047
  return res;
12706
13048
  }
12707
- function usage2(ctx) {
13049
+ function usage3(ctx) {
12708
13050
  return {
12709
13051
  model: ctx.model.id,
12710
13052
  provider: "fish",
@@ -12713,18 +13055,18 @@ function usage2(ctx) {
12713
13055
  quantity: 1
12714
13056
  };
12715
13057
  }
12716
- function audioMime(res, format) {
13058
+ function audioMime2(res, format) {
12717
13059
  const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12718
13060
  if (header?.startsWith("audio/")) return header;
12719
13061
  return format === "wav" ? "audio/wav" : "audio/mpeg";
12720
13062
  }
12721
- async function generateSpeech(req, ctx) {
12722
- checkRow(ctx, "speech");
13063
+ async function generateSpeech2(req, ctx) {
13064
+ checkRow2(ctx, "speech");
12723
13065
  const format = req.outputFormat ?? "mp3";
12724
13066
  const body = { text: req.text, format };
12725
13067
  const voice = req.customVoice ?? req.voice;
12726
13068
  if (voice !== void 0) {
12727
- body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
13069
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
12728
13070
  }
12729
13071
  if (req.language !== void 0) body.language = req.language;
12730
13072
  const { bytes, mime } = await withRetry(
@@ -12740,19 +13082,19 @@ async function generateSpeech(req, ctx) {
12740
13082
  } catch (cause) {
12741
13083
  throw classifyThrown("fish", cause, ctx.model.id);
12742
13084
  }
12743
- return { bytes: audio, mime: audioMime(res, format) };
13085
+ return { bytes: audio, mime: audioMime2(res, format) };
12744
13086
  },
12745
13087
  mediaRetryOptions(ctx.call, ctx.signal)
12746
13088
  );
12747
13089
  if (bytes.byteLength === 0)
12748
13090
  throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12749
- return { audio: { bytes, mime }, usage: usage2(ctx) };
13091
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
12750
13092
  }
12751
- var createdModelSchema = z21.object({
12752
- _id: z21.string().min(1),
12753
- state: z21.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
13093
+ var createdModelSchema = z22.object({
13094
+ _id: z22.string().min(1),
13095
+ state: z22.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12754
13096
  });
12755
- function fileName(index, mime) {
13097
+ function fileName2(index, mime) {
12756
13098
  const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12757
13099
  return `sample-${index + 1}.${ext}`;
12758
13100
  }
@@ -12764,7 +13106,7 @@ function allOrNone(ctx, field, values) {
12764
13106
  }
12765
13107
  return set;
12766
13108
  }
12767
- async function cloneForm(req, ctx) {
13109
+ async function cloneForm2(req, ctx) {
12768
13110
  if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12769
13111
  const transcripts = allOrNone(
12770
13112
  ctx,
@@ -12790,13 +13132,13 @@ async function cloneForm(req, ctx) {
12790
13132
  model: ctx.model.id
12791
13133
  });
12792
13134
  const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12793
- form.append("voices", audio, fileName(index, mime));
13135
+ form.append("voices", audio, fileName2(index, mime));
12794
13136
  }
12795
13137
  for (const text2 of transcripts) form.append("texts", text2.trim());
12796
13138
  for (const signature of signatures) form.append("voice_design_signatures", signature);
12797
13139
  return form;
12798
13140
  }
12799
- async function onlyRateLimitRetries(fn) {
13141
+ async function onlyRateLimitRetries2(fn) {
12800
13142
  try {
12801
13143
  return await fn();
12802
13144
  } catch (cause) {
@@ -12814,11 +13156,11 @@ async function onlyRateLimitRetries(fn) {
12814
13156
  });
12815
13157
  }
12816
13158
  }
12817
- async function createVoice(req, ctx) {
12818
- checkRow(ctx, "voice-clone");
12819
- const form = await cloneForm(req, ctx);
13159
+ async function createVoice2(req, ctx) {
13160
+ checkRow2(ctx, "voice-clone");
13161
+ const form = await cloneForm2(req, ctx);
12820
13162
  const res = await withRetry(
12821
- () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13163
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12822
13164
  mediaRetryOptions(ctx.call, ctx.signal)
12823
13165
  );
12824
13166
  const raw = await readBody(res);
@@ -12834,23 +13176,23 @@ async function createVoice(req, ctx) {
12834
13176
  retryable: false
12835
13177
  });
12836
13178
  }
12837
- const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
13179
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
12838
13180
  if (parsed.data.state !== void 0) result.state = parsed.data.state;
12839
13181
  return result;
12840
13182
  }
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()
13183
+ var designSchema = z22.object({
13184
+ candidates: z22.array(
13185
+ z22.looseObject({
13186
+ id: z22.string().min(1),
13187
+ index: z22.number().int(),
13188
+ audio_base64: z22.string().min(1),
13189
+ duration_ms: z22.number().nonnegative(),
13190
+ signature: z22.string().min(1).optional()
12849
13191
  })
12850
13192
  ).min(1)
12851
13193
  });
12852
13194
  async function designVoice(req, ctx) {
12853
- checkRow(ctx, "voice-design");
13195
+ checkRow2(ctx, "voice-design");
12854
13196
  const body = { instruction: req.prompt.trim() };
12855
13197
  if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12856
13198
  if (req.language !== void 0) body.language = req.language;
@@ -12878,11 +13220,11 @@ async function designVoice(req, ctx) {
12878
13220
  // rejects a clone whose signature does not verify, so a wrong one fails loudly.
12879
13221
  signature: c.signature ?? c.id
12880
13222
  }));
12881
- return { candidates, usage: usage2(ctx) };
13223
+ return { candidates, usage: usage3(ctx) };
12882
13224
  }
12883
- async function deleteVoice(req, ctx) {
12884
- checkRow(ctx, "voice-clone");
12885
- const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13225
+ async function deleteVoice2(req, ctx) {
13226
+ checkRow2(ctx, "voice-clone");
13227
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
12886
13228
  let attempts = 0;
12887
13229
  await withRetry(
12888
13230
  async () => {
@@ -12908,20 +13250,20 @@ async function deleteVoice(req, ctx) {
12908
13250
  }
12909
13251
  var fishAdapter = {
12910
13252
  id: "fish",
12911
- generateSpeech,
12912
- createVoice,
13253
+ generateSpeech: generateSpeech2,
13254
+ createVoice: createVoice2,
12913
13255
  designVoice,
12914
- deleteVoice
13256
+ deleteVoice: deleteVoice2
12915
13257
  };
12916
13258
 
12917
13259
  // src/adapters/google-genai.ts
12918
- import { z as z23 } from "zod";
13260
+ import { z as z24 } from "zod";
12919
13261
  import {
12920
13262
  GoogleGenAI
12921
13263
  } from "@google/genai";
12922
13264
 
12923
13265
  // src/adapters/google-files.ts
12924
- import { z as z22 } from "zod";
13266
+ import { z as z23 } from "zod";
12925
13267
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12926
13268
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12927
13269
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12931,17 +13273,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12931
13273
  "binary/octet-stream",
12932
13274
  "application/binary"
12933
13275
  ]);
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()
13276
+ var uploadedFileSchema = z23.object({
13277
+ file: z23.object({
13278
+ uri: z23.string().optional(),
13279
+ name: z23.string().optional(),
13280
+ state: z23.string().optional(),
13281
+ mimeType: z23.string().optional()
12940
13282
  }).optional()
12941
13283
  });
12942
- var fileStateSchema = z22.object({
12943
- state: z22.string().optional(),
12944
- error: z22.object({ message: z22.string().optional() }).optional()
13284
+ var fileStateSchema = z23.object({
13285
+ state: z23.string().optional(),
13286
+ error: z23.object({ message: z23.string().optional() }).optional()
12945
13287
  });
12946
13288
  function resolveMime(declared, fallback) {
12947
13289
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -13048,7 +13390,7 @@ async function startAndUpload(bytes, mimeType, opts) {
13048
13390
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
13049
13391
  return ref;
13050
13392
  }
13051
- async function waitForActive(fileName2, opts) {
13393
+ async function waitForActive(fileName3, opts) {
13052
13394
  const pollOptions2 = {
13053
13395
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
13054
13396
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -13061,14 +13403,14 @@ async function waitForActive(fileName2, opts) {
13061
13403
  retryInit.signal = opts.signal;
13062
13404
  }
13063
13405
  await pollUntil(async () => {
13064
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
13406
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
13065
13407
  if (res.ok) {
13066
13408
  const json = fileStateSchema.parse(await res.json());
13067
13409
  if (json.state === "ACTIVE") return true;
13068
13410
  if (json.state === "FAILED") {
13069
13411
  throw classifyHttpError(
13070
13412
  void 0,
13071
- `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
13413
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
13072
13414
  "google-genai",
13073
13415
  opts.model
13074
13416
  );
@@ -13080,9 +13422,9 @@ async function waitForActive(fileName2, opts) {
13080
13422
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
13081
13423
  }, pollOptions2);
13082
13424
  }
13083
- async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
13425
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
13084
13426
  try {
13085
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
13427
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
13086
13428
  method: "DELETE",
13087
13429
  headers: { "x-goog-api-key": apiKey }
13088
13430
  });
@@ -13162,7 +13504,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
13162
13504
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
13163
13505
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
13164
13506
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
13165
- var errorTextSchema = z23.string();
13507
+ var errorTextSchema = z24.string();
13166
13508
  function isGoogleGenaiVideoKnown(providerModelId) {
13167
13509
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
13168
13510
  }
@@ -13357,7 +13699,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13357
13699
  }
13358
13700
  };
13359
13701
  const jobId = operation.name ?? crypto.randomUUID();
13360
- const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13702
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13361
13703
  return {
13362
13704
  jobId,
13363
13705
  async poll() {
@@ -13395,7 +13737,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
13395
13737
  modelId
13396
13738
  );
13397
13739
  }
13398
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
13740
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
13399
13741
  }
13400
13742
  };
13401
13743
  }
@@ -13506,7 +13848,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13506
13848
  return file.fileUri;
13507
13849
  };
13508
13850
  const cleanupUploads = async () => {
13509
- for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
13851
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
13510
13852
  };
13511
13853
  const callCreate = (input) => client2.interactions.create(
13512
13854
  previousId !== void 0 ? {
@@ -13600,7 +13942,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13600
13942
  if (!(extend && !chained)) await cleanupUploads();
13601
13943
  }
13602
13944
  const jobId = interaction.id ?? crypto.randomUUID();
13603
- const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13945
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13604
13946
  const getInteraction = async () => {
13605
13947
  try {
13606
13948
  const getParams = { stream: false };
@@ -13648,7 +13990,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13648
13990
  bytes: Buffer.from(video.data, "base64"),
13649
13991
  mime: video.mime_type ?? "video/mp4"
13650
13992
  },
13651
- usage: usage4,
13993
+ usage: usage5,
13652
13994
  raw: done,
13653
13995
  providerRef
13654
13996
  };
@@ -13656,7 +13998,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13656
13998
  if (video.uri)
13657
13999
  return {
13658
14000
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13659
- usage: usage4,
14001
+ usage: usage5,
13660
14002
  raw: done,
13661
14003
  providerRef
13662
14004
  };
@@ -13826,15 +14168,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13826
14168
  // src/adapters/google-image.ts
13827
14169
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
13828
14170
  import { generateText } from "ai";
13829
- import { z as z24 } from "zod";
14171
+ import { z as z25 } from "zod";
13830
14172
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13831
14173
  var defaultGoogleImageDeps = {
13832
14174
  createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
13833
14175
  runTextGeneration: (opts) => generateText(opts)
13834
14176
  };
13835
- var causeChainNodeSchema = z24.object({
13836
- message: z24.string().optional(),
13837
- cause: z24.unknown().optional()
14177
+ var causeChainNodeSchema = z25.object({
14178
+ message: z25.string().optional(),
14179
+ cause: z25.unknown().optional()
13838
14180
  });
13839
14181
  function extractBlockReason(cause) {
13840
14182
  let current = cause;
@@ -13934,7 +14276,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13934
14276
  retryable: false
13935
14277
  });
13936
14278
  }
13937
- const usage4 = {
14279
+ const usage5 = {
13938
14280
  model: ctx.model.id,
13939
14281
  provider: "google-image",
13940
14282
  modality: "IMAGE",
@@ -13942,19 +14284,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13942
14284
  quantity: images.length,
13943
14285
  imageQuality: "auto"
13944
14286
  };
13945
- if (req.size !== void 0) usage4.imageSize = req.size;
14287
+ if (req.size !== void 0) usage5.imageSize = req.size;
13946
14288
  if (result.usage?.inputTokens !== void 0)
13947
- usage4.inputTokens = result.usage.inputTokens;
14289
+ usage5.inputTokens = result.usage.inputTokens;
13948
14290
  if (result.usage?.outputTokens !== void 0)
13949
- usage4.outputTokens = result.usage.outputTokens;
13950
- return { images, usage: usage4, raw: result };
14291
+ usage5.outputTokens = result.usage.outputTokens;
14292
+ return { images, usage: usage5, raw: result };
13951
14293
  }
13952
14294
  };
13953
14295
  }
13954
14296
  var googleImageAdapter = createGoogleImageAdapter();
13955
14297
 
13956
14298
  // src/adapters/higgsfield.ts
13957
- import { z as z25 } from "zod";
14299
+ import { z as z26 } from "zod";
13958
14300
 
13959
14301
  // src/adapters/higgsfield-motions.ts
13960
14302
  var MOTION_MAP = {
@@ -14173,14 +14515,14 @@ function klingEndpointFields(providerModelId) {
14173
14515
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
14174
14516
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
14175
14517
  }
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(),
14518
+ var klingCreateSchema = z26.object({ status_url: z26.string() });
14519
+ var klingStatusSchema = z26.object({
14520
+ status: z26.string().optional(),
14521
+ video: z26.object({ url: z26.string().optional() }).optional(),
14180
14522
  error: JsonValueSchema.optional()
14181
14523
  });
14182
- var errorMessageSchema = z25.object({ message: z25.string().optional() });
14183
- var textValueSchema = z25.string();
14524
+ var errorMessageSchema = z26.object({ message: z26.string().optional() });
14525
+ var textValueSchema = z26.string();
14184
14526
  function klingErrorDetail(error) {
14185
14527
  if (error === void 0) return "unknown_error";
14186
14528
  const asText = textValueSchema.safeParse(error);
@@ -14336,8 +14678,8 @@ async function generateKlingVideo(req, ctx) {
14336
14678
  }
14337
14679
  };
14338
14680
  }
14339
- var dopMotionOptionsSchema = z25.object({
14340
- modelkit: z25.object({ motion: z25.string().optional() }).optional()
14681
+ var dopMotionOptionsSchema = z26.object({
14682
+ modelkit: z26.object({ motion: z26.string().optional() }).optional()
14341
14683
  });
14342
14684
  function dopMotionId(ctx) {
14343
14685
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -14353,7 +14695,7 @@ function dopMotionId(ctx) {
14353
14695
  });
14354
14696
  return id;
14355
14697
  }
14356
- var jsonRecordSchema = z25.record(z25.string(), JsonValueSchema);
14698
+ var jsonRecordSchema = z26.record(z26.string(), JsonValueSchema);
14357
14699
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
14358
14700
  var DOP_NESTED_KEYS = ["video", "result", "results"];
14359
14701
  function dopUrl(body) {
@@ -14381,8 +14723,8 @@ function dopUrl(body) {
14381
14723
  }
14382
14724
  return void 0;
14383
14725
  }
14384
- var dopCreateSchema = z25.object({ id: z25.string() });
14385
- var dopStatusSchema = z25.object({ status: z25.string().optional() });
14726
+ var dopCreateSchema = z26.object({ id: z26.string() });
14727
+ var dopStatusSchema = z26.object({ status: z26.string().optional() });
14386
14728
  async function generateDopVideo(req, ctx) {
14387
14729
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
14388
14730
  if (!firstFrame) {
@@ -14509,7 +14851,7 @@ var higgsfieldAdapter = {
14509
14851
  };
14510
14852
 
14511
14853
  // src/adapters/luma.ts
14512
- import { z as z26 } from "zod";
14854
+ import { z as z27 } from "zod";
14513
14855
 
14514
14856
  // src/adapters/mp4-duration.ts
14515
14857
  function mp4DurationSeconds(bytes) {
@@ -14565,7 +14907,7 @@ function findBox(bytes, from, to, type) {
14565
14907
  }
14566
14908
 
14567
14909
  // src/adapters/luma.ts
14568
- var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
14910
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
14569
14911
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14570
14912
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14571
14913
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14594,7 +14936,7 @@ function lumaModel(ctx) {
14594
14936
  return ctx.model.providerModelId.toLowerCase();
14595
14937
  }
14596
14938
  function lumaBase(ctx) {
14597
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
14939
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14598
14940
  }
14599
14941
  function lumaKey(ctx) {
14600
14942
  const key = ctx.keys.luma;
@@ -14726,17 +15068,17 @@ function lumaReframeResolution(req, ctx) {
14726
15068
  });
14727
15069
  return "720p";
14728
15070
  }
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()
15071
+ var lumaGenerationSchema = z27.looseObject({
15072
+ id: z27.string(),
15073
+ state: z27.string().optional(),
15074
+ output: z27.array(
15075
+ z27.looseObject({
15076
+ type: z27.string().optional(),
15077
+ url: z27.string().optional()
14736
15078
  })
14737
15079
  ).optional(),
14738
- failure_reason: z26.string().optional().nullable(),
14739
- failure_code: z26.string().optional().nullable()
15080
+ failure_reason: z27.string().optional().nullable(),
15081
+ failure_code: z27.string().optional().nullable()
14740
15082
  });
14741
15083
  function lumaFailure(ctx, code, reason) {
14742
15084
  const detail = reason ?? code ?? "unknown_error";
@@ -15168,7 +15510,7 @@ var lumaAdapter = {
15168
15510
 
15169
15511
  // src/adapters/openai-image.ts
15170
15512
  import OpenAI from "openai";
15171
- import { z as z27 } from "zod";
15513
+ import { z as z28 } from "zod";
15172
15514
  var MAX_EDIT_REFERENCES = 16;
15173
15515
  function aspectRatioToSize(ratio, tier) {
15174
15516
  const TIER_LONG_EDGE = {
@@ -15251,9 +15593,9 @@ function toProviderError2(cause, ctx) {
15251
15593
  ctx.model.id
15252
15594
  );
15253
15595
  }
15254
- var openaiUsageSchema = z27.object({
15255
- input_tokens: z27.number().optional(),
15256
- output_tokens: z27.number().optional()
15596
+ var openaiUsageSchema = z28.object({
15597
+ input_tokens: z28.number().optional(),
15598
+ output_tokens: z28.number().optional()
15257
15599
  });
15258
15600
  var openaiImageAdapter = {
15259
15601
  id: "openai-image",
@@ -15378,7 +15720,7 @@ var openaiImageAdapter = {
15378
15720
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
15379
15721
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
15380
15722
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
15381
- const usage4 = {
15723
+ const usage5 = {
15382
15724
  model: ctx.model.id,
15383
15725
  provider: "openai-image",
15384
15726
  modality: "IMAGE",
@@ -15386,10 +15728,10 @@ var openaiImageAdapter = {
15386
15728
  quantity: images.length,
15387
15729
  imageQuality: quality
15388
15730
  };
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 };
15731
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15732
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15733
+ if (req.size !== void 0) usage5.imageSize = req.size;
15734
+ return { images, usage: usage5, raw: response };
15393
15735
  }
15394
15736
  };
15395
15737
 
@@ -15645,16 +15987,16 @@ async function generateProdiaImage(req, ctx) {
15645
15987
  new Uint8Array(await res.arrayBuffer()),
15646
15988
  res.headers.get("content-type")
15647
15989
  );
15648
- const usage4 = {
15990
+ const usage5 = {
15649
15991
  model: ctx.model.id,
15650
15992
  provider: "prodia",
15651
15993
  modality: "IMAGE",
15652
15994
  unit: "images",
15653
15995
  quantity: 1
15654
15996
  };
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 };
15997
+ if (req.size !== void 0) usage5.imageSize = req.size;
15998
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
15999
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15658
16000
  }
15659
16001
  var prodiaAdapter = {
15660
16002
  id: "prodia",
@@ -15665,13 +16007,13 @@ var prodiaAdapter = {
15665
16007
  import Replicate from "replicate";
15666
16008
 
15667
16009
  // 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(),
16010
+ import { z as z29 } from "zod";
16011
+ var predictionSchema = z29.object({
16012
+ id: z29.string(),
16013
+ status: z29.string(),
15672
16014
  output: JsonValueSchema.optional(),
15673
16015
  error: JsonValueSchema.optional(),
15674
- metrics: z28.object({ predict_time: z28.number().optional() }).optional()
16016
+ metrics: z29.object({ predict_time: z29.number().optional() }).optional()
15675
16017
  });
15676
16018
  function createReplicateHttpClient(opts) {
15677
16019
  async function request(path, body, signal) {
@@ -15722,7 +16064,7 @@ function createReplicateHttpClient(opts) {
15722
16064
  }
15723
16065
 
15724
16066
  // src/adapters/replicate.ts
15725
- import { z as z29 } from "zod";
16067
+ import { z as z30 } from "zod";
15726
16068
  var POLL_INTERVAL_MS = 1e3;
15727
16069
  var POLL_TIMEOUT_MS = 15 * 6e4;
15728
16070
  var defaultReplicateDeps = {
@@ -15762,8 +16104,8 @@ function route(providerModelId) {
15762
16104
  if (!providerModelId.includes("/")) return { version: providerModelId };
15763
16105
  return { model: providerModelId };
15764
16106
  }
15765
- var replicateResponseStatusSchema = z29.object({
15766
- response: z29.object({ status: z29.number() }).partial()
16107
+ var replicateResponseStatusSchema = z30.object({
16108
+ response: z30.object({ status: z30.number() }).partial()
15767
16109
  });
15768
16110
  function replicateError(cause, ctx) {
15769
16111
  if (isModelKitError(cause)) return cause;
@@ -15786,7 +16128,7 @@ function isUrlFn(value) {
15786
16128
  function extractOutputUrl(output) {
15787
16129
  const root = Array.isArray(output) ? output[0] : output;
15788
16130
  if (root === void 0) throw noOutput();
15789
- const asString = z29.string().safeParse(root);
16131
+ const asString = z30.string().safeParse(root);
15790
16132
  if (asString.success && asString.data) return asString.data;
15791
16133
  if (root instanceof URL) return root.href;
15792
16134
  if (isObjectOutput(root)) {
@@ -15795,15 +16137,15 @@ function extractOutputUrl(output) {
15795
16137
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15796
16138
  const called = urlValue();
15797
16139
  if (called instanceof URL) return called.href;
15798
- const calledString = z29.string().safeParse(called);
16140
+ const calledString = z30.string().safeParse(called);
15799
16141
  if (calledString.success && calledString.data) return calledString.data;
15800
16142
  } else {
15801
- const direct = z29.string().safeParse(urlValue);
16143
+ const direct = z30.string().safeParse(urlValue);
15802
16144
  if (direct.success && direct.data) return direct.data;
15803
16145
  }
15804
16146
  }
15805
16147
  if ("default" in root) {
15806
- const fallback = z29.string().safeParse(root.default);
16148
+ const fallback = z30.string().safeParse(root.default);
15807
16149
  if (fallback.success && fallback.data) return fallback.data;
15808
16150
  }
15809
16151
  }
@@ -15864,7 +16206,7 @@ async function runPrediction(ctx, input, deps) {
15864
16206
  }
15865
16207
  return void 0;
15866
16208
  }, pollOpts);
15867
- const predictTime = z29.number().safeParse(done.metrics?.predict_time);
16209
+ const predictTime = z30.number().safeParse(done.metrics?.predict_time);
15868
16210
  if (done.output === void 0) throw noOutput();
15869
16211
  return {
15870
16212
  url: extractOutputUrl(done.output),
@@ -16110,9 +16452,9 @@ async function generateReplicateImage(req, ctx, deps) {
16110
16452
  }
16111
16453
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16112
16454
  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 };
16455
+ const usage5 = imageUsage3(ctx, req);
16456
+ usage5.quantity = predictTime;
16457
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
16116
16458
  }
16117
16459
  function klingInput(req) {
16118
16460
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -16217,7 +16559,7 @@ async function generateReplicateVideo(req, ctx, deps) {
16217
16559
  throw replicateError(cause, ctx);
16218
16560
  }
16219
16561
  if (current.status === "succeeded") {
16220
- const predictTime = z29.number().safeParse(current.metrics?.predict_time);
16562
+ const predictTime = z30.number().safeParse(current.metrics?.predict_time);
16221
16563
  if (current.output === void 0) throw noOutput();
16222
16564
  return {
16223
16565
  url: extractOutputUrl(current.output),
@@ -16236,9 +16578,9 @@ async function generateReplicateVideo(req, ctx, deps) {
16236
16578
  return void 0;
16237
16579
  };
16238
16580
  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 };
16581
+ const usage5 = videoUsage5(ctx, req);
16582
+ usage5.quantity = done.predictTime;
16583
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
16242
16584
  };
16243
16585
  return {
16244
16586
  jobId,
@@ -16345,21 +16687,21 @@ async function generateReplicateAudio(req, ctx, deps) {
16345
16687
  input = specResult.input;
16346
16688
  }
16347
16689
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
16348
- const usage4 = audioUsage(ctx, req);
16690
+ const usage5 = audioUsage(ctx, req);
16349
16691
  if (ctx.model.usage.unit === "seconds") {
16350
16692
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
16351
- usage4.quantity = seconds3;
16352
- usage4.durationSeconds = seconds3;
16693
+ usage5.quantity = seconds3;
16694
+ usage5.durationSeconds = seconds3;
16353
16695
  } else {
16354
- usage4.quantity = predictTime;
16696
+ usage5.quantity = predictTime;
16355
16697
  }
16356
- return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
16698
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
16357
16699
  }
16358
16700
 
16359
16701
  // src/adapters/xai-video.ts
16360
16702
  import { experimental_generateVideo } from "ai";
16361
16703
  import { createXai as createXai2 } from "@ai-sdk/xai";
16362
- import { z as z30 } from "zod";
16704
+ import { z as z31 } from "zod";
16363
16705
  var POLL_INTERVAL_MS2 = 1e4;
16364
16706
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
16365
16707
  var defaultXaiDeps = {
@@ -16372,8 +16714,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
16372
16714
  };
16373
16715
  }
16374
16716
  var xaiVideoAdapter = createXaiVideoAdapter();
16375
- var xaiResponseStatusSchema = z30.object({
16376
- response: z30.object({ status: z30.number() }).partial()
16717
+ var xaiResponseStatusSchema = z31.object({
16718
+ response: z31.object({ status: z31.number() }).partial()
16377
16719
  });
16378
16720
  function xaiError(cause, ctx) {
16379
16721
  const info = describeThrown(cause);
@@ -16381,12 +16723,12 @@ function xaiError(cause, ctx) {
16381
16723
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
16382
16724
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
16383
16725
  }
16384
- var xaiMetaSchema = z30.object({
16726
+ var xaiMetaSchema = z31.object({
16385
16727
  videoUrl: JsonValueSchema.optional(),
16386
16728
  costInUsdTicks: JsonValueSchema.optional(),
16387
16729
  duration: JsonValueSchema.optional()
16388
16730
  });
16389
- var xaiProviderMetadataSchema = z30.object({ xai: xaiMetaSchema });
16731
+ var xaiProviderMetadataSchema = z31.object({ xai: xaiMetaSchema });
16390
16732
  function metaOf(result) {
16391
16733
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
16392
16734
  if (!parsed.success) return {};
@@ -16498,12 +16840,12 @@ async function mapResult(ctx, req, result) {
16498
16840
  if (first) {
16499
16841
  return {
16500
16842
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16501
- usage: usage3(ctx, req, metaOf(result)),
16843
+ usage: usage4(ctx, req, metaOf(result)),
16502
16844
  raw: result.providerMetadata
16503
16845
  };
16504
16846
  }
16505
16847
  const meta = metaOf(result);
16506
- const videoUrl = z30.string().safeParse(meta.videoUrl);
16848
+ const videoUrl = z31.string().safeParse(meta.videoUrl);
16507
16849
  if (videoUrl.success && videoUrl.data) {
16508
16850
  const res = await ctx.fetch(videoUrl.data);
16509
16851
  if (!res.ok) {
@@ -16513,7 +16855,7 @@ async function mapResult(ctx, req, result) {
16513
16855
  const mime = res.headers.get("content-type") ?? "video/mp4";
16514
16856
  return {
16515
16857
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16516
- usage: usage3(ctx, req, meta),
16858
+ usage: usage4(ctx, req, meta),
16517
16859
  raw: result.providerMetadata
16518
16860
  };
16519
16861
  }
@@ -16525,8 +16867,8 @@ async function mapResult(ctx, req, result) {
16525
16867
  retryable: false
16526
16868
  });
16527
16869
  }
16528
- function usage3(ctx, req, meta) {
16529
- const costTicks = z30.number().safeParse(meta.costInUsdTicks);
16870
+ function usage4(ctx, req, meta) {
16871
+ const costTicks = z31.number().safeParse(meta.costInUsdTicks);
16530
16872
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16531
16873
  const event = {
16532
16874
  model: ctx.model.id,
@@ -16566,7 +16908,8 @@ var DEFAULT_ADAPTERS = {
16566
16908
  higgsfield: higgsfieldAdapter,
16567
16909
  "xai-video": xaiVideoAdapter,
16568
16910
  luma: lumaAdapter,
16569
- fish: fishAdapter
16911
+ fish: fishAdapter,
16912
+ elevenlabs: elevenLabsAdapter
16570
16913
  };
16571
16914
 
16572
16915
  // src/catalog/data-only.ts
@@ -16605,15 +16948,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16605
16948
  "transcription",
16606
16949
  "mask"
16607
16950
  ]);
16608
- function fishSpeech(row2) {
16609
- return row2.adapter === "fish" && row2.type === "speech";
16951
+ function directSpeech(row2) {
16952
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
16610
16953
  }
16611
16954
  function dataOnlyCapable(row2) {
16612
16955
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16613
16956
  if (!adapterServesType(adapter, row2.type)) {
16614
16957
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16615
16958
  }
16616
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
16959
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16617
16960
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16618
16961
  }
16619
16962
  switch (row2.adapter) {
@@ -16695,6 +17038,10 @@ function dataOnlyCapable(row2) {
16695
17038
  const reason = fishRowRefusal(row2);
16696
17039
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16697
17040
  }
17041
+ case "elevenlabs": {
17042
+ const reason = elevenLabsRowRefusal(row2);
17043
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17044
+ }
16698
17045
  default: {
16699
17046
  return assertNever(row2.adapter);
16700
17047
  }
@@ -16714,22 +17061,22 @@ var liveState = store[KEY] ??= {
16714
17061
  var liveCatalog = liveState.catalog;
16715
17062
 
16716
17063
  // src/catalog/load.ts
16717
- import { z as z31 } from "zod";
17064
+ import { z as z32 } from "zod";
16718
17065
  function rowCount() {
16719
17066
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16720
17067
  }
16721
17068
  function authHeaders(auth) {
16722
17069
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16723
17070
  }
16724
- var EnvelopeSchema = z31.object({
16725
- rows: z31.array(JsonValueSchema),
16726
- revision: z31.string().optional()
17071
+ var EnvelopeSchema = z32.object({
17072
+ rows: z32.array(JsonValueSchema),
17073
+ revision: z32.string().optional()
16727
17074
  });
16728
17075
  function dropReason(path, message) {
16729
17076
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16730
17077
  }
16731
17078
  function rowId(raw) {
16732
- const parsed = z31.object({ id: z31.string().min(1) }).loose().safeParse(raw);
17079
+ const parsed = z32.object({ id: z32.string().min(1) }).loose().safeParse(raw);
16733
17080
  if (!parsed.success) return "?";
16734
17081
  return parsed.data.id;
16735
17082
  }
@@ -17890,7 +18237,8 @@ var ADAPTER_KEYS = {
17890
18237
  higgsfield: ["higgsfield"],
17891
18238
  "xai-video": ["xai"],
17892
18239
  luma: ["luma"],
17893
- fish: ["fish"]
18240
+ fish: ["fish"],
18241
+ elevenlabs: ["elevenlabs"]
17894
18242
  };
17895
18243
  function hasAll(keys, names) {
17896
18244
  if (!keys) return false;
@@ -17950,6 +18298,7 @@ function keysFromEnv(env, prefix = "") {
17950
18298
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17951
18299
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
17952
18300
  set("fish", pick2("FISH_AUDIO_API_KEY"));
18301
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
17953
18302
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17954
18303
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17955
18304
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17972,7 +18321,7 @@ function keysFromEnv(env, prefix = "") {
17972
18321
 
17973
18322
  // src/text.ts
17974
18323
  import "ai";
17975
- import { z as z32 } from "zod";
18324
+ import { z as z33 } from "zod";
17976
18325
  function mergeTextProviderOptions(catalog, caller) {
17977
18326
  const merged = {};
17978
18327
  const catalogOptions = catalog.providerOptions ?? {};
@@ -18011,17 +18360,17 @@ function passthroughTextModel(model) {
18011
18360
  pricingKind: "token"
18012
18361
  };
18013
18362
  }
18014
- var perplexityCostSchema = z32.object({
18015
- perplexity: z32.object({ cost: z32.object({ totalCost: z32.number().finite().nonnegative() }) })
18363
+ var perplexityCostSchema = z33.object({
18364
+ perplexity: z33.object({ cost: z33.object({ totalCost: z33.number().finite().nonnegative() }) })
18016
18365
  });
18017
18366
  function reportedCostUsd(metadata) {
18018
18367
  const parsed = perplexityCostSchema.safeParse(metadata);
18019
18368
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
18020
18369
  }
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;
18370
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18371
+ const inputTokens = usage5.inputTokens ?? 0;
18372
+ const outputTokens = usage5.outputTokens ?? 0;
18373
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
18025
18374
  const event = {
18026
18375
  model: model.id,
18027
18376
  provider,
@@ -18056,7 +18405,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18056
18405
  return { ...prepared, providerOptions };
18057
18406
  };
18058
18407
  }
18059
- function usage4(results) {
18408
+ function usage5(results) {
18060
18409
  const grouped = /* @__PURE__ */ new Map();
18061
18410
  for (const [index, step] of results.entries()) {
18062
18411
  const target = steps.get(index) ?? initial;
@@ -18080,7 +18429,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
18080
18429
  }
18081
18430
  return [...grouped.values()];
18082
18431
  }
18083
- return { wrap, usage: usage4 };
18432
+ return { wrap, usage: usage5 };
18084
18433
  }
18085
18434
 
18086
18435
  // src/client.ts
@@ -18092,7 +18441,7 @@ import {
18092
18441
  streamObject as aiStreamObject2,
18093
18442
  streamText as aiStreamText2
18094
18443
  } from "ai";
18095
- import { z as z33 } from "zod";
18444
+ import { z as z34 } from "zod";
18096
18445
 
18097
18446
  // src/generated-image.ts
18098
18447
  function toGeneratedImage(image) {
@@ -18214,9 +18563,9 @@ function providerJobMethods(kind, deps) {
18214
18563
  if (!methods.result) throw missing3(adapter, ctx.model);
18215
18564
  const result = await methods.result(sub, ctx, webhook);
18216
18565
  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 };
18566
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18567
+ await deps.emit(usage5);
18568
+ return { ...result, usage: usage5 };
18220
18569
  },
18221
18570
  async cancel(sub, call = {}) {
18222
18571
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -18456,10 +18805,10 @@ function audioNodeMethods(deps) {
18456
18805
  const startedAt = Date.now();
18457
18806
  const outcome = await adapter.dub(resolved, ctx);
18458
18807
  if (outcome.kind === "audio") {
18459
- const { audio, usage: usage4, raw } = outcome.result;
18808
+ const { audio, usage: usage5, raw } = outcome.result;
18460
18809
  return {
18461
18810
  audio,
18462
- usage: await deps.settle(model, usage4, startedAt),
18811
+ usage: await deps.settle(model, usage5, startedAt),
18463
18812
  ...raw !== void 0 && { raw }
18464
18813
  };
18465
18814
  }
@@ -18497,10 +18846,10 @@ function textAbortOptions(sdk, context) {
18497
18846
  if (abortSignal) return { abortSignal };
18498
18847
  return {};
18499
18848
  }
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"]);
18849
+ var catalogId = z34.string();
18850
+ var exactSize = z34.templateLiteral([z34.number(), "x", z34.number()]);
18851
+ var sdkRatio = z34.templateLiteral([z34.number(), ":", z34.number()]);
18852
+ var sizeTier = z34.enum(["512", "1K", "2K", "4K"]);
18504
18853
  function isCatalogId(model) {
18505
18854
  return catalogId.safeParse(model).success;
18506
18855
  }
@@ -18713,7 +19062,7 @@ function createModelKit(config, adapters) {
18713
19062
  const images = result.images.map(
18714
19063
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18715
19064
  );
18716
- const usage4 = timed(
19065
+ const usage5 = timed(
18717
19066
  {
18718
19067
  model: model.modelId,
18719
19068
  provider: model.provider,
@@ -18723,8 +19072,8 @@ function createModelKit(config, adapters) {
18723
19072
  },
18724
19073
  startedAt
18725
19074
  );
18726
- await emit(usage4);
18727
- return { image: images[0], images, usage: usage4, raw: result, warnings };
19075
+ await emit(usage5);
19076
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
18728
19077
  }
18729
19078
  function passthroughVideo(req, call) {
18730
19079
  const {
@@ -18800,7 +19149,7 @@ function createModelKit(config, adapters) {
18800
19149
  let settled;
18801
19150
  let failed = false;
18802
19151
  const done = pending.then(async (result) => {
18803
- const usage4 = timed(
19152
+ const usage5 = timed(
18804
19153
  {
18805
19154
  model: model.modelId,
18806
19155
  provider: model.provider,
@@ -18813,10 +19162,10 @@ function createModelKit(config, adapters) {
18813
19162
  );
18814
19163
  settled = {
18815
19164
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18816
- usage: usage4,
19165
+ usage: usage5,
18817
19166
  raw: result
18818
19167
  };
18819
- await emit(usage4);
19168
+ await emit(usage5);
18820
19169
  return settled;
18821
19170
  });
18822
19171
  done.catch(() => {
@@ -18843,12 +19192,12 @@ function createModelKit(config, adapters) {
18843
19192
  if (settled) return settled;
18844
19193
  const pending = result(opts).then(
18845
19194
  async (out) => {
18846
- const usage4 = timed(
19195
+ const usage5 = timed(
18847
19196
  { ...out.usage, model: model.id, unit: model.usage.unit },
18848
19197
  startedAt
18849
19198
  );
18850
- await emit(usage4);
18851
- return { ...out, usage: usage4 };
19199
+ await emit(usage5);
19200
+ return { ...out, usage: usage5 };
18852
19201
  },
18853
19202
  (cause) => {
18854
19203
  settled = void 0;
@@ -18868,9 +19217,9 @@ function createModelKit(config, adapters) {
18868
19217
  return context(model, signal ? { ...call, signal } : call, warnings);
18869
19218
  },
18870
19219
  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;
19220
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19221
+ await emit(usage5);
19222
+ return usage5;
18874
19223
  },
18875
19224
  wrapVideoJob
18876
19225
  });
@@ -18906,11 +19255,11 @@ function createModelKit(config, adapters) {
18906
19255
  });
18907
19256
  const startedAt = Date.now();
18908
19257
  const result = await adapter.generateImage(request, ctx);
18909
- const usage4 = timed(
19258
+ const usage5 = timed(
18910
19259
  { ...result.usage, model: model.id, unit: model.usage.unit },
18911
19260
  startedAt
18912
19261
  );
18913
- await emit(usage4);
19262
+ await emit(usage5);
18914
19263
  const images = result.images.map(toGeneratedImage);
18915
19264
  const first = images[0];
18916
19265
  if (!first)
@@ -18919,7 +19268,7 @@ function createModelKit(config, adapters) {
18919
19268
  message: `${model.id} returned no image`,
18920
19269
  model: model.id
18921
19270
  });
18922
- return { ...result, usage: usage4, image: first, images, warnings };
19271
+ return { ...result, usage: usage5, image: first, images, warnings };
18923
19272
  },
18924
19273
  async generateVideo(req, call = {}) {
18925
19274
  mediaRetryOptions(call);
@@ -19018,12 +19367,12 @@ function createModelKit(config, adapters) {
19018
19367
  }
19019
19368
  const startedAt = Date.now();
19020
19369
  const result = await adapter.generateAudio(resolved, ctx);
19021
- const usage4 = timed(
19370
+ const usage5 = timed(
19022
19371
  { ...result.usage, model: model.id, unit: model.usage.unit },
19023
19372
  startedAt
19024
19373
  );
19025
- await emit(usage4);
19026
- return { ...result, usage: usage4 };
19374
+ await emit(usage5);
19375
+ return { ...result, usage: usage5 };
19027
19376
  },
19028
19377
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
19029
19378
  mediaRetryOptions(call);
@@ -19103,8 +19452,8 @@ function createModelKit(config, adapters) {
19103
19452
  options.prepareStep ?? options.experimental_prepareStep
19104
19453
  ),
19105
19454
  onFinish: async (event) => {
19106
- for (const usage4 of steps.usage(event.steps))
19107
- await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
19455
+ for (const usage5 of steps.usage(event.steps))
19456
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
19108
19457
  await callerOnFinish?.(event);
19109
19458
  }
19110
19459
  });
@@ -19222,6 +19571,7 @@ export {
19222
19571
  dataOnlyCapable,
19223
19572
  describe,
19224
19573
  describeThrown,
19574
+ elevenLabsAdapter,
19225
19575
  generateImage as experimental_generateImage,
19226
19576
  falAdapter,
19227
19577
  falWebhookBodySchema,