@shop-os/modelkit 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1230,6 +1230,303 @@ 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
+
1233
1530
  // src/catalog/languages-audio.ts
1234
1531
  var ELEVENLABS_V4_LANGUAGES = [
1235
1532
  { code: "af", name: "Afrikaans" },
@@ -3311,7 +3608,7 @@ var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.
3311
3608
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3312
3609
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3313
3610
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3314
- var PER_CALL = { unit: "images" };
3611
+ var PER_CALL2 = { unit: "images" };
3315
3612
  var EXPOSURE4 = ["cowork", "space_builder"];
3316
3613
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3317
3614
  function elevenLabsTts(tts) {
@@ -3332,7 +3629,7 @@ function elevenLabsTts(tts) {
3332
3629
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3333
3630
  },
3334
3631
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3335
- usage: PER_CALL,
3632
+ usage: PER_CALL2,
3336
3633
  pricingKind: "flat",
3337
3634
  display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3338
3635
  capabilities: {}
@@ -3356,7 +3653,7 @@ function geminiTts(id, label, description) {
3356
3653
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3357
3654
  },
3358
3655
  defaults: { voice: "Kore" },
3359
- usage: PER_CALL,
3656
+ usage: PER_CALL2,
3360
3657
  pricingKind: "flat",
3361
3658
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3362
3659
  capabilities: {}
@@ -3379,7 +3676,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3379
3676
  },
3380
3677
  defaults: {},
3381
3678
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3382
- usage: PER_CALL,
3679
+ usage: PER_CALL2,
3383
3680
  pricingKind: "flat",
3384
3681
  display: { provider: "sync", logo: SYNC_LOGO, description },
3385
3682
  capabilities: { acceptsSourceVideo: true }
@@ -3440,7 +3737,7 @@ var MEDIA_NODE_MODELS = [
3440
3737
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3441
3738
  },
3442
3739
  defaults: { voice: "Wise_Woman" },
3443
- usage: PER_CALL,
3740
+ usage: PER_CALL2,
3444
3741
  pricingKind: "flat",
3445
3742
  display: {
3446
3743
  provider: "minimax",
@@ -3467,7 +3764,7 @@ var MEDIA_NODE_MODELS = [
3467
3764
  supports: []
3468
3765
  },
3469
3766
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3470
- usage: PER_CALL,
3767
+ usage: PER_CALL2,
3471
3768
  pricingKind: "flat",
3472
3769
  display: {
3473
3770
  provider: "elevenlabs",
@@ -3494,7 +3791,7 @@ var MEDIA_NODE_MODELS = [
3494
3791
  supports: []
3495
3792
  },
3496
3793
  defaults: {},
3497
- usage: PER_CALL,
3794
+ usage: PER_CALL2,
3498
3795
  pricingKind: "flat",
3499
3796
  display: {
3500
3797
  provider: "elevenlabs",
@@ -3541,7 +3838,7 @@ var MEDIA_NODE_MODELS = [
3541
3838
  supports: []
3542
3839
  },
3543
3840
  defaults: {},
3544
- usage: PER_CALL,
3841
+ usage: PER_CALL2,
3545
3842
  pricingKind: "flat",
3546
3843
  display: {
3547
3844
  provider: "veed",
@@ -3593,7 +3890,7 @@ var MEDIA_NODE_MODELS = [
3593
3890
  supports: []
3594
3891
  },
3595
3892
  defaults: {},
3596
- usage: PER_CALL,
3893
+ usage: PER_CALL2,
3597
3894
  pricingKind: "flat",
3598
3895
  display: {
3599
3896
  provider: "elevenlabs",
@@ -3602,7 +3899,8 @@ var MEDIA_NODE_MODELS = [
3602
3899
  },
3603
3900
  capabilities: {}
3604
3901
  },
3605
- SAM_3_IMAGE
3902
+ SAM_3_IMAGE,
3903
+ ...FISH_MODELS
3606
3904
  ];
3607
3905
 
3608
3906
  // src/catalog/model3d.ts
@@ -7237,7 +7535,8 @@ var ADAPTER_IDS = [
7237
7535
  "prodia",
7238
7536
  "higgsfield",
7239
7537
  "xai-video",
7240
- "luma"
7538
+ "luma",
7539
+ "fish"
7241
7540
  ];
7242
7541
  var ModelTypeSchema = z3.enum([
7243
7542
  "text",
@@ -7254,6 +7553,8 @@ var ModelTypeSchema = z3.enum([
7254
7553
  "dubbing",
7255
7554
  "lipsync",
7256
7555
  "transcription",
7556
+ "voice-clone",
7557
+ "voice-design",
7257
7558
  "model3d"
7258
7559
  ]);
7259
7560
  var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
@@ -7429,6 +7730,10 @@ var ModelConstraintsSchema = z3.looseObject({
7429
7730
  supports: z3.array(SupportedOptionSchema).optional(),
7430
7731
  ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
7431
7732
  voices: z3.array(VoiceOptionSchema).optional(),
7733
+ voiceDesign: z3.object({
7734
+ maxCandidates: z3.number().int().positive(),
7735
+ previewMaxChars: z3.number().int().positive()
7736
+ }).optional(),
7432
7737
  languages: z3.array(LanguageOptionSchema).optional(),
7433
7738
  outputFormats: z3.array(z3.string().min(1)).min(1).optional(),
7434
7739
  sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
@@ -7527,6 +7832,7 @@ var CatalogDisplaySchema = z3.looseObject({
7527
7832
  });
7528
7833
  var CatalogCapabilitiesSchema = z3.looseObject({
7529
7834
  acceptsSourceVideo: z3.boolean().optional(),
7835
+ customVoices: z3.boolean().optional(),
7530
7836
  videoEdit: z3.boolean().optional(),
7531
7837
  framesExcludeReferences: z3.boolean().optional(),
7532
7838
  sourceVideoExcludesFrames: z3.boolean().optional(),
@@ -8046,7 +8352,7 @@ var errorCodes = z6.object({
8046
8352
  type: z6.string().optional(),
8047
8353
  error: z6.object({ code: z6.string().optional(), type: z6.string().optional() }).optional()
8048
8354
  });
8049
- var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
8355
+ var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
8050
8356
  var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
8051
8357
  function billingCode(body) {
8052
8358
  const parsed = errorCodes.safeParse(body);
@@ -8443,16 +8749,16 @@ async function generateSeedreamImage(req, ctx) {
8443
8749
  } else {
8444
8750
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8445
8751
  }
8446
- const usage3 = {
8752
+ const usage4 = {
8447
8753
  model: modelId,
8448
8754
  provider: "ark",
8449
8755
  modality: "IMAGE",
8450
8756
  unit: "images",
8451
8757
  quantity: 1
8452
8758
  };
8453
- if (req.size !== void 0) usage3.imageSize = req.size;
8454
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
8455
- return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage3, raw: data };
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 };
8456
8762
  }
8457
8763
  var SeedanceUsageSchema = z7.object({
8458
8764
  total_tokens: z7.number().optional(),
@@ -8493,7 +8799,7 @@ function seedanceErrorMessage(error, status) {
8493
8799
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8494
8800
  return `Seedance task ${status}`;
8495
8801
  }
8496
- function seedanceJob(ctx, key, jobId, usage3) {
8802
+ function seedanceJob(ctx, key, jobId, usage4) {
8497
8803
  const modelId = ctx.model.id;
8498
8804
  const fetchStatus = async () => {
8499
8805
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8543,21 +8849,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
8543
8849
  modelId
8544
8850
  );
8545
8851
  if (polled.duration !== void 0 && polled.duration > 0) {
8546
- usage3.quantity = polled.duration;
8547
- usage3.durationSeconds = polled.duration;
8852
+ usage4.quantity = polled.duration;
8853
+ usage4.durationSeconds = polled.duration;
8548
8854
  }
8549
8855
  const rendered = VideoResolutionSchema.safeParse(
8550
8856
  polled.resolution?.toLowerCase()
8551
8857
  );
8552
- if (rendered.success) usage3.resolution = rendered.data;
8858
+ if (rendered.success) usage4.resolution = rendered.data;
8553
8859
  const tokens = polled.usage;
8554
8860
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
8555
- usage3.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8556
- usage3.outputTokens = tokens.completion_tokens;
8861
+ usage4.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8862
+ usage4.outputTokens = tokens.completion_tokens;
8557
8863
  }
8558
8864
  return {
8559
8865
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8560
- usage: usage3,
8866
+ usage: usage4,
8561
8867
  raw: polled
8562
8868
  };
8563
8869
  }
@@ -8663,8 +8969,8 @@ async function generateSeedanceVideo(req, ctx) {
8663
8969
  );
8664
8970
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8665
8971
  const jobId = submit.id;
8666
- const usage3 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8667
- return seedanceJob(ctx, key, jobId, usage3);
8972
+ const usage4 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8973
+ return seedanceJob(ctx, key, jobId, usage4);
8668
8974
  }
8669
8975
 
8670
8976
  // src/adapters/fal.ts
@@ -10152,7 +10458,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10152
10458
  return { bytes, mime: mime || "image/png" };
10153
10459
  })
10154
10460
  );
10155
- const usage3 = {
10461
+ const usage4 = {
10156
10462
  model: ctx.model.id,
10157
10463
  provider: "fal",
10158
10464
  modality: "IMAGE",
@@ -10160,9 +10466,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10160
10466
  quantity: images.length
10161
10467
  };
10162
10468
  const billedSize = plan4.imageSize ?? req.size;
10163
- if (billedSize !== void 0 && ctx.model.type === "image") usage3.imageSize = billedSize;
10164
- if (plan4.imageQuality !== void 0) usage3.imageQuality = plan4.imageQuality;
10165
- const result = { images, usage: usage3, raw: payload };
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 };
10166
10472
  const remote = files.find((f) => !f.url.startsWith("data:"));
10167
10473
  if (remote !== void 0) result.outputUrl = remote.url;
10168
10474
  return result;
@@ -12325,14 +12631,297 @@ function planUsage(ctx, plan4) {
12325
12631
  };
12326
12632
  }
12327
12633
 
12634
+ // src/adapters/fish.ts
12635
+ import { z as z21 } from "zod";
12636
+ var DEFAULT_BASE_URL = "https://api.fish.audio";
12637
+ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12638
+ "s2.1-pro",
12639
+ "s2.1-pro-free",
12640
+ "drama-3"
12641
+ ]);
12642
+ var FISH_VOICE_CLONE = "voice-clone";
12643
+ var FISH_VOICE_DESIGN = "voice-design-1";
12644
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12645
+ function fishRowRefusal(row2) {
12646
+ const id = row2.providerModelId;
12647
+ if (row2.type === "speech") {
12648
+ return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
12649
+ }
12650
+ if (row2.type === "voice-clone") {
12651
+ return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
12652
+ }
12653
+ if (row2.type === "voice-design") {
12654
+ return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
12655
+ }
12656
+ return `fish has no ${row2.type} rows`;
12657
+ }
12658
+ function fishError(ctx, code, message) {
12659
+ return new ModelKitError({
12660
+ code,
12661
+ message,
12662
+ provider: "fish",
12663
+ model: ctx.model.id,
12664
+ retryable: false
12665
+ });
12666
+ }
12667
+ function checkRow(ctx, type) {
12668
+ const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
12669
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12670
+ throw fishError(
12671
+ ctx,
12672
+ "unsupported_option",
12673
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12674
+ );
12675
+ }
12676
+ }
12677
+ function checkVoiceId(ctx, field, id) {
12678
+ if (!VOICE_ID.test(id))
12679
+ throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
12680
+ return id;
12681
+ }
12682
+ function fishKey(ctx) {
12683
+ const key = ctx.keys.fish;
12684
+ if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
12685
+ return key;
12686
+ }
12687
+ function fishUrl(ctx, path) {
12688
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL}${path}`;
12689
+ }
12690
+ async function fishFetch(ctx, path, init) {
12691
+ throwIfAborted(ctx.signal);
12692
+ const request = {
12693
+ method: init.method,
12694
+ headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
12695
+ };
12696
+ if (init.body !== void 0) request.body = init.body;
12697
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12698
+ let res;
12699
+ try {
12700
+ res = await ctx.fetch(fishUrl(ctx, path), request);
12701
+ } catch (cause) {
12702
+ throw classifyThrown("fish", cause, ctx.model.id);
12703
+ }
12704
+ if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
12705
+ return res;
12706
+ }
12707
+ function usage2(ctx) {
12708
+ return {
12709
+ model: ctx.model.id,
12710
+ provider: "fish",
12711
+ modality: "AUDIO",
12712
+ unit: ctx.model.usage.unit,
12713
+ quantity: 1
12714
+ };
12715
+ }
12716
+ function audioMime(res, format) {
12717
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12718
+ if (header?.startsWith("audio/")) return header;
12719
+ return format === "wav" ? "audio/wav" : "audio/mpeg";
12720
+ }
12721
+ async function generateSpeech(req, ctx) {
12722
+ checkRow(ctx, "speech");
12723
+ const format = req.outputFormat ?? "mp3";
12724
+ const body = { text: req.text, format };
12725
+ const voice = req.customVoice ?? req.voice;
12726
+ if (voice !== void 0) {
12727
+ body.reference_id = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12728
+ }
12729
+ if (req.language !== void 0) body.language = req.language;
12730
+ const { bytes, mime } = await withRetry(
12731
+ async () => {
12732
+ const res = await fishFetch(ctx, "/v1/tts", {
12733
+ method: "POST",
12734
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
12735
+ body: JSON.stringify(body)
12736
+ });
12737
+ let audio;
12738
+ try {
12739
+ audio = new Uint8Array(await res.arrayBuffer());
12740
+ } catch (cause) {
12741
+ throw classifyThrown("fish", cause, ctx.model.id);
12742
+ }
12743
+ return { bytes: audio, mime: audioMime(res, format) };
12744
+ },
12745
+ mediaRetryOptions(ctx.call, ctx.signal)
12746
+ );
12747
+ if (bytes.byteLength === 0)
12748
+ throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
12749
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12750
+ }
12751
+ var createdModelSchema = z21.object({
12752
+ _id: z21.string().min(1),
12753
+ state: z21.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
12754
+ });
12755
+ function fileName(index, mime) {
12756
+ const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
12757
+ return `sample-${index + 1}.${ext}`;
12758
+ }
12759
+ function allOrNone(ctx, field, values) {
12760
+ const set = values.filter((v) => v !== void 0 && v.trim() !== "");
12761
+ if (set.length === 0) return [];
12762
+ if (set.length !== values.length) {
12763
+ throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
12764
+ }
12765
+ return set;
12766
+ }
12767
+ async function cloneForm(req, ctx) {
12768
+ if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
12769
+ const transcripts = allOrNone(
12770
+ ctx,
12771
+ "transcript",
12772
+ req.samples.map((s) => s.transcript)
12773
+ );
12774
+ const signatures = allOrNone(
12775
+ ctx,
12776
+ "designSignature",
12777
+ req.samples.map((s) => s.designSignature)
12778
+ );
12779
+ const form = new FormData();
12780
+ form.append("type", "tts");
12781
+ form.append("train_mode", "fast");
12782
+ form.append("visibility", "private");
12783
+ form.append("title", req.title.trim());
12784
+ if (req.description?.trim()) form.append("description", req.description.trim());
12785
+ if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
12786
+ for (const [index, sample] of req.samples.entries()) {
12787
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
12788
+ signal: ctx.signal,
12789
+ provider: "fish",
12790
+ model: ctx.model.id
12791
+ });
12792
+ const audio = new Blob([new Uint8Array(bytes)], { type: mime });
12793
+ form.append("voices", audio, fileName(index, mime));
12794
+ }
12795
+ for (const text2 of transcripts) form.append("texts", text2.trim());
12796
+ for (const signature of signatures) form.append("voice_design_signatures", signature);
12797
+ return form;
12798
+ }
12799
+ async function onlyRateLimitRetries(fn) {
12800
+ try {
12801
+ return await fn();
12802
+ } catch (cause) {
12803
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
12804
+ throw cause;
12805
+ throw new ModelKitError({
12806
+ code: cause.code,
12807
+ message: cause.message,
12808
+ ...cause.provider !== void 0 && { provider: cause.provider },
12809
+ ...cause.model !== void 0 && { model: cause.model },
12810
+ ...cause.status !== void 0 && { status: cause.status },
12811
+ ...cause.body !== void 0 && { body: cause.body },
12812
+ cause,
12813
+ retryable: false
12814
+ });
12815
+ }
12816
+ }
12817
+ async function createVoice(req, ctx) {
12818
+ checkRow(ctx, "voice-clone");
12819
+ const form = await cloneForm(req, ctx);
12820
+ const res = await withRetry(
12821
+ () => onlyRateLimitRetries(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
12822
+ mediaRetryOptions(ctx.call, ctx.signal)
12823
+ );
12824
+ const raw = await readBody(res);
12825
+ const parsed = createdModelSchema.safeParse(raw);
12826
+ if (!parsed.success) {
12827
+ throw new ModelKitError({
12828
+ code: "provider_rejected",
12829
+ message: "Fish returned no voice id",
12830
+ provider: "fish",
12831
+ model: ctx.model.id,
12832
+ status: res.status,
12833
+ body: raw,
12834
+ retryable: false
12835
+ });
12836
+ }
12837
+ const result = { voiceId: parsed.data._id, usage: usage2(ctx), raw };
12838
+ if (parsed.data.state !== void 0) result.state = parsed.data.state;
12839
+ return result;
12840
+ }
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()
12849
+ })
12850
+ ).min(1)
12851
+ });
12852
+ async function designVoice(req, ctx) {
12853
+ checkRow(ctx, "voice-design");
12854
+ const body = { instruction: req.prompt.trim() };
12855
+ if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
12856
+ if (req.language !== void 0) body.language = req.language;
12857
+ if (req.count !== void 0) body.n = req.count;
12858
+ if (req.seed !== void 0) body.seed = req.seed;
12859
+ const raw = await withRetry(
12860
+ async () => {
12861
+ const res = await fishFetch(ctx, "/v1/voice-design", {
12862
+ method: "POST",
12863
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
12864
+ body: JSON.stringify(body)
12865
+ });
12866
+ return readBody(res);
12867
+ },
12868
+ mediaRetryOptions(ctx.call, ctx.signal)
12869
+ );
12870
+ const parsed = designSchema.safeParse(raw);
12871
+ if (!parsed.success) {
12872
+ throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
12873
+ }
12874
+ const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
12875
+ audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
12876
+ durationSeconds: c.duration_ms / 1e3,
12877
+ // The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
12878
+ // rejects a clone whose signature does not verify, so a wrong one fails loudly.
12879
+ signature: c.signature ?? c.id
12880
+ }));
12881
+ return { candidates, usage: usage2(ctx) };
12882
+ }
12883
+ async function deleteVoice(req, ctx) {
12884
+ checkRow(ctx, "voice-clone");
12885
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
12886
+ let attempts = 0;
12887
+ await withRetry(
12888
+ async () => {
12889
+ attempts += 1;
12890
+ try {
12891
+ await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
12892
+ } catch (cause) {
12893
+ if (!isModelKitError(cause) || cause.status !== 404) throw cause;
12894
+ if (attempts > 1) return;
12895
+ throw new ModelKitError({
12896
+ code: "provider_rejected",
12897
+ message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
12898
+ provider: "fish",
12899
+ model: ctx.model.id,
12900
+ status: 404,
12901
+ cause,
12902
+ retryable: false
12903
+ });
12904
+ }
12905
+ },
12906
+ mediaRetryOptions(ctx.call, ctx.signal)
12907
+ );
12908
+ }
12909
+ var fishAdapter = {
12910
+ id: "fish",
12911
+ generateSpeech,
12912
+ createVoice,
12913
+ designVoice,
12914
+ deleteVoice
12915
+ };
12916
+
12328
12917
  // src/adapters/google-genai.ts
12329
- import { z as z22 } from "zod";
12918
+ import { z as z23 } from "zod";
12330
12919
  import {
12331
12920
  GoogleGenAI
12332
12921
  } from "@google/genai";
12333
12922
 
12334
12923
  // src/adapters/google-files.ts
12335
- import { z as z21 } from "zod";
12924
+ import { z as z22 } from "zod";
12336
12925
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12337
12926
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12338
12927
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12342,17 +12931,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12342
12931
  "binary/octet-stream",
12343
12932
  "application/binary"
12344
12933
  ]);
12345
- var uploadedFileSchema = z21.object({
12346
- file: z21.object({
12347
- uri: z21.string().optional(),
12348
- name: z21.string().optional(),
12349
- state: z21.string().optional(),
12350
- mimeType: z21.string().optional()
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()
12351
12940
  }).optional()
12352
12941
  });
12353
- var fileStateSchema = z21.object({
12354
- state: z21.string().optional(),
12355
- error: z21.object({ message: z21.string().optional() }).optional()
12942
+ var fileStateSchema = z22.object({
12943
+ state: z22.string().optional(),
12944
+ error: z22.object({ message: z22.string().optional() }).optional()
12356
12945
  });
12357
12946
  function resolveMime(declared, fallback) {
12358
12947
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -12459,7 +13048,7 @@ async function startAndUpload(bytes, mimeType, opts) {
12459
13048
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
12460
13049
  return ref;
12461
13050
  }
12462
- async function waitForActive(fileName, opts) {
13051
+ async function waitForActive(fileName2, opts) {
12463
13052
  const pollOptions2 = {
12464
13053
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
12465
13054
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -12472,14 +13061,14 @@ async function waitForActive(fileName, opts) {
12472
13061
  retryInit.signal = opts.signal;
12473
13062
  }
12474
13063
  await pollUntil(async () => {
12475
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, retryInit);
13064
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, retryInit);
12476
13065
  if (res.ok) {
12477
13066
  const json = fileStateSchema.parse(await res.json());
12478
13067
  if (json.state === "ACTIVE") return true;
12479
13068
  if (json.state === "FAILED") {
12480
13069
  throw classifyHttpError(
12481
13070
  void 0,
12482
- `Files API processing failed for ${fileName}: ${json.error?.message ?? "unknown error"}`,
13071
+ `Files API processing failed for ${fileName2}: ${json.error?.message ?? "unknown error"}`,
12483
13072
  "google-genai",
12484
13073
  opts.model
12485
13074
  );
@@ -12491,9 +13080,9 @@ async function waitForActive(fileName, opts) {
12491
13080
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
12492
13081
  }, pollOptions2);
12493
13082
  }
12494
- async function deleteGoogleFile(fileName, apiKey, fetchImpl) {
13083
+ async function deleteGoogleFile(fileName2, apiKey, fetchImpl) {
12495
13084
  try {
12496
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, {
13085
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName2}`, {
12497
13086
  method: "DELETE",
12498
13087
  headers: { "x-goog-api-key": apiKey }
12499
13088
  });
@@ -12573,7 +13162,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
12573
13162
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
12574
13163
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
12575
13164
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
12576
- var errorTextSchema = z22.string();
13165
+ var errorTextSchema = z23.string();
12577
13166
  function isGoogleGenaiVideoKnown(providerModelId) {
12578
13167
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
12579
13168
  }
@@ -12768,7 +13357,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12768
13357
  }
12769
13358
  };
