@shop-os/modelkit 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1731,6 +1731,369 @@ var ELEVENLABS_VOICES = [
1731
1731
  previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
1732
1732
  }
1733
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"
1900
+ },
1901
+ {
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"
1908
+ },
1909
+ {
1910
+ id: "ec0718028a2445fb9be8e8bfb56a0150",
1911
+ name: "Rodrigo",
1912
+ gender: "male",
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"
1916
+ },
1917
+ {
1918
+ id: "10a3a20742114a4ea6dd441e7591850f",
1919
+ name: "Manon",
1920
+ gender: "female",
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"
1924
+ },
1925
+ {
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",
1936
+ gender: "female",
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"
1940
+ },
1941
+ {
1942
+ id: "c1e7cc926aa5469aa966c353094d4b0b",
1943
+ name: "Lukas",
1944
+ gender: "male",
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"
1948
+ },
1949
+ {
1950
+ id: "b3c060cc41544a7da94a2c487647c902",
1951
+ name: "Let\xEDcia",
1952
+ gender: "female",
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"
1957
+ },
1958
+ {
1959
+ id: "add7bcb8d3c8423bbfa152ca232aad6e",
1960
+ name: "Ricardo",
1961
+ gender: "male",
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"
1966
+ },
1967
+ {
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"
1974
+ },
1975
+ {
1976
+ id: "297a6fd278df47c3b9da9bfdf55ac89a",
1977
+ name: "Satoru",
1978
+ gender: "male",
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"
1982
+ },
1983
+ {
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"
1990
+ },
1991
+ {
1992
+ id: "74c6aba5cbf94a15bbdc547ffce5cb38",
1993
+ name: "Yutong",
1994
+ gender: "female",
1995
+ languages: ["zh"],
1996
+ description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
1997
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
1998
+ }
1999
+ ];
2000
+
2001
+ // src/catalog/speech-fish.ts
2002
+ var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
2003
+ var PER_CALL2 = { unit: "images" };
2004
+ var PER_REQUEST2 = { unit: "requests" };
2005
+ var TTS_MAX_CHARS = 1e4;
2006
+ function fishTts(id, label, providerModelId, description) {
2007
+ return {
2008
+ id,
2009
+ aliases: [],
2010
+ label,
2011
+ type: "speech",
2012
+ adapter: "fish",
2013
+ providerModelId,
2014
+ lifecycle: "active",
2015
+ exposure: [],
2016
+ constraints: {
2017
+ voices: FISH_VOICES,
2018
+ outputFormats: ["mp3", "wav"],
2019
+ supports: [],
2020
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2021
+ },
2022
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2023
+ usage: PER_CALL2,
2024
+ pricingKind: "flat",
2025
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2026
+ capabilities: { customVoices: true }
2027
+ };
2028
+ }
2029
+ var FISH_MODELS = [
2030
+ fishTts(
2031
+ "fish-s2.1-pro",
2032
+ "Fish Audio S2.1 Pro",
2033
+ "s2.1-pro",
2034
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2035
+ ),
2036
+ fishTts(
2037
+ "fish-s2.1-pro-free",
2038
+ "Fish Audio S2.1 Pro Free",
2039
+ "s2.1-pro-free",
2040
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2041
+ ),
2042
+ fishTts(
2043
+ "fish-drama-3",
2044
+ "Fish Audio Drama 3",
2045
+ "drama-3",
2046
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2047
+ ),
2048
+ {
2049
+ id: "fish-voice-clone",
2050
+ aliases: [],
2051
+ label: "Fish Audio Voice Clone",
2052
+ type: "voice-clone",
2053
+ adapter: "fish",
2054
+ providerModelId: "voice-clone",
2055
+ lifecycle: "active",
2056
+ exposure: [],
2057
+ constraints: {
2058
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2059
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2060
+ supports: []
2061
+ },
2062
+ defaults: {},
2063
+ usage: PER_REQUEST2,
2064
+ pricingKind: "flat",
2065
+ display: {
2066
+ provider: "fishaudio",
2067
+ logo: FISH_LOGO,
2068
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2069
+ },
2070
+ capabilities: {}
2071
+ },
2072
+ {
2073
+ id: "fish-voice-design-1",
2074
+ aliases: [],
2075
+ label: "Fish Audio Voice Design",
2076
+ type: "voice-design",
2077
+ adapter: "fish",
2078
+ providerModelId: "voice-design-1",
2079
+ lifecycle: "active",
2080
+ exposure: [],
2081
+ constraints: {
2082
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2083
+ supports: [],
2084
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2085
+ },
2086
+ defaults: {},
2087
+ usage: PER_REQUEST2,
2088
+ pricingKind: "flat",
2089
+ display: {
2090
+ provider: "fishaudio",
2091
+ logo: FISH_LOGO,
2092
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2093
+ },
2094
+ capabilities: {}
2095
+ }
2096
+ ];
1734
2097
 
1735
2098
  // src/catalog/voices-gemini.ts
1736
2099
  var GEMINI_TTS_VOICES = [
@@ -3307,11 +3670,11 @@ var MINIMAX_VOICES = [
3307
3670
  ];
3308
3671
 
3309
3672
  // src/catalog/media-nodes.ts
3310
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3673
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3311
3674
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3312
3675
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3313
3676
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3314
- var PER_CALL = { unit: "images" };
3677
+ var PER_CALL3 = { unit: "images" };
3315
3678
  var EXPOSURE4 = ["cowork", "space_builder"];
3316
3679
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3317
3680
  function elevenLabsTts(tts) {
@@ -3332,9 +3695,9 @@ function elevenLabsTts(tts) {
3332
3695
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3333
3696
  },
3334
3697
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3335
- usage: PER_CALL,
3698
+ usage: PER_CALL3,
3336
3699
  pricingKind: "flat",
3337
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3700
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3338
3701
  capabilities: {}
3339
3702
  };
3340
3703
  }
@@ -3356,7 +3719,7 @@ function geminiTts(id, label, description) {
3356
3719
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3357
3720
  },
3358
3721
  defaults: { voice: "Kore" },
3359
- usage: PER_CALL,
3722
+ usage: PER_CALL3,
3360
3723
  pricingKind: "flat",
3361
3724
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3362
3725
  capabilities: {}
@@ -3379,7 +3742,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3379
3742
  },
3380
3743
  defaults: {},
3381
3744
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3382
- usage: PER_CALL,
3745
+ usage: PER_CALL3,
3383
3746
  pricingKind: "flat",
3384
3747
  display: { provider: "sync", logo: SYNC_LOGO, description },
3385
3748
  capabilities: { acceptsSourceVideo: true }
@@ -3440,7 +3803,7 @@ var MEDIA_NODE_MODELS = [
3440
3803
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3441
3804
  },
3442
3805
  defaults: { voice: "Wise_Woman" },
3443
- usage: PER_CALL,
3806
+ usage: PER_CALL3,
3444
3807
  pricingKind: "flat",
3445
3808
  display: {
3446
3809
  provider: "minimax",
@@ -3467,11 +3830,11 @@ var MEDIA_NODE_MODELS = [
3467
3830
  supports: []
3468
3831
  },
3469
3832
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3470
- usage: PER_CALL,
3833
+ usage: PER_CALL3,
3471
3834
  pricingKind: "flat",
3472
3835
  display: {
3473
3836
  provider: "elevenlabs",
3474
- logo: ELEVENLABS_LOGO,
3837
+ logo: ELEVENLABS_LOGO2,
3475
3838
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3476
3839
  },
3477
3840
  capabilities: {}
@@ -3494,11 +3857,11 @@ var MEDIA_NODE_MODELS = [
3494
3857
  supports: []
3495
3858
  },
3496
3859
  defaults: {},
3497
- usage: PER_CALL,
3860
+ usage: PER_CALL3,
3498
3861
  pricingKind: "flat",
3499
3862
  display: {
3500
3863
  provider: "elevenlabs",
3501
- logo: ELEVENLABS_LOGO,
3864
+ logo: ELEVENLABS_LOGO2,
3502
3865
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3503
3866
  },
3504
3867
  capabilities: { acceptsSourceVideo: true }
@@ -3541,7 +3904,7 @@ var MEDIA_NODE_MODELS = [
3541
3904
  supports: []
3542
3905
  },
3543
3906
  defaults: {},
3544
- usage: PER_CALL,
3907
+ usage: PER_CALL3,
3545
3908
  pricingKind: "flat",
3546
3909
  display: {
3547
3910
  provider: "veed",
@@ -3593,16 +3956,18 @@ var MEDIA_NODE_MODELS = [
3593
3956
  supports: []
3594
3957
  },
3595
3958
  defaults: {},
3596
- usage: PER_CALL,
3959
+ usage: PER_CALL3,
3597
3960
  pricingKind: "flat",
3598
3961
  display: {
3599
3962
  provider: "elevenlabs",
3600
- logo: ELEVENLABS_LOGO,
3963
+ logo: ELEVENLABS_LOGO2,
3601
3964
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
3602
3965
  },
3603
3966
  capabilities: {}
3604
3967
  },
3605
- SAM_3_IMAGE
3968
+ SAM_3_IMAGE,
3969
+ ...FISH_MODELS,
3970
+ ...ELEVENLABS_DIRECT_MODELS
3606
3971
  ];
3607
3972
 
3608
3973
  // src/catalog/model3d.ts