12770
13359
  const jobId = operation.name ?? crypto.randomUUID();
12771
- const usage3 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13360
+ const usage4 = videoUsage2(ctx, duration, req.resolution ?? "720p");
12772
13361
  return {
12773
13362
  jobId,
12774
13363
  async poll() {
@@ -12806,7 +13395,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12806
13395
  modelId
12807
13396
  );
12808
13397
  }
12809
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage3, raw: finished };
13398
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage4, raw: finished };
12810
13399
  }
12811
13400
  };
12812
13401
  }
@@ -12917,7 +13506,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
12917
13506
  return file.fileUri;
12918
13507
  };
12919
13508
  const cleanupUploads = async () => {
12920
- for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
13509
+ for (const fileName2 of uploadedNames) await deleteGoogleFile(fileName2, apiKey, ctx.fetch);
12921
13510
  };
12922
13511
  const callCreate = (input) => client2.interactions.create(
12923
13512
  previousId !== void 0 ? {
@@ -13011,7 +13600,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13011
13600
  if (!(extend && !chained)) await cleanupUploads();
13012
13601
  }
13013
13602
  const jobId = interaction.id ?? crypto.randomUUID();
13014
- const usage3 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13603
+ const usage4 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13015
13604
  const getInteraction = async () => {
13016
13605
  try {
13017
13606
  const getParams = { stream: false };
@@ -13059,7 +13648,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13059
13648
  bytes: Buffer.from(video.data, "base64"),
13060
13649
  mime: video.mime_type ?? "video/mp4"
13061
13650
  },
13062
- usage: usage3,
13651
+ usage: usage4,
13063
13652
  raw: done,
13064
13653
  providerRef
13065
13654
  };
@@ -13067,7 +13656,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13067
13656
  if (video.uri)
13068
13657
  return {
13069
13658
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13070
- usage: usage3,
13659
+ usage: usage4,
13071
13660
  raw: done,
13072
13661
  providerRef
13073
13662
  };
@@ -13237,15 +13826,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13237
13826
  // src/adapters/google-image.ts
13238
13827
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
13239
13828
  import { generateText } from "ai";
13240
- import { z as z23 } from "zod";
13829
+ import { z as z24 } from "zod";
13241
13830
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13242
13831
  var defaultGoogleImageDeps = {
13243
13832
  createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
13244
13833
  runTextGeneration: (opts) => generateText(opts)
13245
13834
  };
13246
- var causeChainNodeSchema = z23.object({
13247
- message: z23.string().optional(),
13248
- cause: z23.unknown().optional()
13835
+ var causeChainNodeSchema = z24.object({
13836
+ message: z24.string().optional(),
13837
+ cause: z24.unknown().optional()
13249
13838
  });
13250
13839
  function extractBlockReason(cause) {
13251
13840
  let current = cause;
@@ -13345,7 +13934,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13345
13934
  retryable: false
13346
13935
  });
13347
13936
  }
13348
- const usage3 = {
13937
+ const usage4 = {
13349
13938
  model: ctx.model.id,
13350
13939
  provider: "google-image",
13351
13940
  modality: "IMAGE",
@@ -13353,19 +13942,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13353
13942
  quantity: images.length,
13354
13943
  imageQuality: "auto"
13355
13944
  };
13356
- if (req.size !== void 0) usage3.imageSize = req.size;
13945
+ if (req.size !== void 0) usage4.imageSize = req.size;
13357
13946
  if (result.usage?.inputTokens !== void 0)
13358
- usage3.inputTokens = result.usage.inputTokens;
13947
+ usage4.inputTokens = result.usage.inputTokens;
13359
13948
  if (result.usage?.outputTokens !== void 0)
13360
- usage3.outputTokens = result.usage.outputTokens;
13361
- return { images, usage: usage3, raw: result };
13949
+ usage4.outputTokens = result.usage.outputTokens;
13950
+ return { images, usage: usage4, raw: result };
13362
13951
  }
13363
13952
  };
13364
13953
  }
13365
13954
  var googleImageAdapter = createGoogleImageAdapter();
13366
13955
 
13367
13956
  // src/adapters/higgsfield.ts
13368
- import { z as z24 } from "zod";
13957
+ import { z as z25 } from "zod";
13369
13958
 
13370
13959
  // src/adapters/higgsfield-motions.ts
13371
13960
  var MOTION_MAP = {
@@ -13584,14 +14173,14 @@ function klingEndpointFields(providerModelId) {
13584
14173
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
13585
14174
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
13586
14175
  }
13587
- var klingCreateSchema = z24.object({ status_url: z24.string() });
13588
- var klingStatusSchema = z24.object({
13589
- status: z24.string().optional(),
13590
- video: z24.object({ url: z24.string().optional() }).optional(),
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(),
13591
14180
  error: JsonValueSchema.optional()
13592
14181
  });
13593
- var errorMessageSchema = z24.object({ message: z24.string().optional() });
13594
- var textValueSchema = z24.string();
14182
+ var errorMessageSchema = z25.object({ message: z25.string().optional() });
14183
+ var textValueSchema = z25.string();
13595
14184
  function klingErrorDetail(error) {
13596
14185
  if (error === void 0) return "unknown_error";
13597
14186
  const asText = textValueSchema.safeParse(error);
@@ -13747,8 +14336,8 @@ async function generateKlingVideo(req, ctx) {
13747
14336
  }
13748
14337
  };
13749
14338
  }