@@ -3798,7 +4163,7 @@ var MODEL3D_MODELS = [
3798
4163
 
3799
4164
  // src/catalog/other.ts
3800
4165
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3801
- var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4166
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3802
4167
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3803
4168
  var OTHER_MODELS = [
3804
4169
  {
@@ -3963,7 +4328,7 @@ var OTHER_MODELS = [
3963
4328
  pricingKind: "flat",
3964
4329
  display: {
3965
4330
  provider: "elevenlabs",
3966
- logo: ELEVENLABS_LOGO2,
4331
+ logo: ELEVENLABS_LOGO3,
3967
4332
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
3968
4333
  },
3969
4334
  capabilities: {}
@@ -4015,7 +4380,7 @@ var OTHER_MODELS = [
4015
4380
  pricingKind: "flat",
4016
4381
  display: {
4017
4382
  provider: "elevenlabs",
4018
- logo: ELEVENLABS_LOGO2,
4383
+ logo: ELEVENLABS_LOGO3,
4019
4384
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4020
4385
  },
4021
4386
  capabilities: {}
@@ -7237,7 +7602,9 @@ var ADAPTER_IDS = [
7237
7602
  "prodia",
7238
7603
  "higgsfield",
7239
7604
  "xai-video",
7240
- "luma"
7605
+ "luma",
7606
+ "fish",
7607
+ "elevenlabs"
7241
7608
  ];
7242
7609
  var ModelTypeSchema = z3.enum([
7243
7610
  "text",
@@ -7254,6 +7621,8 @@ var ModelTypeSchema = z3.enum([
7254
7621
  "dubbing",
7255
7622
  "lipsync",
7256
7623
  "transcription",
7624
+ "voice-clone",
7625
+ "voice-design",
7257
7626
  "model3d"
7258
7627
  ]);
7259
7628
  var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
@@ -7429,6 +7798,10 @@ var ModelConstraintsSchema = z3.looseObject({
7429
7798
  supports: z3.array(SupportedOptionSchema).optional(),
7430
7799
  ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
7431
7800
  voices: z3.array(VoiceOptionSchema).optional(),
7801
+ voiceDesign: z3.object({
7802
+ maxCandidates: z3.number().int().positive(),
7803
+ previewMaxChars: z3.number().int().positive()
7804
+ }).optional(),
7432
7805
  languages: z3.array(LanguageOptionSchema).optional(),
7433
7806
  outputFormats: z3.array(z3.string().min(1)).min(1).optional(),
7434
7807
  sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
@@ -7527,6 +7900,7 @@ var CatalogDisplaySchema = z3.looseObject({
7527
7900
  });
7528
7901
  var CatalogCapabilitiesSchema = z3.looseObject({
7529
7902
  acceptsSourceVideo: z3.boolean().optional(),
7903
+ customVoices: z3.boolean().optional(),
7530
7904
  videoEdit: z3.boolean().optional(),
7531
7905
  framesExcludeReferences: z3.boolean().optional(),
7532
7906
  sourceVideoExcludesFrames: z3.boolean().optional(),
@@ -8046,7 +8420,7 @@ var errorCodes = z6.object({
8046
8420
  type: z6.string().optional(),
8047
8421
  error: z6.object({ code: z6.string().optional(), type: z6.string().optional() }).optional()
8048
8422
  });
8049
- var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
8423
+ var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
8050
8424
  var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
8051
8425
  function billingCode(body) {
8052
8426
  const parsed = errorCodes.safeParse(body);
@@ -8443,16 +8817,16 @@ async function generateSeedreamImage(req, ctx) {
8443
8817
  } else {
8444
8818
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8445
8819
  }
8446
- const usage3 = {
8820
+ const usage5 = {
8447
8821
  model: modelId,
8448
8822
  provider: "ark",
8449
8823
  modality: "IMAGE",
8450
8824
  unit: "images",
8451
8825
  quantity: 1
8452
8826
  };
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 };
8827
+ if (req.size !== void 0) usage5.imageSize = req.size;
8828
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8829
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8456
8830
  }
8457
8831
  var SeedanceUsageSchema = z7.object({
8458
8832
  total_tokens: z7.number().optional(),
@@ -8493,7 +8867,7 @@ function seedanceErrorMessage(error, status) {
8493
8867
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8494
8868
  return `Seedance task ${status}`;
8495
8869
  }
8496
- function seedanceJob(ctx, key, jobId, usage3) {
8870
+ function seedanceJob(ctx, key, jobId, usage5) {
8497
8871
  const modelId = ctx.model.id;
8498
8872
  const fetchStatus = async () => {
8499
8873
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8543,21 +8917,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
8543
8917
  modelId
8544
8918
  );
8545
8919
  if (polled.duration !== void 0 && polled.duration > 0) {
8546
- usage3.quantity = polled.duration;
8547
- usage3.durationSeconds = polled.duration;
8920
+ usage5.quantity = polled.duration;
8921
+ usage5.durationSeconds = polled.duration;
8548
8922
  }
8549
8923
  const rendered = VideoResolutionSchema.safeParse(
8550
8924
  polled.resolution?.toLowerCase()
8551
8925
  );
8552
- if (rendered.success) usage3.resolution = rendered.data;
8926
+ if (rendered.success) usage5.resolution = rendered.data;
8553
8927
  const tokens = polled.usage;
8554
8928
  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;
8929
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8930
+ usage5.outputTokens = tokens.completion_tokens;
8557
8931
  }
8558
8932
  return {
8559
8933
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8560
- usage: usage3,
8934
+ usage: usage5,
8561
8935
  raw: polled
8562
8936
  };
8563
8937
  }
@@ -8663,8 +9037,8 @@ async function generateSeedanceVideo(req, ctx) {
8663
9037
  );
8664
9038
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8665
9039
  const jobId = submit.id;
8666
- const usage3 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8667
- return seedanceJob(ctx, key, jobId, usage3);
9040
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9041
+ return seedanceJob(ctx, key, jobId, usage5);
8668
9042
  }
8669
9043
 
8670
9044
  // src/adapters/fal.ts
@@ -10152,7 +10526,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10152
10526
  return { bytes, mime: mime || "image/png" };
10153
10527
  })
10154
10528
  );
10155
- const usage3 = {
10529
+ const usage5 = {
10156
10530
  model: ctx.model.id,
10157
10531
  provider: "fal",
10158
10532
  modality: "IMAGE",
@@ -10160,9 +10534,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10160
10534
  quantity: images.length
10161
10535
  };
10162
10536
  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 };
10537
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10538
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10539
+ const result = { images, usage: usage5, raw: payload };
10166
10540
  const remote = files.find((f) => !f.url.startsWith("data:"));
10167
10541
  if (remote !== void 0) result.outputUrl = remote.url;
10168
10542
  return result;
@@ -12325,14 +12699,570 @@ function planUsage(ctx, plan4) {
12325
12699
  };
12326
12700
  }
12327
12701
 
12328
- // src/adapters/google-genai.ts
12702
+ // src/adapters/elevenlabs.ts
12703
+ import { z as z21 } from "zod";
12704
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12705
+ var DEFAULT_FORMAT = "mp3_44100_128";
12706
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12707
+ var ELEVENLABS_IVC = "ivc";
12708
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12709
+ function elevenLabsRowRefusal(row2) {
12710
+ const id = row2.providerModelId;
12711
+ if (row2.type === "speech") {
12712
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12713
+ }
12714
+ if (row2.type === "voice-clone") {
12715
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12716
+ }
12717
+ return `elevenlabs has no ${row2.type} rows`;
12718
+ }
12719
+ function elevenLabsError(ctx, code, message) {
12720
+ return new ModelKitError({
12721
+ code,
12722
+ message,
12723
+ provider: "elevenlabs",
12724
+ model: ctx.model.id,
12725
+ retryable: false
12726
+ });
12727
+ }
12728
+ function checkRow(ctx, type) {
12729
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12730
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12731
+ throw elevenLabsError(
12732
+ ctx,
12733
+ "unsupported_option",
12734
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12735
+ );
12736
+ }
12737
+ }
12738
+ function checkVoiceId(ctx, field, id) {
12739
+ if (!VOICE_ID.test(id))
12740
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12741
+ return id;
12742
+ }
12743
+ function elevenLabsKey(ctx) {
12744
+ const key = ctx.keys.elevenlabs;
12745
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12746
+ return key;
12747
+ }
12748
+ function elevenLabsUrl(ctx, path) {
12749
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12750
+ }
12751
+ var errorDetail = z21.object({
12752
+ detail: z21.object({ status: z21.string(), message: z21.string().optional() })
12753
+ });
12754
+ function errorStatus(body) {
12755
+ const parsed = errorDetail.safeParse(body);
12756
+ return parsed.success ? parsed.data.detail : void 0;
12757
+ }
12758
+ function classifyResponse(ctx, status, body) {
12759
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12760
+ const detail = errorStatus(body);
12761
+ if (detail?.status === "voice_limit_reached") {
12762
+ return new ModelKitError({
12763
+ code: "provider_rejected",
12764
+ message: detail.message ?? "ElevenLabs voice limit reached",
12765
+ provider: "elevenlabs",
12766
+ model: ctx.model.id,
12767
+ status,
12768
+ body,
12769
+ cause: error,
12770
+ retryable: false
12771
+ });
12772
+ }
12773
+ if (detail?.status === "quota_exceeded") {
12774
+ return new ModelKitError({
12775
+ code: "provider_billing",
12776
+ message: error.message,
12777
+ provider: "elevenlabs",
12778
+ model: ctx.model.id,
12779
+ status,
12780
+ body,
12781
+ cause: error,
12782
+ retryable: false
12783
+ });
12784
+ }
12785
+ return error;
12786
+ }
12787
+ async function elevenLabsFetch(ctx, path, init) {
12788
+ throwIfAborted(ctx.signal);
12789
+ const request = {
12790
+ method: init.method,
12791
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12792
+ };
12793
+ if (init.body !== void 0) request.body = init.body;
12794
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12795
+ let res;
12796
+ try {
12797
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12798
+ } catch (cause) {
12799
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12800
+ }
12801
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12802
+ return res;
12803
+ }
12804
+ function usage2(ctx) {
12805
+ return {
12806
+ model: ctx.model.id,
12807
+ provider: "elevenlabs",
12808
+ modality: "AUDIO",
12809
+ unit: ctx.model.usage.unit,
12810
+ quantity: 1
12811
+ };
12812
+ }
12813
+ function audioMime(res) {
12814
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12815
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12816
+ }
12817
+ async function generateSpeech(req, ctx) {
12818
+ checkRow(ctx, "speech");
12819
+ const voice = req.customVoice ?? req.voice;
12820
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12821
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12822
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12823
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12824
+ if (req.language !== void 0) body.language_code = req.language;
12825
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12826
+ const { bytes, mime } = await withRetry(
12827
+ async () => {
12828
+ const res = await elevenLabsFetch(ctx, path, {
12829
+ method: "POST",
12830
+ headers: { "Content-Type": "application/json" },
12831
+ body: JSON.stringify(body)
12832
+ });
12833
+ let audio;
12834
+ try {
12835
+ audio = new Uint8Array(await res.arrayBuffer());
12836
+ } catch (cause) {
12837
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12838
+ }
12839
+ return { bytes: audio, mime: audioMime(res) };
12840
+ },
12841
+ mediaRetryOptions(ctx.call, ctx.signal)
12842
+ );
12843
+ if (bytes.byteLength === 0)
12844
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12845
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12846
+ }
12847
+ var createdVoiceSchema = z21.object({
12848
+ voice_id: z21.string().min(1),
12849
+ requires_verification: z21.boolean().optional().catch(void 0)
12850
+ });
12851
+ function sampleMime(mime) {
12852
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12853
+ }
12854
+ function fileName(index, mime, ref) {
12855
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12856
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
12857
+ const ext = fromMime || fromUrl?.toLowerCase();
12858
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
12859
+ }
12860
+ async function cloneForm(req, ctx) {
12861
+ if (req.samples.length === 0)
12862
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
12863
+ if (req.samples.some((s) => s.designSignature?.trim())) {
12864
+ throw elevenLabsError(
12865
+ ctx,
12866
+ "unsupported_option",
12867
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
12868
+ );
12869
+ }
12870
+ const form = new FormData();
12871
+ form.append("name", req.title.trim());
12872
+ if (req.description?.trim()) form.append("description", req.description.trim());
12873
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
12874
+ for (const [index, sample] of req.samples.entries()) {
12875
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
12876
+ signal: ctx.signal,
12877
+ provider: "elevenlabs",
12878
+ model: ctx.model.id
12879
+ });
12880
+ const type = sampleMime(mime);
12881
+ const audio = new Blob([new Uint8Array(bytes)], { type });
12882
+ form.append("files", audio, fileName(index, type, sample.audio));
12883
+ }
12884
+ return form;
12885
+ }
12886
+ async function onlyRateLimitRetries(fn) {
12887
+ try {
12888
+ return await fn();
12889
+ } catch (cause) {
12890
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
12891
+ throw cause;
12892
+ throw new ModelKitError({
12893
+ code: cause.code,
12894
+ message: cause.message,
12895
+ ...cause.provider !== void 0 && { provider: cause.provider },
12896
+ ...cause.model !== void 0 && { model: cause.model },
12897
+ ...cause.status !== void 0 && { status: cause.status },
12898
+ ...cause.body !== void 0 && { body: cause.body },
12899
+ cause,
12900
+ retryable: false
12901
+ });
12902
+ }
12903
+ }
12904
+ async function createVoice(req, ctx) {
12905
+ checkRow(ctx, "voice-clone");
12906
+ const form = await cloneForm(req, ctx);
12907
+ const res = await withRetry(
12908
+ () => onlyRateLimitRetries(
12909
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
12910
+ ),
12911
+ mediaRetryOptions(ctx.call, ctx.signal)
12912
+ );
12913
+ const raw = await readBody(res);
12914
+ const parsed = createdVoiceSchema.safeParse(raw);
12915
+ if (!parsed.success) {
12916
+ throw new ModelKitError({
12917
+ code: "provider_rejected",
12918
+ message: "ElevenLabs returned no voice id",
12919
+ provider: "elevenlabs",
12920
+ model: ctx.model.id,
12921
+ status: res.status,
12922
+ body: raw,
12923
+ retryable: false
12924
+ });
12925
+ }
12926
+ return {
12927
+ voiceId: parsed.data.voice_id,
12928
+ state: parsed.data.requires_verification === true ? "created" : "trained",
12929
+ usage: usage2(ctx),
12930
+ raw
12931
+ };
12932
+ }
12933
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
12934
+ "voice_not_found",
12935
+ "voice_does_not_exist"
12936
+ ]);
12937
+ function notFound(cause) {
12938
+ if (cause.status === 404) return true;
12939
+ const status = errorStatus(cause.body)?.status;
12940
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
12941
+ }
12942
+ async function deleteVoice(req, ctx) {
12943
+ checkRow(ctx, "voice-clone");
12944
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
12945
+ let attempts = 0;
12946
+ await withRetry(
12947
+ async () => {
12948
+ attempts += 1;
12949
+ try {
12950
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
12951
+ } catch (cause) {
12952
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
12953
+ if (attempts > 1) return;
12954
+ throw new ModelKitError({
12955
+ code: "provider_rejected",
12956
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
12957
+ provider: "elevenlabs",
12958
+ model: ctx.model.id,
12959
+ ...cause.status !== void 0 && { status: cause.status },
12960
+ cause,
12961
+ retryable: false
12962
+ });
12963
+ }
12964
+ },
12965
+ mediaRetryOptions(ctx.call, ctx.signal)
12966
+ );
12967
+ }
12968
+ var elevenLabsAdapter = {
12969
+ id: "elevenlabs",
12970
+ generateSpeech,
12971
+ createVoice,
12972
+ deleteVoice
12973
+ };
12974
+
12975
+ // src/adapters/fish.ts
12329
12976
  import { z as z22 } from "zod";
12977
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
12978
+ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
12979
+ "s2.1-pro",
12980
+ "s2.1-pro-free",
12981
+ "drama-3"
12982
+ ]);
12983
+ var FISH_VOICE_CLONE = "voice-clone";
12984
+ var FISH_VOICE_DESIGN = "voice-design-1";
12985
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
12986
+ function fishRowRefusal(row2) {
12987
+ const id = row2.providerModelId;
12988
+ if (row2.type === "speech") {
12989
+ return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
12990
+ }
12991
+ if (row2.type === "voice-clone") {
12992
+ return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
12993
+ }
12994
+ if (row2.type === "voice-design") {
12995
+ return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
12996
+ }
12997
+ return `fish has no ${row2.type} rows`;
12998
+ }
12999
+ function fishError(ctx, code, message) {
13000
+ return new ModelKitError({
13001
+ code,
13002
+ message,
13003
+ provider: "fish",
13004
+ model: ctx.model.id,
13005
+ retryable: false
13006
+ });
13007
+ }
13008
+ function checkRow2(ctx, type) {
13009
+ const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
13010
+ if (ctx.model.type !== type || refusal2 !== void 0) {
13011
+ throw fishError(
13012
+ ctx,
13013
+ "unsupported_option",
13014
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
13015
+ );
13016
+ }
13017
+ }
13018
+ function checkVoiceId2(ctx, field, id) {
13019
+ if (!VOICE_ID2.test(id))
13020
+ throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
13021
+ return id;
13022
+ }
13023
+ function fishKey(ctx) {
13024
+ const key = ctx.keys.fish;
13025
+ if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
13026
+ return key;
13027
+ }
13028
+ function fishUrl(ctx, path) {
13029
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
13030
+ }
13031
+ async function fishFetch(ctx, path, init) {
13032
+ throwIfAborted(ctx.signal);
13033
+ const request = {
13034
+ method: init.method,
13035
+ headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
13036
+ };
13037
+ if (init.body !== void 0) request.body = init.body;
13038
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
13039
+ let res;
13040
+ try {
13041
+ res = await ctx.fetch(fishUrl(ctx, path), request);
13042
+ } catch (cause) {
13043
+ throw classifyThrown("fish", cause, ctx.model.id);
13044
+ }
13045
+ if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
13046
+ return res;
13047
+ }
13048
+ function usage3(ctx) {
13049
+ return {
13050
+ model: ctx.model.id,
13051
+ provider: "fish",
13052
+ modality: "AUDIO",
13053
+ unit: ctx.model.usage.unit,
13054
+ quantity: 1
13055
+ };
13056
+ }
13057
+ function audioMime2(res, format) {
13058
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
13059
+ if (header?.startsWith("audio/")) return header;
13060
+ return format === "wav" ? "audio/wav" : "audio/mpeg";
13061
+ }
13062
+ async function generateSpeech2(req, ctx) {
13063
+ checkRow2(ctx, "speech");
13064
+ const format = req.outputFormat ?? "mp3";
13065
+ const body = { text: req.text, format };
13066
+ const voice = req.customVoice ?? req.voice;
13067
+ if (voice !== void 0) {
13068
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
13069
+ }
13070
+ if (req.language !== void 0) body.language = req.language;
13071
+ const { bytes, mime } = await withRetry(
13072
+ async () => {
13073
+ const res = await fishFetch(ctx, "/v1/tts", {
13074
+ method: "POST",
13075
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
13076
+ body: JSON.stringify(body)
13077
+ });
13078
+ let audio;
13079
+ try {
13080
+ audio = new Uint8Array(await res.arrayBuffer());
13081
+ } catch (cause) {
13082
+ throw classifyThrown("fish", cause, ctx.model.id);
13083
+ }
13084
+ return { bytes: audio, mime: audioMime2(res, format) };
13085
+ },
13086
+ mediaRetryOptions(ctx.call, ctx.signal)
13087
+ );
13088
+ if (bytes.byteLength === 0)
13089
+ throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
13090
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
13091
+ }
13092
+ var createdModelSchema = z22.object({
13093
+ _id: z22.string().min(1),
13094
+ state: z22.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
13095
+ });
13096
+ function fileName2(index, mime) {
13097
+ const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
13098
+ return `sample-${index + 1}.${ext}`;
13099
+ }
13100
+ function allOrNone(ctx, field, values) {
13101
+ const set = values.filter((v) => v !== void 0 && v.trim() !== "");
13102
+ if (set.length === 0) return [];
13103
+ if (set.length !== values.length) {
13104
+ throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
13105
+ }
13106
+ return set;
13107
+ }
13108
+ async function cloneForm2(req, ctx) {
13109
+ if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
13110
+ const transcripts = allOrNone(
13111
+ ctx,
13112
+ "transcript",
13113
+ req.samples.map((s) => s.transcript)
13114
+ );
13115
+ const signatures = allOrNone(
13116
+ ctx,
13117
+ "designSignature",
13118
+ req.samples.map((s) => s.designSignature)
13119
+ );
13120
+ const form = new FormData();
13121
+ form.append("type", "tts");
13122
+ form.append("train_mode", "fast");
13123
+ form.append("visibility", "private");
13124
+ form.append("title", req.title.trim());
13125
+ if (req.description?.trim()) form.append("description", req.description.trim());
13126
+ if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
13127
+ for (const [index, sample] of req.samples.entries()) {
13128
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
13129
+ signal: ctx.signal,
13130
+ provider: "fish",
13131
+ model: ctx.model.id
13132
+ });
13133
+ const audio = new Blob([new Uint8Array(bytes)], { type: mime });
13134
+ form.append("voices", audio, fileName2(index, mime));
13135
+ }
13136
+ for (const text2 of transcripts) form.append("texts", text2.trim());
13137
+ for (const signature of signatures) form.append("voice_design_signatures", signature);
13138
+ return form;
13139
+ }
13140
+ async function onlyRateLimitRetries2(fn) {
13141
+ try {
13142
+ return await fn();
13143
+ } catch (cause) {
13144
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
13145
+ throw cause;
13146
+ throw new ModelKitError({
13147
+ code: cause.code,
13148
+ message: cause.message,
13149
+ ...cause.provider !== void 0 && { provider: cause.provider },
13150
+ ...cause.model !== void 0 && { model: cause.model },
13151
+ ...cause.status !== void 0 && { status: cause.status },
13152
+ ...cause.body !== void 0 && { body: cause.body },
13153
+ cause,
13154
+ retryable: false
13155
+ });
13156
+ }
13157
+ }
13158
+ async function createVoice2(req, ctx) {
13159
+ checkRow2(ctx, "voice-clone");
13160
+ const form = await cloneForm2(req, ctx);
13161
+ const res = await withRetry(
13162
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13163
+ mediaRetryOptions(ctx.call, ctx.signal)
13164
+ );
13165
+ const raw = await readBody(res);
13166
+ const parsed = createdModelSchema.safeParse(raw);
13167
+ if (!parsed.success) {
13168
+ throw new ModelKitError({
13169
+ code: "provider_rejected",
13170
+ message: "Fish returned no voice id",
13171
+ provider: "fish",
13172
+ model: ctx.model.id,
13173
+ status: res.status,
13174
+ body: raw,
13175
+ retryable: false
13176
+ });
13177
+ }
13178
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
13179
+ if (parsed.data.state !== void 0) result.state = parsed.data.state;
13180
+ return result;
13181
+ }
13182
+ var designSchema = z22.object({
13183
+ candidates: z22.array(
13184
+ z22.looseObject({
13185
+ id: z22.string().min(1),
13186
+ index: z22.number().int(),
13187
+ audio_base64: z22.string().min(1),
13188
+ duration_ms: z22.number().nonnegative(),
13189
+ signature: z22.string().min(1).optional()
13190
+ })
13191
+ ).min(1)
13192
+ });
13193
+ async function designVoice(req, ctx) {
13194
+ checkRow2(ctx, "voice-design");
13195
+ const body = { instruction: req.prompt.trim() };
13196
+ if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
13197
+ if (req.language !== void 0) body.language = req.language;
13198
+ if (req.count !== void 0) body.n = req.count;
13199
+ if (req.seed !== void 0) body.seed = req.seed;
13200
+ const raw = await withRetry(
13201
+ async () => {
13202
+ const res = await fishFetch(ctx, "/v1/voice-design", {
13203
+ method: "POST",
13204
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
13205
+ body: JSON.stringify(body)
13206
+ });
13207
+ return readBody(res);
13208
+ },
13209
+ mediaRetryOptions(ctx.call, ctx.signal)
13210
+ );
13211
+ const parsed = designSchema.safeParse(raw);
13212
+ if (!parsed.success) {
13213
+ throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
13214
+ }
13215
+ const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
13216
+ audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
13217
+ durationSeconds: c.duration_ms / 1e3,
13218
+ // The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
13219
+ // rejects a clone whose signature does not verify, so a wrong one fails loudly.
13220
+ signature: c.signature ?? c.id
13221
+ }));
13222
+ return { candidates, usage: usage3(ctx) };
13223
+ }
13224
+ async function deleteVoice2(req, ctx) {
13225
+ checkRow2(ctx, "voice-clone");
13226
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
13227
+ let attempts = 0;
13228
+ await withRetry(
13229
+ async () => {
13230
+ attempts += 1;
13231
+ try {
13232
+ await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
13233
+ } catch (cause) {
13234
+ if (!isModelKitError(cause) || cause.status !== 404) throw cause;
13235
+ if (attempts > 1) return;
13236
+ throw new ModelKitError({
13237
+ code: "provider_rejected",
13238
+ message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13239
+ provider: "fish",
13240
+ model: ctx.model.id,
13241
+ status: 404,
13242
+ cause,
13243
+ retryable: false
13244
+ });
13245
+ }
13246
+ },
13247
+ mediaRetryOptions(ctx.call, ctx.signal)
13248
+ );
13249
+ }
13250
+ var fishAdapter = {
13251
+ id: "fish",
13252
+ generateSpeech: generateSpeech2,
13253
+ createVoice: createVoice2,
13254
+ designVoice,
13255
+ deleteVoice: deleteVoice2
13256
+ };
13257
+
13258
+ // src/adapters/google-genai.ts
13259
+ import { z as z24 } from "zod";
12330
13260
  import {
12331
13261
  GoogleGenAI
12332
13262
  } from "@google/genai";
12333
13263
 
12334
13264
  // src/adapters/google-files.ts
12335
- import { z as z21 } from "zod";
13265
+ import { z as z23 } from "zod";
12336
13266
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12337
13267
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12338
13268
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12342,17 +13272,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12342
13272
  "binary/octet-stream",
12343
13273
  "application/binary"
12344
13274
  ]);
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()
13275
+ var uploadedFileSchema = z23.object({
13276
+ file: z23.object({
13277
+ uri: z23.string().optional(),
13278
+ name: z23.string().optional(),
13279
+ state: z23.string().optional(),
13280
+ mimeType: z23.string().optional()
12351
13281
  }).optional()
12352
13282
  });
12353
- var fileStateSchema = z21.object({
12354
- state: z21.string().optional(),
12355
- error: z21.object({ message: z21.string().optional() }).optional()
13283
+ var fileStateSchema = z23.object({
13284
+ state: z23.string().optional(),
13285
+ error: z23.object({ message: z23.string().optional() }).optional()
12356
13286
  });
12357
13287
  function resolveMime(declared, fallback) {
12358
13288
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -12459,7 +13389,7 @@ async function startAndUpload(bytes, mimeType, opts) {
12459
13389
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
12460
13390
  return ref;
12461
13391
  }
12462
- async function waitForActive(fileName, opts) {
13392
+ async function waitForActive(fileName3, opts) {
12463
13393
  const pollOptions2 = {
12464
13394
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
12465
13395
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -12472,14 +13402,14 @@ async function waitForActive(fileName, opts) {
12472
13402
  retryInit.signal = opts.signal;
12473
13403
  }
12474
13404
  await pollUntil(async () => {
12475
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, retryInit);
13405
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
12476
13406
  if (res.ok) {
12477
13407
  const json = fileStateSchema.parse(await res.json());
12478
13408
  if (json.state === "ACTIVE") return true;
12479
13409
  if (json.state === "FAILED") {
12480
13410
  throw classifyHttpError(
12481
13411
  void 0,
12482
- `Files API processing failed for ${fileName}: ${json.error?.message ?? "unknown error"}`,
13412
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
12483
13413
  "google-genai",
12484
13414
  opts.model
12485
13415
  );
@@ -12491,9 +13421,9 @@ async function waitForActive(fileName, opts) {
12491
13421
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
12492
13422
  }, pollOptions2);
12493
13423
  }
12494
- async function deleteGoogleFile(fileName, apiKey, fetchImpl) {
13424
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
12495
13425
  try {
12496
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, {
13426
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
12497
13427
  method: "DELETE",
12498
13428
  headers: { "x-goog-api-key": apiKey }
12499
13429
  });
@@ -12573,7 +13503,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
12573
13503
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
12574
13504
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
12575
13505
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
12576
- var errorTextSchema = z22.string();
13506
+ var errorTextSchema = z24.string();
12577
13507
  function isGoogleGenaiVideoKnown(providerModelId) {
12578
13508
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
12579
13509
  }
@@ -12768,7 +13698,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12768
13698
  }
12769
13699
  };
12770
13700
  const jobId = operation.name ?? crypto.randomUUID();
12771
- const usage3 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13701
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
12772
13702
  return {
12773
13703
  jobId,
12774
13704
  async poll() {
@@ -12806,7 +13736,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12806
13736
  modelId
12807
13737
  );
12808
13738
  }
12809
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage3, raw: finished };
13739
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
12810
13740
  }
12811
13741
  };
12812
13742
  }
@@ -12917,7 +13847,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
12917
13847
  return file.fileUri;
12918
13848
  };
12919
13849
  const cleanupUploads = async () => {
12920
- for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
13850
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
12921
13851
  };
12922
13852
  const callCreate = (input) => client2.interactions.create(
12923
13853
  previousId !== void 0 ? {
@@ -13011,7 +13941,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13011
13941
  if (!(extend && !chained)) await cleanupUploads();
13012
13942
  }
13013
13943
  const jobId = interaction.id ?? crypto.randomUUID();
13014
- const usage3 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13944
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13015
13945
  const getInteraction = async () => {
13016
13946
  try {
13017
13947
  const getParams = { stream: false };
@@ -13059,7 +13989,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13059
13989
  bytes: Buffer.from(video.data, "base64"),
13060
13990
  mime: video.mime_type ?? "video/mp4"
13061
13991
  },
13062
- usage: usage3,
13992
+ usage: usage5,
13063
13993
  raw: done,
13064
13994
  providerRef
13065
13995
  };
@@ -13067,7 +13997,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13067
13997
  if (video.uri)
13068
13998
  return {
13069
13999
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13070
- usage: usage3,
14000
+ usage: usage5,
13071
14001
  raw: done,
13072
14002
  providerRef
13073
14003
  };
@@ -13237,15 +14167,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13237
14167
  // src/adapters/google-image.ts
13238
14168
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
13239
14169
  import { generateText } from "ai";
13240
- import { z as z23 } from "zod";
14170
+ import { z as z25 } from "zod";
13241
14171
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13242
14172
  var defaultGoogleImageDeps = {
13243
14173
  createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
13244
14174
  runTextGeneration: (opts) => generateText(opts)
13245
14175
  };
13246
- var causeChainNodeSchema = z23.object({
13247
- message: z23.string().optional(),
13248
- cause: z23.unknown().optional()
14176
+ var causeChainNodeSchema = z25.object({
14177
+ message: z25.string().optional(),
14178
+ cause: z25.unknown().optional()
13249
14179
  });
13250
14180
  function extractBlockReason(cause) {
13251
14181
  let current = cause;
@@ -13345,7 +14275,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13345
14275
  retryable: false
13346
14276
  });
13347
14277
  }
13348
- const usage3 = {
14278
+ const usage5 = {
13349
14279
  model: ctx.model.id,
13350
14280
  provider: "google-image",
13351
14281
  modality: "IMAGE",
@@ -13353,19 +14283,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13353
14283
  quantity: images.length,
13354
14284
  imageQuality: "auto"
13355
14285
  };
13356
- if (req.size !== void 0) usage3.imageSize = req.size;
14286
+ if (req.size !== void 0) usage5.imageSize = req.size;
13357
14287
  if (result.usage?.inputTokens !== void 0)
13358
- usage3.inputTokens = result.usage.inputTokens;
14288
+ usage5.inputTokens = result.usage.inputTokens;
13359
14289
  if (result.usage?.outputTokens !== void 0)
13360
- usage3.outputTokens = result.usage.outputTokens;
13361
- return { images, usage: usage3, raw: result };
14290
+ usage5.outputTokens = result.usage.outputTokens;
14291
+ return { images, usage: usage5, raw: result };
13362
14292
  }
13363
14293
  };
13364
14294
  }