13750
- var dopMotionOptionsSchema = z24.object({
13751
- modelkit: z24.object({ motion: z24.string().optional() }).optional()
14339
+ var dopMotionOptionsSchema = z25.object({
14340
+ modelkit: z25.object({ motion: z25.string().optional() }).optional()
13752
14341
  });
13753
14342
  function dopMotionId(ctx) {
13754
14343
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -13764,7 +14353,7 @@ function dopMotionId(ctx) {
13764
14353
  });
13765
14354
  return id;
13766
14355
  }
13767
- var jsonRecordSchema = z24.record(z24.string(), JsonValueSchema);
14356
+ var jsonRecordSchema = z25.record(z25.string(), JsonValueSchema);
13768
14357
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
13769
14358
  var DOP_NESTED_KEYS = ["video", "result", "results"];
13770
14359
  function dopUrl(body) {
@@ -13792,8 +14381,8 @@ function dopUrl(body) {
13792
14381
  }
13793
14382
  return void 0;
13794
14383
  }
13795
- var dopCreateSchema = z24.object({ id: z24.string() });
13796
- var dopStatusSchema = z24.object({ status: z24.string().optional() });
14384
+ var dopCreateSchema = z25.object({ id: z25.string() });
14385
+ var dopStatusSchema = z25.object({ status: z25.string().optional() });
13797
14386
  async function generateDopVideo(req, ctx) {
13798
14387
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
13799
14388
  if (!firstFrame) {
@@ -13920,7 +14509,7 @@ var higgsfieldAdapter = {
13920
14509
  };
13921
14510
 
13922
14511
  // src/adapters/luma.ts
13923
- import { z as z25 } from "zod";
14512
+ import { z as z26 } from "zod";
13924
14513
 
13925
14514
  // src/adapters/mp4-duration.ts
13926
14515
  function mp4DurationSeconds(bytes) {
@@ -13976,7 +14565,7 @@ function findBox(bytes, from, to, type) {
13976
14565
  }
13977
14566
 
13978
14567
  // src/adapters/luma.ts
13979
- var DEFAULT_BASE_URL = "https://agents.lumalabs.ai";
14568
+ var DEFAULT_BASE_URL2 = "https://agents.lumalabs.ai";
13980
14569
  var IMAGE_POLL_INTERVAL_MS = 3e3;
13981
14570
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
13982
14571
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14005,7 +14594,7 @@ function lumaModel(ctx) {
14005
14594
  return ctx.model.providerModelId.toLowerCase();
14006
14595
  }
14007
14596
  function lumaBase(ctx) {
14008
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
14597
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL2;
14009
14598
  }
14010
14599
  function lumaKey(ctx) {
14011
14600
  const key = ctx.keys.luma;
@@ -14137,17 +14726,17 @@ function lumaReframeResolution(req, ctx) {
14137
14726
  });
14138
14727
  return "720p";
14139
14728
  }
14140
- var lumaGenerationSchema = z25.looseObject({
14141
- id: z25.string(),
14142
- state: z25.string().optional(),
14143
- output: z25.array(
14144
- z25.looseObject({
14145
- type: z25.string().optional(),
14146
- url: z25.string().optional()
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()
14147
14736
  })
14148
14737
  ).optional(),
14149
- failure_reason: z25.string().optional().nullable(),
14150
- failure_code: z25.string().optional().nullable()
14738
+ failure_reason: z26.string().optional().nullable(),
14739
+ failure_code: z26.string().optional().nullable()
14151
14740
  });
14152
14741
  function lumaFailure(ctx, code, reason) {
14153
14742
  const detail = reason ?? code ?? "unknown_error";
@@ -14579,7 +15168,7 @@ var lumaAdapter = {
14579
15168
 
14580
15169
  // src/adapters/openai-image.ts
14581
15170
  import OpenAI from "openai";
14582
- import { z as z26 } from "zod";
15171
+ import { z as z27 } from "zod";
14583
15172
  var MAX_EDIT_REFERENCES = 16;
14584
15173
  function aspectRatioToSize(ratio, tier) {
14585
15174
  const TIER_LONG_EDGE = {
@@ -14662,9 +15251,9 @@ function toProviderError2(cause, ctx) {
14662
15251
  ctx.model.id
14663
15252
  );
14664
15253
  }
14665
- var openaiUsageSchema = z26.object({
14666
- input_tokens: z26.number().optional(),
14667
- output_tokens: z26.number().optional()
15254
+ var openaiUsageSchema = z27.object({
15255
+ input_tokens: z27.number().optional(),
15256
+ output_tokens: z27.number().optional()
14668
15257
  });
14669
15258
  var openaiImageAdapter = {
14670
15259
  id: "openai-image",
@@ -14789,7 +15378,7 @@ var openaiImageAdapter = {
14789
15378
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
14790
15379
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
14791
15380
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
14792
- const usage3 = {
15381
+ const usage4 = {
14793
15382
  model: ctx.model.id,
14794
15383
  provider: "openai-image",
14795
15384
  modality: "IMAGE",
@@ -14797,10 +15386,10 @@ var openaiImageAdapter = {
14797
15386
  quantity: images.length,
14798
15387
  imageQuality: quality
14799
15388
  };
14800
- if (inputTokens !== void 0) usage3.inputTokens = inputTokens;
14801
- if (outputTokens !== void 0) usage3.outputTokens = outputTokens;
14802
- if (req.size !== void 0) usage3.imageSize = req.size;
14803
- return { images, usage: usage3, raw: response };
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 };
14804
15393
  }
14805
15394
  };
14806
15395
 
@@ -15056,16 +15645,16 @@ async function generateProdiaImage(req, ctx) {
15056
15645
  new Uint8Array(await res.arrayBuffer()),
15057
15646
  res.headers.get("content-type")
15058
15647
  );
15059
- const usage3 = {
15648
+ const usage4 = {
15060
15649
  model: ctx.model.id,
15061
15650
  provider: "prodia",
15062
15651
  modality: "IMAGE",
15063
15652
  unit: "images",
15064
15653
  quantity: 1
15065
15654
  };
15066
- if (req.size !== void 0) usage3.imageSize = req.size;
15067
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
15068
- return { images: [{ bytes, mime }], usage: usage3, raw: void 0 };
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 };
15069
15658
  }
15070
15659
  var prodiaAdapter = {
15071
15660
  id: "prodia",
@@ -15076,13 +15665,13 @@ var prodiaAdapter = {
15076
15665
  import Replicate from "replicate";
15077
15666
 
15078
15667
  // src/adapters/replicate-http.ts
15079
- import { z as z27 } from "zod";
15080
- var predictionSchema = z27.object({
15081
- id: z27.string(),
15082
- status: z27.string(),
15668
+ import { z as z28 } from "zod";
15669
+ var predictionSchema = z28.object({
15670
+ id: z28.string(),
15671
+ status: z28.string(),
15083
15672
  output: JsonValueSchema.optional(),
15084
15673
  error: JsonValueSchema.optional(),
15085
- metrics: z27.object({ predict_time: z27.number().optional() }).optional()
15674
+ metrics: z28.object({ predict_time: z28.number().optional() }).optional()
15086
15675
  });
15087
15676
  function createReplicateHttpClient(opts) {
15088
15677
  async function request(path, body, signal) {
@@ -15133,7 +15722,7 @@ function createReplicateHttpClient(opts) {
15133
15722
  }
15134
15723
 
15135
15724
  // src/adapters/replicate.ts
15136
- import { z as z28 } from "zod";
15725
+ import { z as z29 } from "zod";
15137
15726
  var POLL_INTERVAL_MS = 1e3;
15138
15727
  var POLL_TIMEOUT_MS = 15 * 6e4;
15139
15728
  var defaultReplicateDeps = {
@@ -15173,8 +15762,8 @@ function route(providerModelId) {
15173
15762
  if (!providerModelId.includes("/")) return { version: providerModelId };
15174
15763
  return { model: providerModelId };
15175
15764
  }
15176
- var replicateResponseStatusSchema = z28.object({
15177
- response: z28.object({ status: z28.number() }).partial()
15765
+ var replicateResponseStatusSchema = z29.object({
15766
+ response: z29.object({ status: z29.number() }).partial()
15178
15767
  });
15179
15768
  function replicateError(cause, ctx) {
15180
15769
  if (isModelKitError(cause)) return cause;
@@ -15197,7 +15786,7 @@ function isUrlFn(value) {
15197
15786
  function extractOutputUrl(output) {
15198
15787
  const root = Array.isArray(output) ? output[0] : output;
15199
15788
  if (root === void 0) throw noOutput();
15200
- const asString = z28.string().safeParse(root);
15789
+ const asString = z29.string().safeParse(root);
15201
15790
  if (asString.success && asString.data) return asString.data;
15202
15791
  if (root instanceof URL) return root.href;
15203
15792
  if (isObjectOutput(root)) {
@@ -15206,15 +15795,15 @@ function extractOutputUrl(output) {
15206
15795
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15207
15796
  const called = urlValue();
15208
15797
  if (called instanceof URL) return called.href;
15209
- const calledString = z28.string().safeParse(called);
15798
+ const calledString = z29.string().safeParse(called);
15210
15799
  if (calledString.success && calledString.data) return calledString.data;
15211
15800
  } else {
15212
- const direct = z28.string().safeParse(urlValue);
15801
+ const direct = z29.string().safeParse(urlValue);
15213
15802
  if (direct.success && direct.data) return direct.data;
15214
15803
  }
15215
15804
  }
15216
15805
  if ("default" in root) {
15217
- const fallback = z28.string().safeParse(root.default);
15806
+ const fallback = z29.string().safeParse(root.default);
15218
15807
  if (fallback.success && fallback.data) return fallback.data;
15219
15808
  }
15220
15809
  }
@@ -15275,7 +15864,7 @@ async function runPrediction(ctx, input, deps) {
15275
15864
  }
15276
15865
  return void 0;
15277
15866
  }, pollOpts);
15278
- const predictTime = z28.number().safeParse(done.metrics?.predict_time);
15867
+ const predictTime = z29.number().safeParse(done.metrics?.predict_time);
15279
15868
  if (done.output === void 0) throw noOutput();
15280
15869
  return {
15281
15870
  url: extractOutputUrl(done.output),
@@ -15521,9 +16110,9 @@ async function generateReplicateImage(req, ctx, deps) {
15521
16110
  }
15522
16111
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15523
16112
  const file = await download(ctx, url);
15524
- const usage3 = imageUsage3(ctx, req);
15525
- usage3.quantity = predictTime;
15526
- return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage3, raw, outputUrl: 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 };
15527
16116
  }
15528
16117
  function klingInput(req) {
15529
16118
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -15628,7 +16217,7 @@ async function generateReplicateVideo(req, ctx, deps) {
15628
16217
  throw replicateError(cause, ctx);
15629
16218
  }
15630
16219
  if (current.status === "succeeded") {
15631
- const predictTime = z28.number().safeParse(current.metrics?.predict_time);
16220
+ const predictTime = z29.number().safeParse(current.metrics?.predict_time);
15632
16221
  if (current.output === void 0) throw noOutput();
15633
16222
  return {
15634
16223
  url: extractOutputUrl(current.output),
@@ -15647,9 +16236,9 @@ async function generateReplicateVideo(req, ctx, deps) {
15647
16236
  return void 0;
15648
16237
  };
15649
16238
  const toResult = (done) => {
15650
- const usage3 = videoUsage5(ctx, req);
15651
- usage3.quantity = done.predictTime;
15652
- return { video: { url: done.url }, usage: usage3, raw: done.raw };
16239
+ const usage4 = videoUsage5(ctx, req);
16240
+ usage4.quantity = done.predictTime;
16241
+ return { video: { url: done.url }, usage: usage4, raw: done.raw };
15653
16242
  };
15654
16243
  return {
15655
16244
  jobId,
@@ -15756,21 +16345,21 @@ async function generateReplicateAudio(req, ctx, deps) {
15756
16345
  input = specResult.input;
15757
16346
  }
15758
16347
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15759
- const usage3 = audioUsage(ctx, req);
16348
+ const usage4 = audioUsage(ctx, req);
15760
16349
  if (ctx.model.usage.unit === "seconds") {
15761
16350
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
15762
- usage3.quantity = seconds3;
15763
- usage3.durationSeconds = seconds3;
16351
+ usage4.quantity = seconds3;
16352
+ usage4.durationSeconds = seconds3;
15764
16353
  } else {
15765
- usage3.quantity = predictTime;
16354
+ usage4.quantity = predictTime;
15766
16355
  }
15767
- return { audio: { url }, usage: usage3, raw: predictionRaw(raw) };
16356
+ return { audio: { url }, usage: usage4, raw: predictionRaw(raw) };
15768
16357
  }
15769
16358
 
15770
16359
  // src/adapters/xai-video.ts
15771
16360
  import { experimental_generateVideo } from "ai";
15772
16361
  import { createXai as createXai2 } from "@ai-sdk/xai";
15773
- import { z as z29 } from "zod";
16362
+ import { z as z30 } from "zod";
15774
16363
  var POLL_INTERVAL_MS2 = 1e4;
15775
16364
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
15776
16365
  var defaultXaiDeps = {
@@ -15783,8 +16372,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
15783
16372
  };
15784
16373
  }
15785
16374
  var xaiVideoAdapter = createXaiVideoAdapter();
15786
- var xaiResponseStatusSchema = z29.object({
15787
- response: z29.object({ status: z29.number() }).partial()
16375
+ var xaiResponseStatusSchema = z30.object({
16376
+ response: z30.object({ status: z30.number() }).partial()
15788
16377
  });
15789
16378
  function xaiError(cause, ctx) {
15790
16379
  const info = describeThrown(cause);
@@ -15792,12 +16381,12 @@ function xaiError(cause, ctx) {
15792
16381
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
15793
16382
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
15794
16383
  }
15795
- var xaiMetaSchema = z29.object({
16384
+ var xaiMetaSchema = z30.object({
15796
16385
  videoUrl: JsonValueSchema.optional(),
15797
16386
  costInUsdTicks: JsonValueSchema.optional(),
15798
16387
  duration: JsonValueSchema.optional()
15799
16388
  });
15800
- var xaiProviderMetadataSchema = z29.object({ xai: xaiMetaSchema });
16389
+ var xaiProviderMetadataSchema = z30.object({ xai: xaiMetaSchema });
15801
16390
  function metaOf(result) {
15802
16391
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
15803
16392
  if (!parsed.success) return {};
@@ -15909,12 +16498,12 @@ async function mapResult(ctx, req, result) {
15909
16498
  if (first) {
15910
16499
  return {
15911
16500
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
15912
- usage: usage2(ctx, req, metaOf(result)),
16501
+ usage: usage3(ctx, req, metaOf(result)),
15913
16502
  raw: result.providerMetadata
15914
16503
  };
15915
16504
  }
15916
16505
  const meta = metaOf(result);
15917
- const videoUrl = z29.string().safeParse(meta.videoUrl);
16506
+ const videoUrl = z30.string().safeParse(meta.videoUrl);
15918
16507
  if (videoUrl.success && videoUrl.data) {
15919
16508
  const res = await ctx.fetch(videoUrl.data);
15920
16509
  if (!res.ok) {
@@ -15924,7 +16513,7 @@ async function mapResult(ctx, req, result) {
15924
16513
  const mime = res.headers.get("content-type") ?? "video/mp4";
15925
16514
  return {
15926
16515
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
15927
- usage: usage2(ctx, req, meta),
16516
+ usage: usage3(ctx, req, meta),
15928
16517
  raw: result.providerMetadata
15929
16518
  };
15930
16519
  }
@@ -15936,8 +16525,8 @@ async function mapResult(ctx, req, result) {
15936
16525
  retryable: false
15937
16526
  });
15938
16527
  }
15939
- function usage2(ctx, req, meta) {
15940
- const costTicks = z29.number().safeParse(meta.costInUsdTicks);
16528
+ function usage3(ctx, req, meta) {
16529
+ const costTicks = z30.number().safeParse(meta.costInUsdTicks);
15941
16530
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
15942
16531
  const event = {
15943
16532
  model: ctx.model.id,
@@ -15976,7 +16565,8 @@ var DEFAULT_ADAPTERS = {
15976
16565
  prodia: prodiaAdapter,
15977
16566
  higgsfield: higgsfieldAdapter,
15978
16567
  "xai-video": xaiVideoAdapter,
15979
- luma: lumaAdapter
16568
+ luma: lumaAdapter,
16569
+ fish: fishAdapter
15980
16570
  };
15981
16571
 
15982
16572
  // src/catalog/data-only.ts
@@ -16000,6 +16590,8 @@ function adapterServesType(adapter, type) {
16000
16590
  if (type === "dubbing") return adapter.dub !== void 0;
16001
16591
  if (type === "lipsync") return adapter.lipsync !== void 0;
16002
16592
  if (type === "transcription") return adapter.transcribe !== void 0;
16593
+ if (type === "voice-clone") return adapter.createVoice !== void 0;
16594
+ if (type === "voice-design") return adapter.designVoice !== void 0;
16003
16595
  if (type === "video-tool") return adapter.submitVideoTool !== void 0;
16004
16596
  if (type === "model3d") return adapter.submitModel3d !== void 0;
16005
16597
  return adapter.languageModel !== void 0;
@@ -16013,12 +16605,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16013
16605
  "transcription",
16014
16606
  "mask"
16015
16607
  ]);
16608
+ function fishSpeech(row2) {
16609
+ return row2.adapter === "fish" && row2.type === "speech";
16610
+ }
16016
16611
  function dataOnlyCapable(row2) {
16017
16612
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16018
16613
  if (!adapterServesType(adapter, row2.type)) {
16019
16614
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16020
16615
  }
16021
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
16616
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !fishSpeech(row2)) {
16022
16617
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16023
16618
  }
16024
16619
  switch (row2.adapter) {
@@ -16096,6 +16691,10 @@ function dataOnlyCapable(row2) {
16096
16691
  const reason = lumaRowRefusal(row2);
16097
16692
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16098
16693
  }
16694
+ case "fish": {
16695
+ const reason = fishRowRefusal(row2);
16696
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
16697
+ }
16099
16698
  default: {
16100
16699
  return assertNever(row2.adapter);
16101
16700
  }
@@ -16115,22 +16714,22 @@ var liveState = store[KEY] ??= {
16115
16714
  var liveCatalog = liveState.catalog;
16116
16715
 
16117
16716
  // src/catalog/load.ts
16118
- import { z as z30 } from "zod";
16717
+ import { z as z31 } from "zod";
16119
16718
  function rowCount() {
16120
16719
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16121
16720
  }
16122
16721
  function authHeaders(auth) {
16123
16722
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16124
16723
  }
16125
- var EnvelopeSchema = z30.object({
16126
- rows: z30.array(JsonValueSchema),
16127
- revision: z30.string().optional()
16724
+ var EnvelopeSchema = z31.object({
16725
+ rows: z31.array(JsonValueSchema),
16726
+ revision: z31.string().optional()
16128
16727
  });
16129
16728
  function dropReason(path, message) {
16130
16729
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16131
16730
  }
16132
16731
  function rowId(raw) {
16133
- const parsed = z30.object({ id: z30.string().min(1) }).loose().safeParse(raw);
16732
+ const parsed = z31.object({ id: z31.string().min(1) }).loose().safeParse(raw);
16134
16733
  if (!parsed.success) return "?";
16135
16734
  return parsed.data.id;
16136
16735
  }
@@ -17046,8 +17645,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
17046
17645
  const warnings = [];
17047
17646
  checkScript(model, request.text);
17048
17647
  const resolved = { model: model.id, text: request.text };
17049
- const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
17050
- if (voice !== void 0) resolved.voice = voice;
17648
+ const customVoice = request.customVoice?.trim();
17649
+ if (customVoice) {
17650
+ if (model.capabilities?.customVoices !== true) {
17651
+ throw unsupported3(model, "does not take a custom voice");
17652
+ }
17653
+ if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
17654
+ resolved.customVoice = customVoice;
17655
+ } else {
17656
+ const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
17657
+ if (voice !== void 0) resolved.voice = voice;
17658
+ }
17051
17659
  const language = resolveListed(
17052
17660
  model,
17053
17661
  {
@@ -17169,6 +17777,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
17169
17777
  return { request: resolved, warnings };
17170
17778
  }
17171
17779
 
17780
+ // src/resolve-voice.ts
17781
+ function refuse(model, code, message) {
17782
+ return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
17783
+ }
17784
+ function checkSample(model, sample, index) {
17785
+ const limits = model.constraints.references?.audioSeconds;
17786
+ const length = sample.audio.durationSeconds;
17787
+ if (limits === void 0 || length === void 0) return;
17788
+ if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
17789
+ const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
17790
+ throw refuse(
17791
+ model,
17792
+ "unsupported_option",
17793
+ `takes samples of ${range2}; sample ${index + 1} is ${length} s`
17794
+ );
17795
+ }
17796
+ }
17797
+ function resolveVoiceCloneOptions(model, request) {
17798
+ const title = request.title.trim();
17799
+ if (!title) throw refuse(model, "missing_input", "needs a title");
17800
+ if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
17801
+ const max = model.constraints.references?.audios;
17802
+ if (max !== void 0 && request.samples.length > max) {
17803
+ throw refuse(
17804
+ model,
17805
+ "unsupported_option",
17806
+ `takes up to ${max} samples; got ${request.samples.length}`
17807
+ );
17808
+ }
17809
+ request.samples.forEach((sample, index) => checkSample(model, sample, index));
17810
+ const total = model.constraints.references?.audioSeconds?.total;
17811
+ const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
17812
+ if (total !== void 0 && seconds3 > total) {
17813
+ throw refuse(
17814
+ model,
17815
+ "unsupported_option",
17816
+ `takes up to ${total} s of samples; got ${seconds3} s`
17817
+ );
17818
+ }
17819
+ for (const field of ["transcript", "designSignature"]) {
17820
+ const set = request.samples.filter((s) => s[field]?.trim()).length;
17821
+ if (set !== 0 && set !== request.samples.length) {
17822
+ throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
17823
+ }
17824
+ }
17825
+ return { request: { ...request, model: model.id, title }, warnings: [] };
17826
+ }
17827
+ function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
17828
+ const warnings = [];
17829
+ const prompt = request.prompt.trim();
17830
+ if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
17831
+ const maxChars = promptConventions(model).maxChars;
17832
+ if (maxChars !== void 0 && prompt.length > maxChars) {
17833
+ throw refuse(
17834
+ model,
17835
+ "unsupported_option",
17836
+ `takes up to ${maxChars} characters; got ${prompt.length}`
17837
+ );
17838
+ }
17839
+ const limits = model.constraints.voiceDesign;
17840
+ const resolved = { model: model.id, prompt };
17841
+ const preview2 = request.previewText?.trim();
17842
+ if (preview2) {
17843
+ if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
17844
+ throw refuse(
17845
+ model,
17846
+ "unsupported_option",
17847
+ `takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
17848
+ );
17849
+ }
17850
+ resolved.previewText = preview2;
17851
+ }
17852
+ const language = request.language?.trim();
17853
+ if (language) resolved.language = language;
17854
+ if (request.seed !== void 0) resolved.seed = request.seed;
17855
+ const count2 = request.count ?? model.defaults.count;
17856
+ if (count2 !== void 0) {
17857
+ const cap = limits?.maxCandidates ?? count2;
17858
+ if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
17859
+ if (onUnsupported === "error" || !Number.isInteger(count2)) {
17860
+ throw refuse(
17861
+ model,
17862
+ "unsupported_option",
17863
+ `returns 1-${cap} candidates; got ${count2}`
17864
+ );
17865
+ }
17866
+ const to = Math.min(Math.max(count2, 1), cap);
17867
+ warnings.push({
17868
+ code: "option_ignored",
17869
+ field: "count",
17870
+ from: String(count2),
17871
+ to: String(to),
17872
+ message: `count ${count2} replaced by ${to} for ${model.id}`
17873
+ });
17874
+ resolved.count = to;
17875
+ } else resolved.count = count2;
17876
+ }
17877
+ return { request: resolved, warnings };
17878
+ }
17879
+
17172
17880
  // src/keys.ts
17173
17881
  var ADAPTER_KEYS = {
17174
17882
  "ai-sdk-text": [],
@@ -17181,7 +17889,8 @@ var ADAPTER_KEYS = {
17181
17889
  prodia: ["prodia"],
17182
17890
  higgsfield: ["higgsfield"],
17183
17891
  "xai-video": ["xai"],
17184
- luma: ["luma"]
17892
+ luma: ["luma"],
17893
+ fish: ["fish"]
17185
17894
  };
17186
17895
  function hasAll(keys, names) {
17187
17896
  if (!keys) return false;
@@ -17240,6 +17949,7 @@ function keysFromEnv(env, prefix = "") {
17240
17949
  set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
17241
17950
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17242
17951
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
17952
+ set("fish", pick2("FISH_AUDIO_API_KEY"));
17243
17953
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17244
17954
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17245
17955
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17262,7 +17972,7 @@ function keysFromEnv(env, prefix = "") {
17262
17972
 
17263
17973
  // src/text.ts
17264
17974
  import "ai";
17265
- import { z as z31 } from "zod";
17975
+ import { z as z32 } from "zod";
17266
17976
  function mergeTextProviderOptions(catalog, caller) {
17267
17977
  const merged = {};
17268
17978
  const catalogOptions = catalog.providerOptions ?? {};
@@ -17301,17 +18011,17 @@ function passthroughTextModel(model) {
17301
18011
  pricingKind: "token"
17302
18012
  };
17303
18013
  }
17304
- var perplexityCostSchema = z31.object({
17305
- perplexity: z31.object({ cost: z31.object({ totalCost: z31.number().finite().nonnegative() }) })
18014
+ var perplexityCostSchema = z32.object({
18015
+ perplexity: z32.object({ cost: z32.object({ totalCost: z32.number().finite().nonnegative() }) })
17306
18016
  });
17307
18017
  function reportedCostUsd(metadata) {
17308
18018
  const parsed = perplexityCostSchema.safeParse(metadata);
17309
18019
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
17310
18020
  }
17311
- function textUsageEvent(model, provider, usage3, providerMetadata) {
17312
- const inputTokens = usage3.inputTokens ?? 0;
17313
- const outputTokens = usage3.outputTokens ?? 0;
17314
- const total = usage3.totalTokens ?? inputTokens + outputTokens;
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;
17315
18025
  const event = {
17316
18026
  model: model.id,
17317
18027
  provider,
@@ -17346,7 +18056,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17346
18056
  return { ...prepared, providerOptions };
17347
18057
  };
17348
18058
  }
17349
- function usage3(results) {
18059
+ function usage4(results) {
17350
18060
  const grouped = /* @__PURE__ */ new Map();
17351
18061
  for (const [index, step] of results.entries()) {
17352
18062
  const target = steps.get(index) ?? initial;
@@ -17370,7 +18080,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17370
18080
  }
17371
18081
  return [...grouped.values()];
17372
18082
  }
17373
- return { wrap, usage: usage3 };
18083
+ return { wrap, usage: usage4 };
17374
18084
  }
17375
18085
 
17376
18086
  // src/client.ts
@@ -17382,7 +18092,7 @@ import {
17382
18092
  streamObject as aiStreamObject2,
17383
18093
  streamText as aiStreamText2
17384
18094
  } from "ai";
17385
- import { z as z32 } from "zod";
18095
+ import { z as z33 } from "zod";
17386
18096
 
17387
18097
  // src/generated-image.ts
17388
18098
  function toGeneratedImage(image) {
@@ -17504,9 +18214,9 @@ function providerJobMethods(kind, deps) {
17504
18214
  if (!methods.result) throw missing3(adapter, ctx.model);
17505
18215
  const result = await methods.result(sub, ctx, webhook);
17506
18216
  const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
17507
- const usage3 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
17508
- await deps.emit(usage3);
17509
- return { ...result, usage: usage3 };
18217
+ const usage4 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18218
+ await deps.emit(usage4);
18219
+ return { ...result, usage: usage4 };
17510
18220
  },
17511
18221
  async cancel(sub, call = {}) {
17512
18222
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -17531,6 +18241,9 @@ var MEDIA_METHODS = {
17531
18241
  lipsync: ["lipsync"],
17532
18242
  dubbing: ["dub"],
17533
18243
  transcription: ["transcribe"],
18244
+ // deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
18245
+ "voice-clone": ["createVoice"],
18246
+ "voice-design": ["designVoice"],
17534
18247
  "video-tool": ["submitVideoTool"],
17535
18248
  // 3D jobs run through submitModel3d, which checks the row type itself; their preflight
17536
18249
  // is model3dInputRefusal, not resolveOptions.
@@ -17545,6 +18258,8 @@ var METHOD_NOUN = {
17545
18258
  lipsync: "a lipsync model",
17546
18259
  dub: "a dubbing model",
17547
18260
  transcribe: "a transcription model",
18261
+ createVoice: "a voice cloning model",
18262
+ designVoice: "a voice design model",
17548
18263
  submitVideoTool: "a video tool"
17549
18264
  };
17550
18265
  function assertMethod(model, method) {
@@ -17587,6 +18302,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
17587
18302
  assertMethod(model, "transcribe");
17588
18303
  return resolveTranscriptionOptions(model, request, onUnsupported);
17589
18304
  }
18305
+ function resolveVoiceCloneCall(model, request) {
18306
+ assertMethod(model, "createVoice");
18307
+ return resolveVoiceCloneOptions(model, request);
18308
+ }
18309
+ function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
18310
+ assertMethod(model, "designVoice");
18311
+ return resolveVoiceDesignOptions(model, request, onUnsupported);
18312
+ }
17590
18313
 
17591
18314
  // src/client-audio.ts
17592
18315
  function noMethod(adapter, model, what) {
@@ -17676,6 +18399,49 @@ function audioNodeMethods(deps) {
17676
18399
  const result = await adapter.transcribe(resolved, ctx);
17677
18400
  return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
17678
18401
  },
18402
+ async createVoice(req, call = {}) {
18403
+ mediaRetryOptions(call);
18404
+ const { abortSignal, ...request } = req;
18405
+ const model = catalog.require(req.model);
18406
+ const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
18407
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18408
+ if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
18409
+ const startedAt = Date.now();
18410
+ const result = await adapter.createVoice(resolved, ctx);
18411
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18412
+ },
18413
+ async designVoice(req, call = {}) {
18414
+ mediaRetryOptions(call);
18415
+ const { abortSignal, ...request } = req;
18416
+ const model = catalog.require(req.model);
18417
+ const { request: resolved, warnings } = resolveVoiceDesignCall(
18418
+ model,
18419
+ request,
18420
+ call.onUnsupported ?? "error"
18421
+ );
18422
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18423
+ if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
18424
+ const startedAt = Date.now();
18425
+ const result = await adapter.designVoice(resolved, ctx);
18426
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18427
+ },
18428
+ async deleteVoice(req, call = {}) {
18429
+ mediaRetryOptions(call);
18430
+ const { abortSignal, ...request } = req;
18431
+ const model = catalog.require(req.model);
18432
+ assertMethod(model, "createVoice");
18433
+ const voiceId = request.voiceId.trim();
18434
+ if (!voiceId) {
18435
+ throw new ModelKitError({
18436
+ code: "missing_input",
18437
+ message: `${model.id} requires voiceId`,
18438
+ model: model.id
18439
+ });
18440
+ }
18441
+ const { adapter, ctx } = prepare(model, call, abortSignal, []);
18442
+ if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
18443
+ await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
18444
+ },
17679
18445
  async dub(req, call = {}) {
17680
18446
  mediaRetryOptions(call);
17681
18447
  const { abortSignal, ...request } = req;
@@ -17690,10 +18456,10 @@ function audioNodeMethods(deps) {
17690
18456
  const startedAt = Date.now();
17691
18457
  const outcome = await adapter.dub(resolved, ctx);
17692
18458
  if (outcome.kind === "audio") {
17693
- const { audio, usage: usage3, raw } = outcome.result;
18459
+ const { audio, usage: usage4, raw } = outcome.result;
17694
18460
  return {
17695
18461
  audio,
17696
- usage: await deps.settle(model, usage3, startedAt),
18462
+ usage: await deps.settle(model, usage4, startedAt),
17697
18463
  ...raw !== void 0 && { raw }
17698
18464
  };
17699
18465
  }
@@ -17731,10 +18497,10 @@ function textAbortOptions(sdk, context) {
17731
18497
  if (abortSignal) return { abortSignal };
17732
18498
  return {};
17733
18499
  }
17734
- var catalogId = z32.string();
17735
- var exactSize = z32.templateLiteral([z32.number(), "x", z32.number()]);
17736
- var sdkRatio = z32.templateLiteral([z32.number(), ":", z32.number()]);
17737
- var sizeTier = z32.enum(["512", "1K", "2K", "4K"]);
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"]);
17738
18504
  function isCatalogId(model) {
17739
18505
  return catalogId.safeParse(model).success;
17740
18506
  }
@@ -17947,7 +18713,7 @@ function createModelKit(config, adapters) {
17947
18713
  const images = result.images.map(
17948
18714
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
17949
18715
  );
17950
- const usage3 = timed(
18716
+ const usage4 = timed(
17951
18717
  {
17952
18718
  model: model.modelId,
17953
18719
  provider: model.provider,
@@ -17957,8 +18723,8 @@ function createModelKit(config, adapters) {
17957
18723
  },
17958
18724
  startedAt
17959
18725
  );
17960
- await emit(usage3);
17961
- return { image: images[0], images, usage: usage3, raw: result, warnings };
18726
+ await emit(usage4);
18727
+ return { image: images[0], images, usage: usage4, raw: result, warnings };
17962
18728
  }
17963
18729
  function passthroughVideo(req, call) {
17964
18730
  const {
@@ -18034,7 +18800,7 @@ function createModelKit(config, adapters) {
18034
18800
  let settled;
18035
18801
  let failed = false;
18036
18802
  const done = pending.then(async (result) => {
18037
- const usage3 = timed(
18803
+ const usage4 = timed(
18038
18804
  {
18039
18805
  model: model.modelId,
18040
18806
  provider: model.provider,
@@ -18047,10 +18813,10 @@ function createModelKit(config, adapters) {
18047
18813
  );
18048
18814
  settled = {
18049
18815
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18050
- usage: usage3,
18816
+ usage: usage4,
18051
18817
  raw: result
18052
18818
  };
18053
- await emit(usage3);
18819
+ await emit(usage4);
18054
18820
  return settled;
18055
18821
  });
18056
18822
  done.catch(() => {
@@ -18077,12 +18843,12 @@ function createModelKit(config, adapters) {
18077
18843
  if (settled) return settled;
18078
18844
  const pending = result(opts).then(
18079
18845
  async (out) => {
18080
- const usage3 = timed(
18846
+ const usage4 = timed(
18081
18847
  { ...out.usage, model: model.id, unit: model.usage.unit },
18082
18848
  startedAt
18083
18849
  );
18084
- await emit(usage3);
18085
- return { ...out, usage: usage3 };
18850
+ await emit(usage4);
18851
+ return { ...out, usage: usage4 };
18086
18852
  },
18087
18853
  (cause) => {
18088
18854
  settled = void 0;
@@ -18102,9 +18868,9 @@ function createModelKit(config, adapters) {
18102
18868
  return context(model, signal ? { ...call, signal } : call, warnings);
18103
18869
  },
18104
18870
  async settle(model, event, startedAt) {
18105
- const usage3 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
18106
- await emit(usage3);
18107
- return usage3;
18871
+ const usage4 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
18872
+ await emit(usage4);
18873
+ return usage4;
18108
18874
  },
18109
18875
  wrapVideoJob
18110
18876
  });
@@ -18140,11 +18906,11 @@ function createModelKit(config, adapters) {
18140
18906
  });
18141
18907
  const startedAt = Date.now();
18142
18908
  const result = await adapter.generateImage(request, ctx);
18143
- const usage3 = timed(
18909
+ const usage4 = timed(
18144
18910
  { ...result.usage, model: model.id, unit: model.usage.unit },
18145
18911
  startedAt
18146
18912
  );
18147
- await emit(usage3);
18913
+ await emit(usage4);
18148
18914
  const images = result.images.map(toGeneratedImage);
18149
18915
  const first = images[0];
18150
18916
  if (!first)
@@ -18153,7 +18919,7 @@ function createModelKit(config, adapters) {
18153
18919
  message: `${model.id} returned no image`,
18154
18920
  model: model.id
18155
18921
  });
18156
- return { ...result, usage: usage3, image: first, images, warnings };
18922
+ return { ...result, usage: usage4, image: first, images, warnings };
18157
18923
  },
18158
18924
  async generateVideo(req, call = {}) {
18159
18925
  mediaRetryOptions(call);
@@ -18252,12 +19018,12 @@ function createModelKit(config, adapters) {
18252
19018
  }
18253
19019
  const startedAt = Date.now();
18254
19020
  const result = await adapter.generateAudio(resolved, ctx);
18255
- const usage3 = timed(
19021
+ const usage4 = timed(
18256
19022
  { ...result.usage, model: model.id, unit: model.usage.unit },
18257
19023
  startedAt
18258
19024
  );
18259
- await emit(usage3);
18260
- return { ...result, usage: usage3 };
19025
+ await emit(usage4);
19026
+ return { ...result, usage: usage4 };
18261
19027
  },
18262
19028
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
18263
19029
  mediaRetryOptions(call);
@@ -18337,8 +19103,8 @@ function createModelKit(config, adapters) {
18337
19103
  options.prepareStep ?? options.experimental_prepareStep
18338
19104
  ),
18339
19105
  onFinish: async (event) => {
18340
- for (const usage3 of steps.usage(event.steps))
18341
- await emit(textTimed(withRowUnit(usage3), event.steps.length, startedAt));
19106
+ for (const usage4 of steps.usage(event.steps))
19107
+ await emit(textTimed(withRowUnit(usage4), event.steps.length, startedAt));
18342
19108
  await callerOnFinish?.(event);
18343
19109
  }
18344
19110
  });
@@ -18460,6 +19226,7 @@ export {
18460
19226
  falAdapter,
18461
19227
  falWebhookBodySchema,
18462
19228
  fileCatalogCache,
19229
+ fishAdapter,
18463
19230
  generateAudio,
18464
19231
  generateImage,
18465
19232
  generateObject,
@@ -18512,6 +19279,8 @@ export {
18512
19279
  resolveTranscriptionOptions,
18513
19280
  resolveVideoOptions,
18514
19281
  resolveVoiceChangeOptions,
19282
+ resolveVoiceCloneOptions,
19283
+ resolveVoiceDesignOptions,
18515
19284
  shouldRetry,
18516
19285
  sleep,
18517
19286
  sortCatalogRows,