13365
14295
  var googleImageAdapter = createGoogleImageAdapter();
13366
14296
 
13367
14297
  // src/adapters/higgsfield.ts
13368
- import { z as z24 } from "zod";
14298
+ import { z as z26 } from "zod";
13369
14299
 
13370
14300
  // src/adapters/higgsfield-motions.ts
13371
14301
  var MOTION_MAP = {
@@ -13584,14 +14514,14 @@ function klingEndpointFields(providerModelId) {
13584
14514
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
13585
14515
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
13586
14516
  }
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(),
14517
+ var klingCreateSchema = z26.object({ status_url: z26.string() });
14518
+ var klingStatusSchema = z26.object({
14519
+ status: z26.string().optional(),
14520
+ video: z26.object({ url: z26.string().optional() }).optional(),
13591
14521
  error: JsonValueSchema.optional()
13592
14522
  });
13593
- var errorMessageSchema = z24.object({ message: z24.string().optional() });
13594
- var textValueSchema = z24.string();
14523
+ var errorMessageSchema = z26.object({ message: z26.string().optional() });
14524
+ var textValueSchema = z26.string();
13595
14525
  function klingErrorDetail(error) {
13596
14526
  if (error === void 0) return "unknown_error";
13597
14527
  const asText = textValueSchema.safeParse(error);
@@ -13747,8 +14677,8 @@ async function generateKlingVideo(req, ctx) {
13747
14677
  }
13748
14678
  };
13749
14679
  }
13750
- var dopMotionOptionsSchema = z24.object({
13751
- modelkit: z24.object({ motion: z24.string().optional() }).optional()
14680
+ var dopMotionOptionsSchema = z26.object({
14681
+ modelkit: z26.object({ motion: z26.string().optional() }).optional()
13752
14682
  });
13753
14683
  function dopMotionId(ctx) {
13754
14684
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -13764,7 +14694,7 @@ function dopMotionId(ctx) {
13764
14694
  });
13765
14695
  return id;
13766
14696
  }
13767
- var jsonRecordSchema = z24.record(z24.string(), JsonValueSchema);
14697
+ var jsonRecordSchema = z26.record(z26.string(), JsonValueSchema);
13768
14698
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
13769
14699
  var DOP_NESTED_KEYS = ["video", "result", "results"];
13770
14700
  function dopUrl(body) {
@@ -13792,8 +14722,8 @@ function dopUrl(body) {
13792
14722
  }
13793
14723
  return void 0;
13794
14724
  }
13795
- var dopCreateSchema = z24.object({ id: z24.string() });
13796
- var dopStatusSchema = z24.object({ status: z24.string().optional() });
14725
+ var dopCreateSchema = z26.object({ id: z26.string() });
14726
+ var dopStatusSchema = z26.object({ status: z26.string().optional() });
13797
14727
  async function generateDopVideo(req, ctx) {
13798
14728
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
13799
14729
  if (!firstFrame) {
@@ -13920,7 +14850,7 @@ var higgsfieldAdapter = {
13920
14850
  };
13921
14851
 
13922
14852
  // src/adapters/luma.ts
13923
- import { z as z25 } from "zod";
14853
+ import { z as z27 } from "zod";
13924
14854
 
13925
14855
  // src/adapters/mp4-duration.ts
13926
14856
  function mp4DurationSeconds(bytes) {
@@ -13976,7 +14906,7 @@ function findBox(bytes, from, to, type) {
13976
14906
  }
13977
14907
 
13978
14908
  // src/adapters/luma.ts
13979
- var DEFAULT_BASE_URL = "https://agents.lumalabs.ai";
14909
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
13980
14910
  var IMAGE_POLL_INTERVAL_MS = 3e3;
13981
14911
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
13982
14912
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14005,7 +14935,7 @@ function lumaModel(ctx) {
14005
14935
  return ctx.model.providerModelId.toLowerCase();
14006
14936
  }
14007
14937
  function lumaBase(ctx) {
14008
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
14938
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14009
14939
  }
14010
14940
  function lumaKey(ctx) {
14011
14941
  const key = ctx.keys.luma;
@@ -14137,17 +15067,17 @@ function lumaReframeResolution(req, ctx) {
14137
15067
  });
14138
15068
  return "720p";
14139
15069
  }
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()
15070
+ var lumaGenerationSchema = z27.looseObject({
15071
+ id: z27.string(),
15072
+ state: z27.string().optional(),
15073
+ output: z27.array(
15074
+ z27.looseObject({
15075
+ type: z27.string().optional(),
15076
+ url: z27.string().optional()
14147
15077
  })
14148
15078
  ).optional(),
14149
- failure_reason: z25.string().optional().nullable(),
14150
- failure_code: z25.string().optional().nullable()
15079
+ failure_reason: z27.string().optional().nullable(),
15080
+ failure_code: z27.string().optional().nullable()
14151
15081
  });
14152
15082
  function lumaFailure(ctx, code, reason) {
14153
15083
  const detail = reason ?? code ?? "unknown_error";
@@ -14579,7 +15509,7 @@ var lumaAdapter = {
14579
15509
 
14580
15510
  // src/adapters/openai-image.ts
14581
15511
  import OpenAI from "openai";
14582
- import { z as z26 } from "zod";
15512
+ import { z as z28 } from "zod";
14583
15513
  var MAX_EDIT_REFERENCES = 16;
14584
15514
  function aspectRatioToSize(ratio, tier) {
14585
15515
  const TIER_LONG_EDGE = {
@@ -14662,9 +15592,9 @@ function toProviderError2(cause, ctx) {
14662
15592
  ctx.model.id
14663
15593
  );
14664
15594
  }
14665
- var openaiUsageSchema = z26.object({
14666
- input_tokens: z26.number().optional(),
14667
- output_tokens: z26.number().optional()
15595
+ var openaiUsageSchema = z28.object({
15596
+ input_tokens: z28.number().optional(),
15597
+ output_tokens: z28.number().optional()
14668
15598
  });
14669
15599
  var openaiImageAdapter = {
14670
15600
  id: "openai-image",
@@ -14789,7 +15719,7 @@ var openaiImageAdapter = {
14789
15719
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
14790
15720
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
14791
15721
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
14792
- const usage3 = {
15722
+ const usage5 = {
14793
15723
  model: ctx.model.id,
14794
15724
  provider: "openai-image",
14795
15725
  modality: "IMAGE",
@@ -14797,10 +15727,10 @@ var openaiImageAdapter = {
14797
15727
  quantity: images.length,
14798
15728
  imageQuality: quality
14799
15729
  };
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 };
15730
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15731
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15732
+ if (req.size !== void 0) usage5.imageSize = req.size;
15733
+ return { images, usage: usage5, raw: response };
14804
15734
  }
14805
15735
  };
14806
15736
 
@@ -15056,16 +15986,16 @@ async function generateProdiaImage(req, ctx) {
15056
15986
  new Uint8Array(await res.arrayBuffer()),
15057
15987
  res.headers.get("content-type")
15058
15988
  );
15059
- const usage3 = {
15989
+ const usage5 = {
15060
15990
  model: ctx.model.id,
15061
15991
  provider: "prodia",
15062
15992
  modality: "IMAGE",
15063
15993
  unit: "images",
15064
15994
  quantity: 1
15065
15995
  };
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 };
15996
+ if (req.size !== void 0) usage5.imageSize = req.size;
15997
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
15998
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15069
15999
  }
15070
16000
  var prodiaAdapter = {
15071
16001
  id: "prodia",
@@ -15076,13 +16006,13 @@ var prodiaAdapter = {
15076
16006
  import Replicate from "replicate";
15077
16007
 
15078
16008
  // 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(),
16009
+ import { z as z29 } from "zod";
16010
+ var predictionSchema = z29.object({
16011
+ id: z29.string(),
16012
+ status: z29.string(),
15083
16013
  output: JsonValueSchema.optional(),
15084
16014
  error: JsonValueSchema.optional(),
15085
- metrics: z27.object({ predict_time: z27.number().optional() }).optional()
16015
+ metrics: z29.object({ predict_time: z29.number().optional() }).optional()
15086
16016
  });
15087
16017
  function createReplicateHttpClient(opts) {
15088
16018
  async function request(path, body, signal) {
@@ -15133,7 +16063,7 @@ function createReplicateHttpClient(opts) {
15133
16063
  }
15134
16064
 
15135
16065
  // src/adapters/replicate.ts
15136
- import { z as z28 } from "zod";
16066
+ import { z as z30 } from "zod";
15137
16067
  var POLL_INTERVAL_MS = 1e3;
15138
16068
  var POLL_TIMEOUT_MS = 15 * 6e4;
15139
16069
  var defaultReplicateDeps = {
@@ -15173,8 +16103,8 @@ function route(providerModelId) {
15173
16103
  if (!providerModelId.includes("/")) return { version: providerModelId };
15174
16104
  return { model: providerModelId };
15175
16105
  }
15176
- var replicateResponseStatusSchema = z28.object({
15177
- response: z28.object({ status: z28.number() }).partial()
16106
+ var replicateResponseStatusSchema = z30.object({
16107
+ response: z30.object({ status: z30.number() }).partial()
15178
16108
  });
15179
16109
  function replicateError(cause, ctx) {
15180
16110
  if (isModelKitError(cause)) return cause;
@@ -15197,7 +16127,7 @@ function isUrlFn(value) {
15197
16127
  function extractOutputUrl(output) {
15198
16128
  const root = Array.isArray(output) ? output[0] : output;
15199
16129
  if (root === void 0) throw noOutput();
15200
- const asString = z28.string().safeParse(root);
16130
+ const asString = z30.string().safeParse(root);
15201
16131
  if (asString.success && asString.data) return asString.data;
15202
16132
  if (root instanceof URL) return root.href;
15203
16133
  if (isObjectOutput(root)) {
@@ -15206,15 +16136,15 @@ function extractOutputUrl(output) {
15206
16136
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15207
16137
  const called = urlValue();
15208
16138
  if (called instanceof URL) return called.href;
15209
- const calledString = z28.string().safeParse(called);
16139
+ const calledString = z30.string().safeParse(called);
15210
16140
  if (calledString.success && calledString.data) return calledString.data;
15211
16141
  } else {
15212
- const direct = z28.string().safeParse(urlValue);
16142
+ const direct = z30.string().safeParse(urlValue);
15213
16143
  if (direct.success && direct.data) return direct.data;
15214
16144
  }
15215
16145
  }
15216
16146
  if ("default" in root) {
15217
- const fallback = z28.string().safeParse(root.default);
16147
+ const fallback = z30.string().safeParse(root.default);
15218
16148
  if (fallback.success && fallback.data) return fallback.data;
15219
16149
  }
15220
16150
  }
@@ -15275,7 +16205,7 @@ async function runPrediction(ctx, input, deps) {
15275
16205
  }
15276
16206
  return void 0;
15277
16207
  }, pollOpts);
15278
- const predictTime = z28.number().safeParse(done.metrics?.predict_time);
16208
+ const predictTime = z30.number().safeParse(done.metrics?.predict_time);
15279
16209
  if (done.output === void 0) throw noOutput();
15280
16210
  return {
15281
16211
  url: extractOutputUrl(done.output),
@@ -15521,9 +16451,9 @@ async function generateReplicateImage(req, ctx, deps) {
15521
16451
  }
15522
16452
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15523
16453
  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 };
16454
+ const usage5 = imageUsage3(ctx, req);
16455
+ usage5.quantity = predictTime;
16456
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
15527
16457
  }
15528
16458
  function klingInput(req) {
15529
16459
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -15628,7 +16558,7 @@ async function generateReplicateVideo(req, ctx, deps) {
15628
16558
  throw replicateError(cause, ctx);
15629
16559
  }
15630
16560
  if (current.status === "succeeded") {
15631
- const predictTime = z28.number().safeParse(current.metrics?.predict_time);
16561
+ const predictTime = z30.number().safeParse(current.metrics?.predict_time);
15632
16562
  if (current.output === void 0) throw noOutput();
15633
16563
  return {
15634
16564
  url: extractOutputUrl(current.output),
@@ -15647,9 +16577,9 @@ async function generateReplicateVideo(req, ctx, deps) {
15647
16577
  return void 0;
15648
16578
  };
15649
16579
  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 };
16580
+ const usage5 = videoUsage5(ctx, req);
16581
+ usage5.quantity = done.predictTime;
16582
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
15653
16583
  };
15654
16584
  return {
15655
16585
  jobId,
@@ -15756,21 +16686,21 @@ async function generateReplicateAudio(req, ctx, deps) {
15756
16686
  input = specResult.input;
15757
16687
  }
15758
16688
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15759
- const usage3 = audioUsage(ctx, req);
16689
+ const usage5 = audioUsage(ctx, req);
15760
16690
  if (ctx.model.usage.unit === "seconds") {
15761
16691
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
15762
- usage3.quantity = seconds3;
15763
- usage3.durationSeconds = seconds3;
16692
+ usage5.quantity = seconds3;
16693
+ usage5.durationSeconds = seconds3;
15764
16694
  } else {
15765
- usage3.quantity = predictTime;
16695
+ usage5.quantity = predictTime;
15766
16696
  }
15767
- return { audio: { url }, usage: usage3, raw: predictionRaw(raw) };
16697
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
15768
16698
  }
15769
16699
 
15770
16700
  // src/adapters/xai-video.ts
15771
16701
  import { experimental_generateVideo } from "ai";
15772
16702
  import { createXai as createXai2 } from "@ai-sdk/xai";
15773
- import { z as z29 } from "zod";
16703
+ import { z as z31 } from "zod";
15774
16704
  var POLL_INTERVAL_MS2 = 1e4;
15775
16705
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
15776
16706
  var defaultXaiDeps = {
@@ -15783,8 +16713,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
15783
16713
  };
15784
16714
  }
15785
16715
  var xaiVideoAdapter = createXaiVideoAdapter();
15786
- var xaiResponseStatusSchema = z29.object({
15787
- response: z29.object({ status: z29.number() }).partial()
16716
+ var xaiResponseStatusSchema = z31.object({
16717
+ response: z31.object({ status: z31.number() }).partial()
15788
16718
  });
15789
16719
  function xaiError(cause, ctx) {
15790
16720
  const info = describeThrown(cause);
@@ -15792,12 +16722,12 @@ function xaiError(cause, ctx) {
15792
16722
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
15793
16723
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
15794
16724
  }
15795
- var xaiMetaSchema = z29.object({
16725
+ var xaiMetaSchema = z31.object({
15796
16726
  videoUrl: JsonValueSchema.optional(),
15797
16727
  costInUsdTicks: JsonValueSchema.optional(),
15798
16728
  duration: JsonValueSchema.optional()
15799
16729
  });
15800
- var xaiProviderMetadataSchema = z29.object({ xai: xaiMetaSchema });
16730
+ var xaiProviderMetadataSchema = z31.object({ xai: xaiMetaSchema });
15801
16731
  function metaOf(result) {
15802
16732
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
15803
16733
  if (!parsed.success) return {};
@@ -15909,12 +16839,12 @@ async function mapResult(ctx, req, result) {
15909
16839
  if (first) {
15910
16840
  return {
15911
16841
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
15912
- usage: usage2(ctx, req, metaOf(result)),
16842
+ usage: usage4(ctx, req, metaOf(result)),
15913
16843
  raw: result.providerMetadata
15914
16844
  };
15915
16845
  }
15916
16846
  const meta = metaOf(result);
15917
- const videoUrl = z29.string().safeParse(meta.videoUrl);
16847
+ const videoUrl = z31.string().safeParse(meta.videoUrl);
15918
16848
  if (videoUrl.success && videoUrl.data) {
15919
16849
  const res = await ctx.fetch(videoUrl.data);
15920
16850
  if (!res.ok) {
@@ -15924,7 +16854,7 @@ async function mapResult(ctx, req, result) {
15924
16854
  const mime = res.headers.get("content-type") ?? "video/mp4";
15925
16855
  return {
15926
16856
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
15927
- usage: usage2(ctx, req, meta),
16857
+ usage: usage4(ctx, req, meta),
15928
16858
  raw: result.providerMetadata
15929
16859
  };
15930
16860
  }
@@ -15936,8 +16866,8 @@ async function mapResult(ctx, req, result) {
15936
16866
  retryable: false
15937
16867
  });
15938
16868
  }
15939
- function usage2(ctx, req, meta) {
15940
- const costTicks = z29.number().safeParse(meta.costInUsdTicks);
16869
+ function usage4(ctx, req, meta) {
16870
+ const costTicks = z31.number().safeParse(meta.costInUsdTicks);
15941
16871
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
15942
16872
  const event = {
15943
16873
  model: ctx.model.id,
@@ -15976,7 +16906,9 @@ var DEFAULT_ADAPTERS = {
15976
16906
  prodia: prodiaAdapter,
15977
16907
  higgsfield: higgsfieldAdapter,
15978
16908
  "xai-video": xaiVideoAdapter,
15979
- luma: lumaAdapter
16909
+ luma: lumaAdapter,
16910
+ fish: fishAdapter,
16911
+ elevenlabs: elevenLabsAdapter
15980
16912
  };
15981
16913
 
15982
16914
  // src/catalog/data-only.ts
@@ -16000,6 +16932,8 @@ function adapterServesType(adapter, type) {
16000
16932
  if (type === "dubbing") return adapter.dub !== void 0;
16001
16933
  if (type === "lipsync") return adapter.lipsync !== void 0;
16002
16934
  if (type === "transcription") return adapter.transcribe !== void 0;
16935
+ if (type === "voice-clone") return adapter.createVoice !== void 0;
16936
+ if (type === "voice-design") return adapter.designVoice !== void 0;
16003
16937
  if (type === "video-tool") return adapter.submitVideoTool !== void 0;
16004
16938
  if (type === "model3d") return adapter.submitModel3d !== void 0;
16005
16939
  return adapter.languageModel !== void 0;
@@ -16013,12 +16947,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16013
16947
  "transcription",
16014
16948
  "mask"
16015
16949
  ]);
16950
+ function directSpeech(row2) {
16951
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
16952
+ }
16016
16953
  function dataOnlyCapable(row2) {
16017
16954
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16018
16955
  if (!adapterServesType(adapter, row2.type)) {
16019
16956
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16020
16957
  }
16021
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
16958
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16022
16959
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16023
16960
  }
16024
16961
  switch (row2.adapter) {
@@ -16096,6 +17033,14 @@ function dataOnlyCapable(row2) {
16096
17033
  const reason = lumaRowRefusal(row2);
16097
17034
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16098
17035
  }
17036
+ case "fish": {
17037
+ const reason = fishRowRefusal(row2);
17038
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17039
+ }
17040
+ case "elevenlabs": {
17041
+ const reason = elevenLabsRowRefusal(row2);
17042
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17043
+ }
16099
17044
  default: {
16100
17045
  return assertNever(row2.adapter);
16101
17046
  }
@@ -16115,22 +17060,22 @@ var liveState = store[KEY] ??= {
16115
17060
  var liveCatalog = liveState.catalog;
16116
17061
 
16117
17062
  // src/catalog/load.ts
16118
- import { z as z30 } from "zod";
17063
+ import { z as z32 } from "zod";
16119
17064
  function rowCount() {
16120
17065
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16121
17066
  }
16122
17067
  function authHeaders(auth) {
16123
17068
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16124
17069
  }
16125
- var EnvelopeSchema = z30.object({
16126
- rows: z30.array(JsonValueSchema),
16127
- revision: z30.string().optional()
17070
+ var EnvelopeSchema = z32.object({
17071
+ rows: z32.array(JsonValueSchema),
17072
+ revision: z32.string().optional()
16128
17073
  });
16129
17074
  function dropReason(path, message) {
16130
17075
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16131
17076
  }
16132
17077
  function rowId(raw) {
16133
- const parsed = z30.object({ id: z30.string().min(1) }).loose().safeParse(raw);
17078
+ const parsed = z32.object({ id: z32.string().min(1) }).loose().safeParse(raw);
16134
17079
  if (!parsed.success) return "?";
16135
17080
  return parsed.data.id;
16136
17081
  }
@@ -17046,8 +17991,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
17046
17991
  const warnings = [];
17047
17992
  checkScript(model, request.text);
17048
17993
  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;
17994
+ const customVoice = request.customVoice?.trim();
17995
+ if (customVoice) {
17996
+ if (model.capabilities?.customVoices !== true) {
17997
+ throw unsupported3(model, "does not take a custom voice");
17998
+ }
17999
+ if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
18000
+ resolved.customVoice = customVoice;
18001
+ } else {
18002
+ const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
18003
+ if (voice !== void 0) resolved.voice = voice;
18004
+ }
17051
18005
  const language = resolveListed(
17052
18006
  model,
17053
18007
  {
@@ -17169,6 +18123,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
17169
18123
  return { request: resolved, warnings };
17170
18124
  }
17171
18125
 
18126
+ // src/resolve-voice.ts
18127
+ function refuse(model, code, message) {
18128
+ return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
18129
+ }
18130
+ function checkSample(model, sample, index) {
18131
+ const limits = model.constraints.references?.audioSeconds;
18132
+ const length = sample.audio.durationSeconds;
18133
+ if (limits === void 0 || length === void 0) return;
18134
+ if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
18135
+ const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
18136
+ throw refuse(
18137
+ model,
18138
+ "unsupported_option",
18139
+ `takes samples of ${range2}; sample ${index + 1} is ${length} s`
18140
+ );
18141
+ }
18142
+ }
18143
+ function resolveVoiceCloneOptions(model, request) {
18144
+ const title = request.title.trim();
18145
+ if (!title) throw refuse(model, "missing_input", "needs a title");
18146
+ if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
18147
+ const max = model.constraints.references?.audios;
18148
+ if (max !== void 0 && request.samples.length > max) {
18149
+ throw refuse(
18150
+ model,
18151
+ "unsupported_option",
18152
+ `takes up to ${max} samples; got ${request.samples.length}`
18153
+ );
18154
+ }
18155
+ request.samples.forEach((sample, index) => checkSample(model, sample, index));
18156
+ const total = model.constraints.references?.audioSeconds?.total;
18157
+ const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
18158
+ if (total !== void 0 && seconds3 > total) {
18159
+ throw refuse(
18160
+ model,
18161
+ "unsupported_option",
18162
+ `takes up to ${total} s of samples; got ${seconds3} s`
18163
+ );
18164
+ }
18165
+ for (const field of ["transcript", "designSignature"]) {
18166
+ const set = request.samples.filter((s) => s[field]?.trim()).length;
18167
+ if (set !== 0 && set !== request.samples.length) {
18168
+ throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
18169
+ }
18170
+ }
18171
+ return { request: { ...request, model: model.id, title }, warnings: [] };
18172
+ }
18173
+ function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
18174
+ const warnings = [];
18175
+ const prompt = request.prompt.trim();
18176
+ if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
18177
+ const maxChars = promptConventions(model).maxChars;
18178
+ if (maxChars !== void 0 && prompt.length > maxChars) {
18179
+ throw refuse(
18180
+ model,
18181
+ "unsupported_option",
18182
+ `takes up to ${maxChars} characters; got ${prompt.length}`
18183
+ );
18184
+ }
18185
+ const limits = model.constraints.voiceDesign;
18186
+ const resolved = { model: model.id, prompt };
18187
+ const preview2 = request.previewText?.trim();
18188
+ if (preview2) {
18189
+ if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
18190
+ throw refuse(
18191
+ model,
18192
+ "unsupported_option",
18193
+ `takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
18194
+ );
18195
+ }
18196
+ resolved.previewText = preview2;
18197
+ }
18198
+ const language = request.language?.trim();
18199
+ if (language) resolved.language = language;
18200
+ if (request.seed !== void 0) resolved.seed = request.seed;
18201
+ const count2 = request.count ?? model.defaults.count;
18202
+ if (count2 !== void 0) {
18203
+ const cap = limits?.maxCandidates ?? count2;
18204
+ if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
18205
+ if (onUnsupported === "error" || !Number.isInteger(count2)) {
18206
+ throw refuse(
18207
+ model,
18208
+ "unsupported_option",
18209
+ `returns 1-${cap} candidates; got ${count2}`
18210
+ );
18211
+ }
18212
+ const to = Math.min(Math.max(count2, 1), cap);
18213
+ warnings.push({
18214
+ code: "option_ignored",
18215
+ field: "count",
18216
+ from: String(count2),
18217
+ to: String(to),
18218
+ message: `count ${count2} replaced by ${to} for ${model.id}`
18219
+ });
18220
+ resolved.count = to;
18221
+ } else resolved.count = count2;
18222
+ }
18223
+ return { request: resolved, warnings };
18224
+ }
18225
+
17172
18226
  // src/keys.ts
17173
18227
  var ADAPTER_KEYS = {
17174
18228
  "ai-sdk-text": [],
@@ -17181,7 +18235,9 @@ var ADAPTER_KEYS = {
17181
18235
  prodia: ["prodia"],
17182
18236
  higgsfield: ["higgsfield"],
17183
18237
  "xai-video": ["xai"],
17184
- luma: ["luma"]
18238
+ luma: ["luma"],
18239
+ fish: ["fish"],
18240
+ elevenlabs: ["elevenlabs"]
17185
18241
  };
17186
18242
  function hasAll(keys, names) {
17187
18243
  if (!keys) return false;
@@ -17240,6 +18296,8 @@ function keysFromEnv(env, prefix = "") {
17240
18296
  set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
17241
18297
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17242
18298
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
18299
+ set("fish", pick2("FISH_AUDIO_API_KEY"));
18300
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
17243
18301
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17244
18302
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17245
18303
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17262,7 +18320,7 @@ function keysFromEnv(env, prefix = "") {
17262
18320
 
17263
18321
  // src/text.ts
17264
18322
  import "ai";
17265
- import { z as z31 } from "zod";
18323
+ import { z as z33 } from "zod";
17266
18324
  function mergeTextProviderOptions(catalog, caller) {
17267
18325
  const merged = {};
17268
18326
  const catalogOptions = catalog.providerOptions ?? {};
@@ -17301,17 +18359,17 @@ function passthroughTextModel(model) {
17301
18359
  pricingKind: "token"
17302
18360
  };
17303
18361
  }
17304
- var perplexityCostSchema = z31.object({
17305
- perplexity: z31.object({ cost: z31.object({ totalCost: z31.number().finite().nonnegative() }) })
18362
+ var perplexityCostSchema = z33.object({
18363
+ perplexity: z33.object({ cost: z33.object({ totalCost: z33.number().finite().nonnegative() }) })
17306
18364
  });
17307
18365
  function reportedCostUsd(metadata) {
17308
18366
  const parsed = perplexityCostSchema.safeParse(metadata);
17309
18367
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
17310
18368
  }
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;
18369
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18370
+ const inputTokens = usage5.inputTokens ?? 0;
18371
+ const outputTokens = usage5.outputTokens ?? 0;
18372
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
17315
18373
  const event = {
17316
18374
  model: model.id,
17317
18375
  provider,
@@ -17346,7 +18404,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17346
18404
  return { ...prepared, providerOptions };
17347
18405
  };
17348
18406
  }
17349
- function usage3(results) {
18407
+ function usage5(results) {
17350
18408
  const grouped = /* @__PURE__ */ new Map();
17351
18409
  for (const [index, step] of results.entries()) {
17352
18410
  const target = steps.get(index) ?? initial;
@@ -17370,7 +18428,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17370
18428
  }
17371
18429
  return [...grouped.values()];
17372
18430
  }
17373
- return { wrap, usage: usage3 };
18431
+ return { wrap, usage: usage5 };
17374
18432
  }
17375
18433
 
17376
18434
  // src/client.ts
@@ -17382,7 +18440,7 @@ import {
17382
18440
  streamObject as aiStreamObject2,
17383
18441
  streamText as aiStreamText2
17384
18442
  } from "ai";
17385
- import { z as z32 } from "zod";
18443
+ import { z as z34 } from "zod";
17386
18444
 
17387
18445
  // src/generated-image.ts
17388
18446
  function toGeneratedImage(image) {
@@ -17504,9 +18562,9 @@ function providerJobMethods(kind, deps) {
17504
18562
  if (!methods.result) throw missing3(adapter, ctx.model);
17505
18563
  const result = await methods.result(sub, ctx, webhook);
17506
18564
  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 };
18565
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18566
+ await deps.emit(usage5);
18567
+ return { ...result, usage: usage5 };
17510
18568
  },
17511
18569
  async cancel(sub, call = {}) {
17512
18570
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -17531,6 +18589,9 @@ var MEDIA_METHODS = {
17531
18589
  lipsync: ["lipsync"],
17532
18590
  dubbing: ["dub"],
17533
18591
  transcription: ["transcribe"],
18592
+ // deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
18593
+ "voice-clone": ["createVoice"],
18594
+ "voice-design": ["designVoice"],
17534
18595
  "video-tool": ["submitVideoTool"],
17535
18596
  // 3D jobs run through submitModel3d, which checks the row type itself; their preflight
17536
18597
  // is model3dInputRefusal, not resolveOptions.
@@ -17545,6 +18606,8 @@ var METHOD_NOUN = {
17545
18606
  lipsync: "a lipsync model",
17546
18607
  dub: "a dubbing model",
17547
18608
  transcribe: "a transcription model",
18609
+ createVoice: "a voice cloning model",
18610
+ designVoice: "a voice design model",
17548
18611
  submitVideoTool: "a video tool"
17549
18612
  };
17550
18613
  function assertMethod(model, method) {
@@ -17587,6 +18650,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
17587
18650
  assertMethod(model, "transcribe");
17588
18651
  return resolveTranscriptionOptions(model, request, onUnsupported);
17589
18652
  }
18653
+ function resolveVoiceCloneCall(model, request) {
18654
+ assertMethod(model, "createVoice");
18655
+ return resolveVoiceCloneOptions(model, request);
18656
+ }
18657
+ function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
18658
+ assertMethod(model, "designVoice");
18659
+ return resolveVoiceDesignOptions(model, request, onUnsupported);
18660
+ }
17590
18661
 
17591
18662
  // src/client-audio.ts
17592
18663
  function noMethod(adapter, model, what) {
@@ -17676,6 +18747,49 @@ function audioNodeMethods(deps) {
17676
18747
  const result = await adapter.transcribe(resolved, ctx);
17677
18748
  return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
17678
18749
  },
18750
+ async createVoice(req, call = {}) {
18751
+ mediaRetryOptions(call);
18752
+ const { abortSignal, ...request } = req;
18753
+ const model = catalog.require(req.model);
18754
+ const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
18755
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18756
+ if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
18757
+ const startedAt = Date.now();
18758
+ const result = await adapter.createVoice(resolved, ctx);
18759
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18760
+ },
18761
+ async designVoice(req, call = {}) {
18762
+ mediaRetryOptions(call);
18763
+ const { abortSignal, ...request } = req;
18764
+ const model = catalog.require(req.model);
18765
+ const { request: resolved, warnings } = resolveVoiceDesignCall(
18766
+ model,
18767
+ request,
18768
+ call.onUnsupported ?? "error"
18769
+ );
18770
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18771
+ if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
18772
+ const startedAt = Date.now();
18773
+ const result = await adapter.designVoice(resolved, ctx);
18774
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18775
+ },
18776
+ async deleteVoice(req, call = {}) {
18777
+ mediaRetryOptions(call);
18778
+ const { abortSignal, ...request } = req;
18779
+ const model = catalog.require(req.model);
18780
+ assertMethod(model, "createVoice");
18781
+ const voiceId = request.voiceId.trim();
18782
+ if (!voiceId) {
18783
+ throw new ModelKitError({
18784
+ code: "missing_input",
18785
+ message: `${model.id} requires voiceId`,
18786
+ model: model.id
18787
+ });
18788
+ }
18789
+ const { adapter, ctx } = prepare(model, call, abortSignal, []);
18790
+ if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
18791
+ await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
18792
+ },
17679
18793
  async dub(req, call = {}) {
17680
18794
  mediaRetryOptions(call);
17681
18795
  const { abortSignal, ...request } = req;
@@ -17690,10 +18804,10 @@ function audioNodeMethods(deps) {
17690
18804
  const startedAt = Date.now();
17691
18805
  const outcome = await adapter.dub(resolved, ctx);
17692
18806
  if (outcome.kind === "audio") {
17693
- const { audio, usage: usage3, raw } = outcome.result;
18807
+ const { audio, usage: usage5, raw } = outcome.result;
17694
18808
  return {
17695
18809
  audio,
17696
- usage: await deps.settle(model, usage3, startedAt),
18810
+ usage: await deps.settle(model, usage5, startedAt),
17697
18811
  ...raw !== void 0 && { raw }
17698
18812
  };
17699
18813
  }
@@ -17731,10 +18845,10 @@ function textAbortOptions(sdk, context) {
17731
18845
  if (abortSignal) return { abortSignal };
17732
18846
  return {};
17733
18847
  }
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"]);
18848
+ var catalogId = z34.string();
18849
+ var exactSize = z34.templateLiteral([z34.number(), "x", z34.number()]);
18850
+ var sdkRatio = z34.templateLiteral([z34.number(), ":", z34.number()]);
18851
+ var sizeTier = z34.enum(["512", "1K", "2K", "4K"]);
17738
18852
  function isCatalogId(model) {
17739
18853
  return catalogId.safeParse(model).success;
17740
18854
  }
@@ -17947,7 +19061,7 @@ function createModelKit(config, adapters) {
17947
19061
  const images = result.images.map(
17948
19062
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
17949
19063
  );
17950
- const usage3 = timed(
19064
+ const usage5 = timed(
17951
19065
  {
17952
19066
  model: model.modelId,
17953
19067
  provider: model.provider,
@@ -17957,8 +19071,8 @@ function createModelKit(config, adapters) {
17957
19071
  },
17958
19072
  startedAt
17959
19073
  );
17960
- await emit(usage3);
17961
- return { image: images[0], images, usage: usage3, raw: result, warnings };
19074
+ await emit(usage5);
19075
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
17962
19076
  }
17963
19077
  function passthroughVideo(req, call) {
17964
19078
  const {
@@ -18034,7 +19148,7 @@ function createModelKit(config, adapters) {
18034
19148
  let settled;
18035
19149
  let failed = false;
18036
19150
  const done = pending.then(async (result) => {
18037
- const usage3 = timed(
19151
+ const usage5 = timed(
18038
19152
  {
18039
19153
  model: model.modelId,
18040
19154
  provider: model.provider,
@@ -18047,10 +19161,10 @@ function createModelKit(config, adapters) {
18047
19161
  );
18048
19162
  settled = {
18049
19163
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18050
- usage: usage3,
19164
+ usage: usage5,
18051
19165
  raw: result
18052
19166
  };
18053
- await emit(usage3);
19167
+ await emit(usage5);
18054
19168
  return settled;
18055
19169
  });
18056
19170
  done.catch(() => {
@@ -18077,12 +19191,12 @@ function createModelKit(config, adapters) {
18077
19191
  if (settled) return settled;
18078
19192
  const pending = result(opts).then(
18079
19193
  async (out) => {
18080
- const usage3 = timed(
19194
+ const usage5 = timed(
18081
19195
  { ...out.usage, model: model.id, unit: model.usage.unit },
18082
19196
  startedAt
18083
19197
  );
18084
- await emit(usage3);
18085
- return { ...out, usage: usage3 };
19198
+ await emit(usage5);
19199
+ return { ...out, usage: usage5 };
18086
19200
  },
18087
19201
  (cause) => {
18088
19202
  settled = void 0;
@@ -18102,9 +19216,9 @@ function createModelKit(config, adapters) {
18102
19216
  return context(model, signal ? { ...call, signal } : call, warnings);
18103
19217
  },
18104
19218
  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;
19219
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19220
+ await emit(usage5);
19221
+ return usage5;
18108
19222
  },
18109
19223
  wrapVideoJob
18110
19224
  });
@@ -18140,11 +19254,11 @@ function createModelKit(config, adapters) {
18140
19254
  });
18141
19255
  const startedAt = Date.now();
18142
19256
  const result = await adapter.generateImage(request, ctx);
18143
- const usage3 = timed(
19257
+ const usage5 = timed(
18144
19258
  { ...result.usage, model: model.id, unit: model.usage.unit },
18145
19259
  startedAt
18146
19260
  );
18147
- await emit(usage3);
19261
+ await emit(usage5);
18148
19262
  const images = result.images.map(toGeneratedImage);
18149
19263
  const first = images[0];
18150
19264
  if (!first)
@@ -18153,7 +19267,7 @@ function createModelKit(config, adapters) {
18153
19267
  message: `${model.id} returned no image`,
18154
19268
  model: model.id
18155
19269
  });
18156
- return { ...result, usage: usage3, image: first, images, warnings };
19270
+ return { ...result, usage: usage5, image: first, images, warnings };
18157
19271
  },
18158
19272
  async generateVideo(req, call = {}) {
18159
19273
  mediaRetryOptions(call);
@@ -18252,12 +19366,12 @@ function createModelKit(config, adapters) {
18252
19366
  }
18253
19367
  const startedAt = Date.now();
18254
19368
  const result = await adapter.generateAudio(resolved, ctx);
18255
- const usage3 = timed(
19369
+ const usage5 = timed(
18256
19370
  { ...result.usage, model: model.id, unit: model.usage.unit },
18257
19371
  startedAt
18258
19372
  );
18259
- await emit(usage3);
18260
- return { ...result, usage: usage3 };
19373
+ await emit(usage5);
19374
+ return { ...result, usage: usage5 };
18261
19375
  },
18262
19376
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
18263
19377
  mediaRetryOptions(call);
@@ -18337,8 +19451,8 @@ function createModelKit(config, adapters) {
18337
19451
  options.prepareStep ?? options.experimental_prepareStep
18338
19452
  ),
18339
19453
  onFinish: async (event) => {
18340
- for (const usage3 of steps.usage(event.steps))
18341
- await emit(textTimed(withRowUnit(usage3), event.steps.length, startedAt));
19454
+ for (const usage5 of steps.usage(event.steps))
19455
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
18342
19456
  await callerOnFinish?.(event);
18343
19457
  }
18344
19458
  });
@@ -18456,10 +19570,12 @@ export {
18456
19570
  dataOnlyCapable,
18457
19571
  describe,
18458
19572
  describeThrown,
19573
+ elevenLabsAdapter,
18459
19574
  generateImage as experimental_generateImage,
18460
19575
  falAdapter,
18461
19576
  falWebhookBodySchema,
18462
19577
  fileCatalogCache,
19578
+ fishAdapter,
18463
19579
  generateAudio,
18464
19580
  generateImage,
18465
19581
  generateObject,
@@ -18512,6 +19628,8 @@ export {
18512
19628
  resolveTranscriptionOptions,
18513
19629
  resolveVideoOptions,
18514
19630
  resolveVoiceChangeOptions,
19631
+ resolveVoiceCloneOptions,
19632
+ resolveVoiceDesignOptions,
18515
19633
  shouldRetry,
18516
19634
  sleep,
18517
19635
  sortCatalogRows,