@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.cjs CHANGED
@@ -66,10 +66,12 @@ __export(index_exports, {
66
66
  dataOnlyCapable: () => dataOnlyCapable,
67
67
  describe: () => describe,
68
68
  describeThrown: () => describeThrown,
69
+ elevenLabsAdapter: () => elevenLabsAdapter,
69
70
  experimental_generateImage: () => generateImage,
70
71
  falAdapter: () => falAdapter,
71
72
  falWebhookBodySchema: () => falWebhookBodySchema,
72
73
  fileCatalogCache: () => fileCatalogCache,
74
+ fishAdapter: () => fishAdapter,
73
75
  generateAudio: () => generateAudio,
74
76
  generateImage: () => generateImage,
75
77
  generateObject: () => generateObject,
@@ -122,6 +124,8 @@ __export(index_exports, {
122
124
  resolveTranscriptionOptions: () => resolveTranscriptionOptions,
123
125
  resolveVideoOptions: () => resolveVideoOptions,
124
126
  resolveVoiceChangeOptions: () => resolveVoiceChangeOptions,
127
+ resolveVoiceCloneOptions: () => resolveVoiceCloneOptions,
128
+ resolveVoiceDesignOptions: () => resolveVoiceDesignOptions,
125
129
  shouldRetry: () => shouldRetry,
126
130
  sleep: () => sleep,
127
131
  sortCatalogRows: () => sortCatalogRows,
@@ -1869,6 +1873,369 @@ var ELEVENLABS_VOICES = [
1869
1873
  previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
1870
1874
  }
1871
1875
  ];
1876
+ var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
1877
+ var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
1878
+ const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
1879
+ return id ? [{ ...v, id }] : [];
1880
+ });
1881
+ var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
1882
+
1883
+ // src/catalog/speech-elevenlabs-direct.ts
1884
+ var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
1885
+ var PER_CALL = { unit: "images" };
1886
+ var PER_REQUEST = { unit: "requests" };
1887
+ var ELEVENLABS_DIRECT_MODELS = [
1888
+ {
1889
+ id: "elevenlabs-v4-direct",
1890
+ aliases: [],
1891
+ label: "ElevenLabs v4 (direct)",
1892
+ type: "speech",
1893
+ adapter: "elevenlabs",
1894
+ providerModelId: "eleven_v4",
1895
+ lifecycle: "active",
1896
+ exposure: [],
1897
+ constraints: {
1898
+ // Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
1899
+ voices: ELEVENLABS_DIRECT_VOICES,
1900
+ languages: ELEVENLABS_V4_LANGUAGES,
1901
+ outputFormats: ELEVENLABS_MP3_FORMATS,
1902
+ supports: [],
1903
+ // ElevenLabs docs: 10,000 characters per request.
1904
+ prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
1905
+ },
1906
+ defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
1907
+ usage: PER_CALL,
1908
+ pricingKind: "flat",
1909
+ display: {
1910
+ provider: "elevenlabs",
1911
+ logo: ELEVENLABS_LOGO,
1912
+ description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
1913
+ },
1914
+ capabilities: { customVoices: true }
1915
+ },
1916
+ {
1917
+ id: "elevenlabs-ivc",
1918
+ aliases: [],
1919
+ label: "ElevenLabs Instant Voice Clone",
1920
+ type: "voice-clone",
1921
+ adapter: "elevenlabs",
1922
+ providerModelId: "ivc",
1923
+ lifecycle: "active",
1924
+ exposure: [],
1925
+ constraints: {
1926
+ // POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
1927
+ // clean speech in total. Each clone uses a voice slot on our plan until deleted.
1928
+ references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
1929
+ supports: []
1930
+ },
1931
+ defaults: {},
1932
+ usage: PER_REQUEST,
1933
+ pricingKind: "flat",
1934
+ display: {
1935
+ provider: "elevenlabs",
1936
+ logo: ELEVENLABS_LOGO,
1937
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
1938
+ },
1939
+ capabilities: {}
1940
+ }
1941
+ ];
1942
+
1943
+ // src/catalog/voices-fish.ts
1944
+ var FISH_VOICES = [
1945
+ {
1946
+ id: "933563129e564b19a115bedd57b7406a",
1947
+ name: "Sarah",
1948
+ gender: "female",
1949
+ languages: ["en"],
1950
+ description: "An engaged speaker.",
1951
+ previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
1952
+ },
1953
+ {
1954
+ id: "bf322df2096a46f18c579d0baa36f41d",
1955
+ name: "Adrian",
1956
+ gender: "male",
1957
+ languages: ["en"],
1958
+ description: "A steady and reliable narrator.",
1959
+ previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
1960
+ },
1961
+ {
1962
+ id: "536d3a5e000945adb7038665781a4aca",
1963
+ name: "Ethan",
1964
+ gender: "male",
1965
+ languages: ["en"],
1966
+ description: "A curious explainer.",
1967
+ previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
1968
+ },
1969
+ {
1970
+ id: "b347db033a6549378b48d00acb0d06cd",
1971
+ name: "Selene",
1972
+ gender: "female",
1973
+ languages: ["en"],
1974
+ description: "A meditative female voice.",
1975
+ previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
1976
+ },
1977
+ {
1978
+ id: "9a9cf47702da476aa4629e2506d4a857",
1979
+ name: "Hannah",
1980
+ gender: "female",
1981
+ languages: ["en"],
1982
+ description: "A conversation specialist.",
1983
+ previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
1984
+ },
1985
+ {
1986
+ id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
1987
+ name: "Jordan",
1988
+ gender: "male",
1989
+ languages: ["en"],
1990
+ description: "A motivational speaker.",
1991
+ previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
1992
+ },
1993
+ {
1994
+ id: "e3cd384158934cc9a01029cd7d278634",
1995
+ name: "Laura",
1996
+ gender: "female",
1997
+ languages: ["en"],
1998
+ description: "A confident female narrator.",
1999
+ previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
2000
+ },
2001
+ {
2002
+ id: "f3a2b90078d54a65af4b95f63bc7798e",
2003
+ name: "Sheila",
2004
+ gender: "female",
2005
+ accent: "american",
2006
+ languages: ["en"],
2007
+ description: "A young American English woman's voice.",
2008
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
2009
+ },
2010
+ {
2011
+ id: "0db6e93af420470b9d9b9a886dbaa954",
2012
+ name: "Kai",
2013
+ gender: "male",
2014
+ languages: ["en"],
2015
+ description: "A friendly English man's voice for companion apps and everyday conversation.",
2016
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
2017
+ },
2018
+ {
2019
+ id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
2020
+ name: "Freya",
2021
+ gender: "female",
2022
+ accent: "british",
2023
+ languages: ["en"],
2024
+ description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
2025
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
2026
+ },
2027
+ {
2028
+ id: "2f64e528a4f2406691925ab1e0ed5b7f",
2029
+ name: "Ananya",
2030
+ gender: "female",
2031
+ languages: ["hi"],
2032
+ description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
2033
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
2034
+ },
2035
+ {
2036
+ id: "cefd91a07b99468f9148e2580990082d",
2037
+ name: "Arjun",
2038
+ gender: "male",
2039
+ languages: ["hi"],
2040
+ description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
2041
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
2042
+ },
2043
+ {
2044
+ id: "3f065d660212478a9c697fa965b4d098",
2045
+ name: "Carmen",
2046
+ gender: "female",
2047
+ languages: ["es"],
2048
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
2049
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
2050
+ },
2051
+ {
2052
+ id: "ec0718028a2445fb9be8e8bfb56a0150",
2053
+ name: "Rodrigo",
2054
+ gender: "male",
2055
+ languages: ["es"],
2056
+ description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
2057
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
2058
+ },
2059
+ {
2060
+ id: "10a3a20742114a4ea6dd441e7591850f",
2061
+ name: "Manon",
2062
+ gender: "female",
2063
+ languages: ["fr"],
2064
+ description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
2065
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
2066
+ },
2067
+ {
2068
+ id: "f69bca092b674168a8d02d61ca20943c",
2069
+ name: "Lucas",
2070
+ gender: "male",
2071
+ languages: ["fr"],
2072
+ description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
2073
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
2074
+ },
2075
+ {
2076
+ id: "3937b44b604249f18b94913daef94043",
2077
+ name: "Lena",
2078
+ gender: "female",
2079
+ languages: ["de"],
2080
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
2081
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
2082
+ },
2083
+ {
2084
+ id: "c1e7cc926aa5469aa966c353094d4b0b",
2085
+ name: "Lukas",
2086
+ gender: "male",
2087
+ languages: ["de"],
2088
+ description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
2089
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
2090
+ },
2091
+ {
2092
+ id: "b3c060cc41544a7da94a2c487647c902",
2093
+ name: "Let\xEDcia",
2094
+ gender: "female",
2095
+ accent: "brazilian",
2096
+ languages: ["pt"],
2097
+ description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
2098
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
2099
+ },
2100
+ {
2101
+ id: "add7bcb8d3c8423bbfa152ca232aad6e",
2102
+ name: "Ricardo",
2103
+ gender: "male",
2104
+ accent: "brazilian",
2105
+ languages: ["pt"],
2106
+ description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
2107
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
2108
+ },
2109
+ {
2110
+ id: "b2d9d8db057042688a5e318b8f405bc2",
2111
+ name: "Kyoko",
2112
+ gender: "female",
2113
+ languages: ["ja"],
2114
+ description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
2115
+ previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
2116
+ },
2117
+ {
2118
+ id: "297a6fd278df47c3b9da9bfdf55ac89a",
2119
+ name: "Satoru",
2120
+ gender: "male",
2121
+ languages: ["ja"],
2122
+ description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
2123
+ previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
2124
+ },
2125
+ {
2126
+ id: "0b14f34a13a94ed88fe6113193749bb0",
2127
+ name: "Fatima",
2128
+ gender: "female",
2129
+ languages: ["ar"],
2130
+ description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
2131
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
2132
+ },
2133
+ {
2134
+ id: "74c6aba5cbf94a15bbdc547ffce5cb38",
2135
+ name: "Yutong",
2136
+ gender: "female",
2137
+ languages: ["zh"],
2138
+ description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
2139
+ previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
2140
+ }
2141
+ ];
2142
+
2143
+ // src/catalog/speech-fish.ts
2144
+ var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
2145
+ var PER_CALL2 = { unit: "images" };
2146
+ var PER_REQUEST2 = { unit: "requests" };
2147
+ var TTS_MAX_CHARS = 1e4;
2148
+ function fishTts(id, label, providerModelId, description) {
2149
+ return {
2150
+ id,
2151
+ aliases: [],
2152
+ label,
2153
+ type: "speech",
2154
+ adapter: "fish",
2155
+ providerModelId,
2156
+ lifecycle: "active",
2157
+ exposure: [],
2158
+ constraints: {
2159
+ voices: FISH_VOICES,
2160
+ outputFormats: ["mp3", "wav"],
2161
+ supports: [],
2162
+ prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
2163
+ },
2164
+ defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
2165
+ usage: PER_CALL2,
2166
+ pricingKind: "flat",
2167
+ display: { provider: "fishaudio", logo: FISH_LOGO, description },
2168
+ capabilities: { customVoices: true }
2169
+ };
2170
+ }
2171
+ var FISH_MODELS = [
2172
+ fishTts(
2173
+ "fish-s2.1-pro",
2174
+ "Fish Audio S2.1 Pro",
2175
+ "s2.1-pro",
2176
+ "Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
2177
+ ),
2178
+ fishTts(
2179
+ "fish-s2.1-pro-free",
2180
+ "Fish Audio S2.1 Pro Free",
2181
+ "s2.1-pro-free",
2182
+ "Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
2183
+ ),
2184
+ fishTts(
2185
+ "fish-drama-3",
2186
+ "Fish Audio Drama 3",
2187
+ "drama-3",
2188
+ "Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
2189
+ ),
2190
+ {
2191
+ id: "fish-voice-clone",
2192
+ aliases: [],
2193
+ label: "Fish Audio Voice Clone",
2194
+ type: "voice-clone",
2195
+ adapter: "fish",
2196
+ providerModelId: "voice-clone",
2197
+ lifecycle: "active",
2198
+ exposure: [],
2199
+ constraints: {
2200
+ // POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
2201
+ references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
2202
+ supports: []
2203
+ },
2204
+ defaults: {},
2205
+ usage: PER_REQUEST2,
2206
+ pricingKind: "flat",
2207
+ display: {
2208
+ provider: "fishaudio",
2209
+ logo: FISH_LOGO,
2210
+ description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
2211
+ },
2212
+ capabilities: {}
2213
+ },
2214
+ {
2215
+ id: "fish-voice-design-1",
2216
+ aliases: [],
2217
+ label: "Fish Audio Voice Design",
2218
+ type: "voice-design",
2219
+ adapter: "fish",
2220
+ providerModelId: "voice-design-1",
2221
+ lifecycle: "active",
2222
+ exposure: [],
2223
+ constraints: {
2224
+ voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
2225
+ supports: [],
2226
+ prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
2227
+ },
2228
+ defaults: {},
2229
+ usage: PER_REQUEST2,
2230
+ pricingKind: "flat",
2231
+ display: {
2232
+ provider: "fishaudio",
2233
+ logo: FISH_LOGO,
2234
+ description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
2235
+ },
2236
+ capabilities: {}
2237
+ }
2238
+ ];
1872
2239
 
1873
2240
  // src/catalog/voices-gemini.ts
1874
2241
  var GEMINI_TTS_VOICES = [
@@ -3445,11 +3812,11 @@ var MINIMAX_VOICES = [
3445
3812
  ];
3446
3813
 
3447
3814
  // src/catalog/media-nodes.ts
3448
- var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3815
+ var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3449
3816
  var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3450
3817
  var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3451
3818
  var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
3452
- var PER_CALL = { unit: "images" };
3819
+ var PER_CALL3 = { unit: "images" };
3453
3820
  var EXPOSURE4 = ["cowork", "space_builder"];
3454
3821
  var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
3455
3822
  function elevenLabsTts(tts) {
@@ -3470,9 +3837,9 @@ function elevenLabsTts(tts) {
3470
3837
  prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
3471
3838
  },
3472
3839
  defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
3473
- usage: PER_CALL,
3840
+ usage: PER_CALL3,
3474
3841
  pricingKind: "flat",
3475
- display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO, description: tts.description },
3842
+ display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
3476
3843
  capabilities: {}
3477
3844
  };
3478
3845
  }
@@ -3494,7 +3861,7 @@ function geminiTts(id, label, description) {
3494
3861
  prompt: { referenceSyntax: "numbered", maxChars: 8192 }
3495
3862
  },
3496
3863
  defaults: { voice: "Kore" },
3497
- usage: PER_CALL,
3864
+ usage: PER_CALL3,
3498
3865
  pricingKind: "flat",
3499
3866
  display: { provider: "google", logo: GOOGLE_LOGO, description },
3500
3867
  capabilities: {}
@@ -3517,7 +3884,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
3517
3884
  },
3518
3885
  defaults: {},
3519
3886
  ...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
3520
- usage: PER_CALL,
3887
+ usage: PER_CALL3,
3521
3888
  pricingKind: "flat",
3522
3889
  display: { provider: "sync", logo: SYNC_LOGO, description },
3523
3890
  capabilities: { acceptsSourceVideo: true }
@@ -3578,7 +3945,7 @@ var MEDIA_NODE_MODELS = [
3578
3945
  prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
3579
3946
  },
3580
3947
  defaults: { voice: "Wise_Woman" },
3581
- usage: PER_CALL,
3948
+ usage: PER_CALL3,
3582
3949
  pricingKind: "flat",
3583
3950
  display: {
3584
3951
  provider: "minimax",
@@ -3605,11 +3972,11 @@ var MEDIA_NODE_MODELS = [
3605
3972
  supports: []
3606
3973
  },
3607
3974
  defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
3608
- usage: PER_CALL,
3975
+ usage: PER_CALL3,
3609
3976
  pricingKind: "flat",
3610
3977
  display: {
3611
3978
  provider: "elevenlabs",
3612
- logo: ELEVENLABS_LOGO,
3979
+ logo: ELEVENLABS_LOGO2,
3613
3980
  description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
3614
3981
  },
3615
3982
  capabilities: {}
@@ -3632,11 +3999,11 @@ var MEDIA_NODE_MODELS = [
3632
3999
  supports: []
3633
4000
  },
3634
4001
  defaults: {},
3635
- usage: PER_CALL,
4002
+ usage: PER_CALL3,
3636
4003
  pricingKind: "flat",
3637
4004
  display: {
3638
4005
  provider: "elevenlabs",
3639
- logo: ELEVENLABS_LOGO,
4006
+ logo: ELEVENLABS_LOGO2,
3640
4007
  description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
3641
4008
  },
3642
4009
  capabilities: { acceptsSourceVideo: true }
@@ -3679,7 +4046,7 @@ var MEDIA_NODE_MODELS = [
3679
4046
  supports: []
3680
4047
  },
3681
4048
  defaults: {},
3682
- usage: PER_CALL,
4049
+ usage: PER_CALL3,
3683
4050
  pricingKind: "flat",
3684
4051
  display: {
3685
4052
  provider: "veed",
@@ -3731,16 +4098,18 @@ var MEDIA_NODE_MODELS = [
3731
4098
  supports: []
3732
4099
  },
3733
4100
  defaults: {},
3734
- usage: PER_CALL,
4101
+ usage: PER_CALL3,
3735
4102
  pricingKind: "flat",
3736
4103
  display: {
3737
4104
  provider: "elevenlabs",
3738
- logo: ELEVENLABS_LOGO,
4105
+ logo: ELEVENLABS_LOGO2,
3739
4106
  description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
3740
4107
  },
3741
4108
  capabilities: {}
3742
4109
  },
3743
- SAM_3_IMAGE
4110
+ SAM_3_IMAGE,
4111
+ ...FISH_MODELS,
4112
+ ...ELEVENLABS_DIRECT_MODELS
3744
4113
  ];
3745
4114
 
3746
4115
  // src/catalog/model3d.ts
@@ -3936,7 +4305,7 @@ var MODEL3D_MODELS = [
3936
4305
 
3937
4306
  // src/catalog/other.ts
3938
4307
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3939
- var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
4308
+ var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
3940
4309
  var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
3941
4310
  var OTHER_MODELS = [
3942
4311
  {
@@ -4101,7 +4470,7 @@ var OTHER_MODELS = [
4101
4470
  pricingKind: "flat",
4102
4471
  display: {
4103
4472
  provider: "elevenlabs",
4104
- logo: ELEVENLABS_LOGO2,
4473
+ logo: ELEVENLABS_LOGO3,
4105
4474
  description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
4106
4475
  },
4107
4476
  capabilities: {}
@@ -4153,7 +4522,7 @@ var OTHER_MODELS = [
4153
4522
  pricingKind: "flat",
4154
4523
  display: {
4155
4524
  provider: "elevenlabs",
4156
- logo: ELEVENLABS_LOGO2,
4525
+ logo: ELEVENLABS_LOGO3,
4157
4526
  description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
4158
4527
  },
4159
4528
  capabilities: {}
@@ -7375,7 +7744,9 @@ var ADAPTER_IDS = [
7375
7744
  "prodia",
7376
7745
  "higgsfield",
7377
7746
  "xai-video",
7378
- "luma"
7747
+ "luma",
7748
+ "fish",
7749
+ "elevenlabs"
7379
7750
  ];
7380
7751
  var ModelTypeSchema = import_zod3.z.enum([
7381
7752
  "text",
@@ -7392,6 +7763,8 @@ var ModelTypeSchema = import_zod3.z.enum([
7392
7763
  "dubbing",
7393
7764
  "lipsync",
7394
7765
  "transcription",
7766
+ "voice-clone",
7767
+ "voice-design",
7395
7768
  "model3d"
7396
7769
  ]);
7397
7770
  var LifecycleSchema = import_zod3.z.enum(["active", "deprecated", "retired"]);
@@ -7567,6 +7940,10 @@ var ModelConstraintsSchema = import_zod3.z.looseObject({
7567
7940
  supports: import_zod3.z.array(SupportedOptionSchema).optional(),
7568
7941
  ratioIgnoredWith: import_zod3.z.array(import_zod3.z.enum(["firstFrame", "sourceVideo"])).optional(),
7569
7942
  voices: import_zod3.z.array(VoiceOptionSchema).optional(),
7943
+ voiceDesign: import_zod3.z.object({
7944
+ maxCandidates: import_zod3.z.number().int().positive(),
7945
+ previewMaxChars: import_zod3.z.number().int().positive()
7946
+ }).optional(),
7570
7947
  languages: import_zod3.z.array(LanguageOptionSchema).optional(),
7571
7948
  outputFormats: import_zod3.z.array(import_zod3.z.string().min(1)).min(1).optional(),
7572
7949
  sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: import_zod3.z.boolean().optional() }).optional(),
@@ -7665,6 +8042,7 @@ var CatalogDisplaySchema = import_zod3.z.looseObject({
7665
8042
  });
7666
8043
  var CatalogCapabilitiesSchema = import_zod3.z.looseObject({
7667
8044
  acceptsSourceVideo: import_zod3.z.boolean().optional(),
8045
+ customVoices: import_zod3.z.boolean().optional(),
7668
8046
  videoEdit: import_zod3.z.boolean().optional(),
7669
8047
  framesExcludeReferences: import_zod3.z.boolean().optional(),
7670
8048
  sourceVideoExcludesFrames: import_zod3.z.boolean().optional(),
@@ -8184,7 +8562,7 @@ var errorCodes = import_zod6.z.object({
8184
8562
  type: import_zod6.z.string().optional(),
8185
8563
  error: import_zod6.z.object({ code: import_zod6.z.string().optional(), type: import_zod6.z.string().optional() }).optional()
8186
8564
  });
8187
- var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
8565
+ var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
8188
8566
  var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
8189
8567
  function billingCode(body) {
8190
8568
  const parsed = errorCodes.safeParse(body);
@@ -8581,16 +8959,16 @@ async function generateSeedreamImage(req, ctx) {
8581
8959
  } else {
8582
8960
  throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
8583
8961
  }
8584
- const usage3 = {
8962
+ const usage5 = {
8585
8963
  model: modelId,
8586
8964
  provider: "ark",
8587
8965
  modality: "IMAGE",
8588
8966
  unit: "images",
8589
8967
  quantity: 1
8590
8968
  };
8591
- if (req.size !== void 0) usage3.imageSize = req.size;
8592
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
8593
- return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage3, raw: data };
8969
+ if (req.size !== void 0) usage5.imageSize = req.size;
8970
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
8971
+ return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
8594
8972
  }
8595
8973
  var SeedanceUsageSchema = import_zod7.z.object({
8596
8974
  total_tokens: import_zod7.z.number().optional(),
@@ -8631,7 +9009,7 @@ function seedanceErrorMessage(error, status) {
8631
9009
  if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
8632
9010
  return `Seedance task ${status}`;
8633
9011
  }
8634
- function seedanceJob(ctx, key, jobId, usage3) {
9012
+ function seedanceJob(ctx, key, jobId, usage5) {
8635
9013
  const modelId = ctx.model.id;
8636
9014
  const fetchStatus = async () => {
8637
9015
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
@@ -8681,21 +9059,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
8681
9059
  modelId
8682
9060
  );
8683
9061
  if (polled.duration !== void 0 && polled.duration > 0) {
8684
- usage3.quantity = polled.duration;
8685
- usage3.durationSeconds = polled.duration;
9062
+ usage5.quantity = polled.duration;
9063
+ usage5.durationSeconds = polled.duration;
8686
9064
  }
8687
9065
  const rendered = VideoResolutionSchema.safeParse(
8688
9066
  polled.resolution?.toLowerCase()
8689
9067
  );
8690
- if (rendered.success) usage3.resolution = rendered.data;
9068
+ if (rendered.success) usage5.resolution = rendered.data;
8691
9069
  const tokens = polled.usage;
8692
9070
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
8693
- usage3.inputTokens = tokens.total_tokens - tokens.completion_tokens;
8694
- usage3.outputTokens = tokens.completion_tokens;
9071
+ usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
9072
+ usage5.outputTokens = tokens.completion_tokens;
8695
9073
  }
8696
9074
  return {
8697
9075
  video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
8698
- usage: usage3,
9076
+ usage: usage5,
8699
9077
  raw: polled
8700
9078
  };
8701
9079
  }
@@ -8801,8 +9179,8 @@ async function generateSeedanceVideo(req, ctx) {
8801
9179
  );
8802
9180
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
8803
9181
  const jobId = submit.id;
8804
- const usage3 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
8805
- return seedanceJob(ctx, key, jobId, usage3);
9182
+ const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
9183
+ return seedanceJob(ctx, key, jobId, usage5);
8806
9184
  }
8807
9185
 
8808
9186
  // src/adapters/fal.ts
@@ -10290,7 +10668,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10290
10668
  return { bytes, mime: mime || "image/png" };
10291
10669
  })
10292
10670
  );
10293
- const usage3 = {
10671
+ const usage5 = {
10294
10672
  model: ctx.model.id,
10295
10673
  provider: "fal",
10296
10674
  modality: "IMAGE",
@@ -10298,9 +10676,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
10298
10676
  quantity: images.length
10299
10677
  };
10300
10678
  const billedSize = plan4.imageSize ?? req.size;
10301
- if (billedSize !== void 0 && ctx.model.type === "image") usage3.imageSize = billedSize;
10302
- if (plan4.imageQuality !== void 0) usage3.imageQuality = plan4.imageQuality;
10303
- const result = { images, usage: usage3, raw: payload };
10679
+ if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
10680
+ if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
10681
+ const result = { images, usage: usage5, raw: payload };
10304
10682
  const remote = files.find((f) => !f.url.startsWith("data:"));
10305
10683
  if (remote !== void 0) result.outputUrl = remote.url;
10306
10684
  return result;
@@ -12463,12 +12841,568 @@ function planUsage(ctx, plan4) {
12463
12841
  };
12464
12842
  }
12465
12843
 
12466
- // src/adapters/google-genai.ts
12844
+ // src/adapters/elevenlabs.ts
12845
+ var import_zod21 = require("zod");
12846
+ var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
12847
+ var DEFAULT_FORMAT = "mp3_44100_128";
12848
+ var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
12849
+ var ELEVENLABS_IVC = "ivc";
12850
+ var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
12851
+ function elevenLabsRowRefusal(row2) {
12852
+ const id = row2.providerModelId;
12853
+ if (row2.type === "speech") {
12854
+ return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
12855
+ }
12856
+ if (row2.type === "voice-clone") {
12857
+ return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
12858
+ }
12859
+ return `elevenlabs has no ${row2.type} rows`;
12860
+ }
12861
+ function elevenLabsError(ctx, code, message) {
12862
+ return new ModelKitError({
12863
+ code,
12864
+ message,
12865
+ provider: "elevenlabs",
12866
+ model: ctx.model.id,
12867
+ retryable: false
12868
+ });
12869
+ }
12870
+ function checkRow(ctx, type) {
12871
+ const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
12872
+ if (ctx.model.type !== type || refusal2 !== void 0) {
12873
+ throw elevenLabsError(
12874
+ ctx,
12875
+ "unsupported_option",
12876
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
12877
+ );
12878
+ }
12879
+ }
12880
+ function checkVoiceId(ctx, field, id) {
12881
+ if (!VOICE_ID.test(id))
12882
+ throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
12883
+ return id;
12884
+ }
12885
+ function elevenLabsKey(ctx) {
12886
+ const key = ctx.keys.elevenlabs;
12887
+ if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
12888
+ return key;
12889
+ }
12890
+ function elevenLabsUrl(ctx, path) {
12891
+ return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
12892
+ }
12893
+ var errorDetail = import_zod21.z.object({
12894
+ detail: import_zod21.z.object({ status: import_zod21.z.string(), message: import_zod21.z.string().optional() })
12895
+ });
12896
+ function errorStatus(body) {
12897
+ const parsed = errorDetail.safeParse(body);
12898
+ return parsed.success ? parsed.data.detail : void 0;
12899
+ }
12900
+ function classifyResponse(ctx, status, body) {
12901
+ const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
12902
+ const detail = errorStatus(body);
12903
+ if (detail?.status === "voice_limit_reached") {
12904
+ return new ModelKitError({
12905
+ code: "provider_rejected",
12906
+ message: detail.message ?? "ElevenLabs voice limit reached",
12907
+ provider: "elevenlabs",
12908
+ model: ctx.model.id,
12909
+ status,
12910
+ body,
12911
+ cause: error,
12912
+ retryable: false
12913
+ });
12914
+ }
12915
+ if (detail?.status === "quota_exceeded") {
12916
+ return new ModelKitError({
12917
+ code: "provider_billing",
12918
+ message: error.message,
12919
+ provider: "elevenlabs",
12920
+ model: ctx.model.id,
12921
+ status,
12922
+ body,
12923
+ cause: error,
12924
+ retryable: false
12925
+ });
12926
+ }
12927
+ return error;
12928
+ }
12929
+ async function elevenLabsFetch(ctx, path, init) {
12930
+ throwIfAborted(ctx.signal);
12931
+ const request = {
12932
+ method: init.method,
12933
+ headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
12934
+ };
12935
+ if (init.body !== void 0) request.body = init.body;
12936
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
12937
+ let res;
12938
+ try {
12939
+ res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
12940
+ } catch (cause) {
12941
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12942
+ }
12943
+ if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
12944
+ return res;
12945
+ }
12946
+ function usage2(ctx) {
12947
+ return {
12948
+ model: ctx.model.id,
12949
+ provider: "elevenlabs",
12950
+ modality: "AUDIO",
12951
+ unit: ctx.model.usage.unit,
12952
+ quantity: 1
12953
+ };
12954
+ }
12955
+ function audioMime(res) {
12956
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
12957
+ return header?.startsWith("audio/") ? header : "audio/mpeg";
12958
+ }
12959
+ async function generateSpeech(req, ctx) {
12960
+ checkRow(ctx, "speech");
12961
+ const voice = req.customVoice ?? req.voice;
12962
+ if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
12963
+ const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
12964
+ const format = req.outputFormat ?? DEFAULT_FORMAT;
12965
+ const body = { text: req.text, model_id: ctx.model.providerModelId };
12966
+ if (req.language !== void 0) body.language_code = req.language;
12967
+ const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
12968
+ const { bytes, mime } = await withRetry(
12969
+ async () => {
12970
+ const res = await elevenLabsFetch(ctx, path, {
12971
+ method: "POST",
12972
+ headers: { "Content-Type": "application/json" },
12973
+ body: JSON.stringify(body)
12974
+ });
12975
+ let audio;
12976
+ try {
12977
+ audio = new Uint8Array(await res.arrayBuffer());
12978
+ } catch (cause) {
12979
+ throw classifyThrown("elevenlabs", cause, ctx.model.id);
12980
+ }
12981
+ return { bytes: audio, mime: audioMime(res) };
12982
+ },
12983
+ mediaRetryOptions(ctx.call, ctx.signal)
12984
+ );
12985
+ if (bytes.byteLength === 0)
12986
+ throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
12987
+ return { audio: { bytes, mime }, usage: usage2(ctx) };
12988
+ }
12989
+ var createdVoiceSchema = import_zod21.z.object({
12990
+ voice_id: import_zod21.z.string().min(1),
12991
+ requires_verification: import_zod21.z.boolean().optional().catch(void 0)
12992
+ });
12993
+ function sampleMime(mime) {
12994
+ return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
12995
+ }
12996
+ function fileName(index, mime, ref) {
12997
+ const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
12998
+ const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
12999
+ const ext = fromMime || fromUrl?.toLowerCase();
13000
+ return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
13001
+ }
13002
+ async function cloneForm(req, ctx) {
13003
+ if (req.samples.length === 0)
13004
+ throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
13005
+ if (req.samples.some((s) => s.designSignature?.trim())) {
13006
+ throw elevenLabsError(
13007
+ ctx,
13008
+ "unsupported_option",
13009
+ "ElevenLabs cannot keep a voice design signature; clone from recordings only"
13010
+ );
13011
+ }
13012
+ const form = new FormData();
13013
+ form.append("name", req.title.trim());
13014
+ if (req.description?.trim()) form.append("description", req.description.trim());
13015
+ if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
13016
+ for (const [index, sample] of req.samples.entries()) {
13017
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
13018
+ signal: ctx.signal,
13019
+ provider: "elevenlabs",
13020
+ model: ctx.model.id
13021
+ });
13022
+ const type = sampleMime(mime);
13023
+ const audio = new Blob([new Uint8Array(bytes)], { type });
13024
+ form.append("files", audio, fileName(index, type, sample.audio));
13025
+ }
13026
+ return form;
13027
+ }
13028
+ async function onlyRateLimitRetries(fn) {
13029
+ try {
13030
+ return await fn();
13031
+ } catch (cause) {
13032
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
13033
+ throw cause;
13034
+ throw new ModelKitError({
13035
+ code: cause.code,
13036
+ message: cause.message,
13037
+ ...cause.provider !== void 0 && { provider: cause.provider },
13038
+ ...cause.model !== void 0 && { model: cause.model },
13039
+ ...cause.status !== void 0 && { status: cause.status },
13040
+ ...cause.body !== void 0 && { body: cause.body },
13041
+ cause,
13042
+ retryable: false
13043
+ });
13044
+ }
13045
+ }
13046
+ async function createVoice(req, ctx) {
13047
+ checkRow(ctx, "voice-clone");
13048
+ const form = await cloneForm(req, ctx);
13049
+ const res = await withRetry(
13050
+ () => onlyRateLimitRetries(
13051
+ () => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
13052
+ ),
13053
+ mediaRetryOptions(ctx.call, ctx.signal)
13054
+ );
13055
+ const raw = await readBody(res);
13056
+ const parsed = createdVoiceSchema.safeParse(raw);
13057
+ if (!parsed.success) {
13058
+ throw new ModelKitError({
13059
+ code: "provider_rejected",
13060
+ message: "ElevenLabs returned no voice id",
13061
+ provider: "elevenlabs",
13062
+ model: ctx.model.id,
13063
+ status: res.status,
13064
+ body: raw,
13065
+ retryable: false
13066
+ });
13067
+ }
13068
+ return {
13069
+ voiceId: parsed.data.voice_id,
13070
+ state: parsed.data.requires_verification === true ? "created" : "trained",
13071
+ usage: usage2(ctx),
13072
+ raw
13073
+ };
13074
+ }
13075
+ var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
13076
+ "voice_not_found",
13077
+ "voice_does_not_exist"
13078
+ ]);
13079
+ function notFound(cause) {
13080
+ if (cause.status === 404) return true;
13081
+ const status = errorStatus(cause.body)?.status;
13082
+ return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
13083
+ }
13084
+ async function deleteVoice(req, ctx) {
13085
+ checkRow(ctx, "voice-clone");
13086
+ const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
13087
+ let attempts = 0;
13088
+ await withRetry(
13089
+ async () => {
13090
+ attempts += 1;
13091
+ try {
13092
+ await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
13093
+ } catch (cause) {
13094
+ if (!isModelKitError(cause) || !notFound(cause)) throw cause;
13095
+ if (attempts > 1) return;
13096
+ throw new ModelKitError({
13097
+ code: "provider_rejected",
13098
+ message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13099
+ provider: "elevenlabs",
13100
+ model: ctx.model.id,
13101
+ ...cause.status !== void 0 && { status: cause.status },
13102
+ cause,
13103
+ retryable: false
13104
+ });
13105
+ }
13106
+ },
13107
+ mediaRetryOptions(ctx.call, ctx.signal)
13108
+ );
13109
+ }
13110
+ var elevenLabsAdapter = {
13111
+ id: "elevenlabs",
13112
+ generateSpeech,
13113
+ createVoice,
13114
+ deleteVoice
13115
+ };
13116
+
13117
+ // src/adapters/fish.ts
12467
13118
  var import_zod22 = require("zod");
13119
+ var DEFAULT_BASE_URL2 = "https://api.fish.audio";
13120
+ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
13121
+ "s2.1-pro",
13122
+ "s2.1-pro-free",
13123
+ "drama-3"
13124
+ ]);
13125
+ var FISH_VOICE_CLONE = "voice-clone";
13126
+ var FISH_VOICE_DESIGN = "voice-design-1";
13127
+ var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
13128
+ function fishRowRefusal(row2) {
13129
+ const id = row2.providerModelId;
13130
+ if (row2.type === "speech") {
13131
+ return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
13132
+ }
13133
+ if (row2.type === "voice-clone") {
13134
+ return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
13135
+ }
13136
+ if (row2.type === "voice-design") {
13137
+ return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
13138
+ }
13139
+ return `fish has no ${row2.type} rows`;
13140
+ }
13141
+ function fishError(ctx, code, message) {
13142
+ return new ModelKitError({
13143
+ code,
13144
+ message,
13145
+ provider: "fish",
13146
+ model: ctx.model.id,
13147
+ retryable: false
13148
+ });
13149
+ }
13150
+ function checkRow2(ctx, type) {
13151
+ const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
13152
+ if (ctx.model.type !== type || refusal2 !== void 0) {
13153
+ throw fishError(
13154
+ ctx,
13155
+ "unsupported_option",
13156
+ refusal2 ?? `${ctx.model.id} is not a ${type} row`
13157
+ );
13158
+ }
13159
+ }
13160
+ function checkVoiceId2(ctx, field, id) {
13161
+ if (!VOICE_ID2.test(id))
13162
+ throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
13163
+ return id;
13164
+ }
13165
+ function fishKey(ctx) {
13166
+ const key = ctx.keys.fish;
13167
+ if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
13168
+ return key;
13169
+ }
13170
+ function fishUrl(ctx, path) {
13171
+ return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
13172
+ }
13173
+ async function fishFetch(ctx, path, init) {
13174
+ throwIfAborted(ctx.signal);
13175
+ const request = {
13176
+ method: init.method,
13177
+ headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
13178
+ };
13179
+ if (init.body !== void 0) request.body = init.body;
13180
+ if (ctx.signal !== void 0) request.signal = ctx.signal;
13181
+ let res;
13182
+ try {
13183
+ res = await ctx.fetch(fishUrl(ctx, path), request);
13184
+ } catch (cause) {
13185
+ throw classifyThrown("fish", cause, ctx.model.id);
13186
+ }
13187
+ if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
13188
+ return res;
13189
+ }
13190
+ function usage3(ctx) {
13191
+ return {
13192
+ model: ctx.model.id,
13193
+ provider: "fish",
13194
+ modality: "AUDIO",
13195
+ unit: ctx.model.usage.unit,
13196
+ quantity: 1
13197
+ };
13198
+ }
13199
+ function audioMime2(res, format) {
13200
+ const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
13201
+ if (header?.startsWith("audio/")) return header;
13202
+ return format === "wav" ? "audio/wav" : "audio/mpeg";
13203
+ }
13204
+ async function generateSpeech2(req, ctx) {
13205
+ checkRow2(ctx, "speech");
13206
+ const format = req.outputFormat ?? "mp3";
13207
+ const body = { text: req.text, format };
13208
+ const voice = req.customVoice ?? req.voice;
13209
+ if (voice !== void 0) {
13210
+ body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
13211
+ }
13212
+ if (req.language !== void 0) body.language = req.language;
13213
+ const { bytes, mime } = await withRetry(
13214
+ async () => {
13215
+ const res = await fishFetch(ctx, "/v1/tts", {
13216
+ method: "POST",
13217
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
13218
+ body: JSON.stringify(body)
13219
+ });
13220
+ let audio;
13221
+ try {
13222
+ audio = new Uint8Array(await res.arrayBuffer());
13223
+ } catch (cause) {
13224
+ throw classifyThrown("fish", cause, ctx.model.id);
13225
+ }
13226
+ return { bytes: audio, mime: audioMime2(res, format) };
13227
+ },
13228
+ mediaRetryOptions(ctx.call, ctx.signal)
13229
+ );
13230
+ if (bytes.byteLength === 0)
13231
+ throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
13232
+ return { audio: { bytes, mime }, usage: usage3(ctx) };
13233
+ }
13234
+ var createdModelSchema = import_zod22.z.object({
13235
+ _id: import_zod22.z.string().min(1),
13236
+ state: import_zod22.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
13237
+ });
13238
+ function fileName2(index, mime) {
13239
+ const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
13240
+ return `sample-${index + 1}.${ext}`;
13241
+ }
13242
+ function allOrNone(ctx, field, values) {
13243
+ const set = values.filter((v) => v !== void 0 && v.trim() !== "");
13244
+ if (set.length === 0) return [];
13245
+ if (set.length !== values.length) {
13246
+ throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
13247
+ }
13248
+ return set;
13249
+ }
13250
+ async function cloneForm2(req, ctx) {
13251
+ if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
13252
+ const transcripts = allOrNone(
13253
+ ctx,
13254
+ "transcript",
13255
+ req.samples.map((s) => s.transcript)
13256
+ );
13257
+ const signatures = allOrNone(
13258
+ ctx,
13259
+ "designSignature",
13260
+ req.samples.map((s) => s.designSignature)
13261
+ );
13262
+ const form = new FormData();
13263
+ form.append("type", "tts");
13264
+ form.append("train_mode", "fast");
13265
+ form.append("visibility", "private");
13266
+ form.append("title", req.title.trim());
13267
+ if (req.description?.trim()) form.append("description", req.description.trim());
13268
+ if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
13269
+ for (const [index, sample] of req.samples.entries()) {
13270
+ const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
13271
+ signal: ctx.signal,
13272
+ provider: "fish",
13273
+ model: ctx.model.id
13274
+ });
13275
+ const audio = new Blob([new Uint8Array(bytes)], { type: mime });
13276
+ form.append("voices", audio, fileName2(index, mime));
13277
+ }
13278
+ for (const text2 of transcripts) form.append("texts", text2.trim());
13279
+ for (const signature of signatures) form.append("voice_design_signatures", signature);
13280
+ return form;
13281
+ }
13282
+ async function onlyRateLimitRetries2(fn) {
13283
+ try {
13284
+ return await fn();
13285
+ } catch (cause) {
13286
+ if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
13287
+ throw cause;
13288
+ throw new ModelKitError({
13289
+ code: cause.code,
13290
+ message: cause.message,
13291
+ ...cause.provider !== void 0 && { provider: cause.provider },
13292
+ ...cause.model !== void 0 && { model: cause.model },
13293
+ ...cause.status !== void 0 && { status: cause.status },
13294
+ ...cause.body !== void 0 && { body: cause.body },
13295
+ cause,
13296
+ retryable: false
13297
+ });
13298
+ }
13299
+ }
13300
+ async function createVoice2(req, ctx) {
13301
+ checkRow2(ctx, "voice-clone");
13302
+ const form = await cloneForm2(req, ctx);
13303
+ const res = await withRetry(
13304
+ () => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
13305
+ mediaRetryOptions(ctx.call, ctx.signal)
13306
+ );
13307
+ const raw = await readBody(res);
13308
+ const parsed = createdModelSchema.safeParse(raw);
13309
+ if (!parsed.success) {
13310
+ throw new ModelKitError({
13311
+ code: "provider_rejected",
13312
+ message: "Fish returned no voice id",
13313
+ provider: "fish",
13314
+ model: ctx.model.id,
13315
+ status: res.status,
13316
+ body: raw,
13317
+ retryable: false
13318
+ });
13319
+ }
13320
+ const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
13321
+ if (parsed.data.state !== void 0) result.state = parsed.data.state;
13322
+ return result;
13323
+ }
13324
+ var designSchema = import_zod22.z.object({
13325
+ candidates: import_zod22.z.array(
13326
+ import_zod22.z.looseObject({
13327
+ id: import_zod22.z.string().min(1),
13328
+ index: import_zod22.z.number().int(),
13329
+ audio_base64: import_zod22.z.string().min(1),
13330
+ duration_ms: import_zod22.z.number().nonnegative(),
13331
+ signature: import_zod22.z.string().min(1).optional()
13332
+ })
13333
+ ).min(1)
13334
+ });
13335
+ async function designVoice(req, ctx) {
13336
+ checkRow2(ctx, "voice-design");
13337
+ const body = { instruction: req.prompt.trim() };
13338
+ if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
13339
+ if (req.language !== void 0) body.language = req.language;
13340
+ if (req.count !== void 0) body.n = req.count;
13341
+ if (req.seed !== void 0) body.seed = req.seed;
13342
+ const raw = await withRetry(
13343
+ async () => {
13344
+ const res = await fishFetch(ctx, "/v1/voice-design", {
13345
+ method: "POST",
13346
+ headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
13347
+ body: JSON.stringify(body)
13348
+ });
13349
+ return readBody(res);
13350
+ },
13351
+ mediaRetryOptions(ctx.call, ctx.signal)
13352
+ );
13353
+ const parsed = designSchema.safeParse(raw);
13354
+ if (!parsed.success) {
13355
+ throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
13356
+ }
13357
+ const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
13358
+ audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
13359
+ durationSeconds: c.duration_ms / 1e3,
13360
+ // The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
13361
+ // rejects a clone whose signature does not verify, so a wrong one fails loudly.
13362
+ signature: c.signature ?? c.id
13363
+ }));
13364
+ return { candidates, usage: usage3(ctx) };
13365
+ }
13366
+ async function deleteVoice2(req, ctx) {
13367
+ checkRow2(ctx, "voice-clone");
13368
+ const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
13369
+ let attempts = 0;
13370
+ await withRetry(
13371
+ async () => {
13372
+ attempts += 1;
13373
+ try {
13374
+ await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
13375
+ } catch (cause) {
13376
+ if (!isModelKitError(cause) || cause.status !== 404) throw cause;
13377
+ if (attempts > 1) return;
13378
+ throw new ModelKitError({
13379
+ code: "provider_rejected",
13380
+ message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
13381
+ provider: "fish",
13382
+ model: ctx.model.id,
13383
+ status: 404,
13384
+ cause,
13385
+ retryable: false
13386
+ });
13387
+ }
13388
+ },
13389
+ mediaRetryOptions(ctx.call, ctx.signal)
13390
+ );
13391
+ }
13392
+ var fishAdapter = {
13393
+ id: "fish",
13394
+ generateSpeech: generateSpeech2,
13395
+ createVoice: createVoice2,
13396
+ designVoice,
13397
+ deleteVoice: deleteVoice2
13398
+ };
13399
+
13400
+ // src/adapters/google-genai.ts
13401
+ var import_zod24 = require("zod");
12468
13402
  var import_genai = require("@google/genai");
12469
13403
 
12470
13404
  // src/adapters/google-files.ts
12471
- var import_zod21 = require("zod");
13405
+ var import_zod23 = require("zod");
12472
13406
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
12473
13407
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
12474
13408
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -12478,17 +13412,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
12478
13412
  "binary/octet-stream",
12479
13413
  "application/binary"
12480
13414
  ]);
12481
- var uploadedFileSchema = import_zod21.z.object({
12482
- file: import_zod21.z.object({
12483
- uri: import_zod21.z.string().optional(),
12484
- name: import_zod21.z.string().optional(),
12485
- state: import_zod21.z.string().optional(),
12486
- mimeType: import_zod21.z.string().optional()
13415
+ var uploadedFileSchema = import_zod23.z.object({
13416
+ file: import_zod23.z.object({
13417
+ uri: import_zod23.z.string().optional(),
13418
+ name: import_zod23.z.string().optional(),
13419
+ state: import_zod23.z.string().optional(),
13420
+ mimeType: import_zod23.z.string().optional()
12487
13421
  }).optional()
12488
13422
  });
12489
- var fileStateSchema = import_zod21.z.object({
12490
- state: import_zod21.z.string().optional(),
12491
- error: import_zod21.z.object({ message: import_zod21.z.string().optional() }).optional()
13423
+ var fileStateSchema = import_zod23.z.object({
13424
+ state: import_zod23.z.string().optional(),
13425
+ error: import_zod23.z.object({ message: import_zod23.z.string().optional() }).optional()
12492
13426
  });
12493
13427
  function resolveMime(declared, fallback) {
12494
13428
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -12595,7 +13529,7 @@ async function startAndUpload(bytes, mimeType, opts) {
12595
13529
  if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
12596
13530
  return ref;
12597
13531
  }
12598
- async function waitForActive(fileName, opts) {
13532
+ async function waitForActive(fileName3, opts) {
12599
13533
  const pollOptions2 = {
12600
13534
  intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
12601
13535
  timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
@@ -12608,14 +13542,14 @@ async function waitForActive(fileName, opts) {
12608
13542
  retryInit.signal = opts.signal;
12609
13543
  }
12610
13544
  await pollUntil(async () => {
12611
- const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, retryInit);
13545
+ const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
12612
13546
  if (res.ok) {
12613
13547
  const json = fileStateSchema.parse(await res.json());
12614
13548
  if (json.state === "ACTIVE") return true;
12615
13549
  if (json.state === "FAILED") {
12616
13550
  throw classifyHttpError(
12617
13551
  void 0,
12618
- `Files API processing failed for ${fileName}: ${json.error?.message ?? "unknown error"}`,
13552
+ `Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
12619
13553
  "google-genai",
12620
13554
  opts.model
12621
13555
  );
@@ -12627,9 +13561,9 @@ async function waitForActive(fileName, opts) {
12627
13561
  throw classifyHttpError(res.status, text2, "google-genai", opts.model);
12628
13562
  }, pollOptions2);
12629
13563
  }
12630
- async function deleteGoogleFile(fileName, apiKey, fetchImpl) {
13564
+ async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
12631
13565
  try {
12632
- await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName}`, {
13566
+ await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
12633
13567
  method: "DELETE",
12634
13568
  headers: { "x-goog-api-key": apiKey }
12635
13569
  });
@@ -12709,7 +13643,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
12709
13643
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
12710
13644
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
12711
13645
  var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
12712
- var errorTextSchema = import_zod22.z.string();
13646
+ var errorTextSchema = import_zod24.z.string();
12713
13647
  function isGoogleGenaiVideoKnown(providerModelId) {
12714
13648
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
12715
13649
  }
@@ -12904,7 +13838,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12904
13838
  }
12905
13839
  };
12906
13840
  const jobId = operation.name ?? crypto.randomUUID();
12907
- const usage3 = videoUsage2(ctx, duration, req.resolution ?? "720p");
13841
+ const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
12908
13842
  return {
12909
13843
  jobId,
12910
13844
  async poll() {
@@ -12942,7 +13876,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
12942
13876
  modelId
12943
13877
  );
12944
13878
  }
12945
- return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage3, raw: finished };
13879
+ return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
12946
13880
  }
12947
13881
  };
12948
13882
  }
@@ -13053,7 +13987,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13053
13987
  return file.fileUri;
13054
13988
  };
13055
13989
  const cleanupUploads = async () => {
13056
- for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
13990
+ for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
13057
13991
  };
13058
13992
  const callCreate = (input) => client2.interactions.create(
13059
13993
  previousId !== void 0 ? {
@@ -13147,7 +14081,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13147
14081
  if (!(extend && !chained)) await cleanupUploads();
13148
14082
  }
13149
14083
  const jobId = interaction.id ?? crypto.randomUUID();
13150
- const usage3 = videoUsage2(ctx, duration, omniResolution ?? "720p");
14084
+ const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
13151
14085
  const getInteraction = async () => {
13152
14086
  try {
13153
14087
  const getParams = { stream: false };
@@ -13195,7 +14129,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13195
14129
  bytes: Buffer.from(video.data, "base64"),
13196
14130
  mime: video.mime_type ?? "video/mp4"
13197
14131
  },
13198
- usage: usage3,
14132
+ usage: usage5,
13199
14133
  raw: done,
13200
14134
  providerRef
13201
14135
  };
@@ -13203,7 +14137,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
13203
14137
  if (video.uri)
13204
14138
  return {
13205
14139
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
13206
- usage: usage3,
14140
+ usage: usage5,
13207
14141
  raw: done,
13208
14142
  providerRef
13209
14143
  };
@@ -13373,15 +14307,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
13373
14307
  // src/adapters/google-image.ts
13374
14308
  var import_google2 = require("@ai-sdk/google");
13375
14309
  var import_ai2 = require("ai");
13376
- var import_zod23 = require("zod");
14310
+ var import_zod25 = require("zod");
13377
14311
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
13378
14312
  var defaultGoogleImageDeps = {
13379
14313
  createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
13380
14314
  runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
13381
14315
  };
13382
- var causeChainNodeSchema = import_zod23.z.object({
13383
- message: import_zod23.z.string().optional(),
13384
- cause: import_zod23.z.unknown().optional()
14316
+ var causeChainNodeSchema = import_zod25.z.object({
14317
+ message: import_zod25.z.string().optional(),
14318
+ cause: import_zod25.z.unknown().optional()
13385
14319
  });
13386
14320
  function extractBlockReason(cause) {
13387
14321
  let current = cause;
@@ -13481,7 +14415,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13481
14415
  retryable: false
13482
14416
  });
13483
14417
  }
13484
- const usage3 = {
14418
+ const usage5 = {
13485
14419
  model: ctx.model.id,
13486
14420
  provider: "google-image",
13487
14421
  modality: "IMAGE",
@@ -13489,19 +14423,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
13489
14423
  quantity: images.length,
13490
14424
  imageQuality: "auto"
13491
14425
  };
13492
- if (req.size !== void 0) usage3.imageSize = req.size;
14426
+ if (req.size !== void 0) usage5.imageSize = req.size;
13493
14427
  if (result.usage?.inputTokens !== void 0)
13494
- usage3.inputTokens = result.usage.inputTokens;
14428
+ usage5.inputTokens = result.usage.inputTokens;
13495
14429
  if (result.usage?.outputTokens !== void 0)
13496
- usage3.outputTokens = result.usage.outputTokens;
13497
- return { images, usage: usage3, raw: result };
14430
+ usage5.outputTokens = result.usage.outputTokens;
14431
+ return { images, usage: usage5, raw: result };
13498
14432
  }
13499
14433
  };
13500
14434
  }
13501
14435
  var googleImageAdapter = createGoogleImageAdapter();
13502
14436
 
13503
14437
  // src/adapters/higgsfield.ts
13504
- var import_zod24 = require("zod");
14438
+ var import_zod26 = require("zod");
13505
14439
 
13506
14440
  // src/adapters/higgsfield-motions.ts
13507
14441
  var MOTION_MAP = {
@@ -13720,14 +14654,14 @@ function klingEndpointFields(providerModelId) {
13720
14654
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
13721
14655
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
13722
14656
  }
13723
- var klingCreateSchema = import_zod24.z.object({ status_url: import_zod24.z.string() });
13724
- var klingStatusSchema = import_zod24.z.object({
13725
- status: import_zod24.z.string().optional(),
13726
- video: import_zod24.z.object({ url: import_zod24.z.string().optional() }).optional(),
14657
+ var klingCreateSchema = import_zod26.z.object({ status_url: import_zod26.z.string() });
14658
+ var klingStatusSchema = import_zod26.z.object({
14659
+ status: import_zod26.z.string().optional(),
14660
+ video: import_zod26.z.object({ url: import_zod26.z.string().optional() }).optional(),
13727
14661
  error: JsonValueSchema.optional()
13728
14662
  });
13729
- var errorMessageSchema = import_zod24.z.object({ message: import_zod24.z.string().optional() });
13730
- var textValueSchema = import_zod24.z.string();
14663
+ var errorMessageSchema = import_zod26.z.object({ message: import_zod26.z.string().optional() });
14664
+ var textValueSchema = import_zod26.z.string();
13731
14665
  function klingErrorDetail(error) {
13732
14666
  if (error === void 0) return "unknown_error";
13733
14667
  const asText = textValueSchema.safeParse(error);
@@ -13883,8 +14817,8 @@ async function generateKlingVideo(req, ctx) {
13883
14817
  }
13884
14818
  };
13885
14819
  }
13886
- var dopMotionOptionsSchema = import_zod24.z.object({
13887
- modelkit: import_zod24.z.object({ motion: import_zod24.z.string().optional() }).optional()
14820
+ var dopMotionOptionsSchema = import_zod26.z.object({
14821
+ modelkit: import_zod26.z.object({ motion: import_zod26.z.string().optional() }).optional()
13888
14822
  });
13889
14823
  function dopMotionId(ctx) {
13890
14824
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -13900,7 +14834,7 @@ function dopMotionId(ctx) {
13900
14834
  });
13901
14835
  return id;
13902
14836
  }
13903
- var jsonRecordSchema = import_zod24.z.record(import_zod24.z.string(), JsonValueSchema);
14837
+ var jsonRecordSchema = import_zod26.z.record(import_zod26.z.string(), JsonValueSchema);
13904
14838
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
13905
14839
  var DOP_NESTED_KEYS = ["video", "result", "results"];
13906
14840
  function dopUrl(body) {
@@ -13928,8 +14862,8 @@ function dopUrl(body) {
13928
14862
  }
13929
14863
  return void 0;
13930
14864
  }
13931
- var dopCreateSchema = import_zod24.z.object({ id: import_zod24.z.string() });
13932
- var dopStatusSchema = import_zod24.z.object({ status: import_zod24.z.string().optional() });
14865
+ var dopCreateSchema = import_zod26.z.object({ id: import_zod26.z.string() });
14866
+ var dopStatusSchema = import_zod26.z.object({ status: import_zod26.z.string().optional() });
13933
14867
  async function generateDopVideo(req, ctx) {
13934
14868
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
13935
14869
  if (!firstFrame) {
@@ -14056,7 +14990,7 @@ var higgsfieldAdapter = {
14056
14990
  };
14057
14991
 
14058
14992
  // src/adapters/luma.ts
14059
- var import_zod25 = require("zod");
14993
+ var import_zod27 = require("zod");
14060
14994
 
14061
14995
  // src/adapters/mp4-duration.ts
14062
14996
  function mp4DurationSeconds(bytes) {
@@ -14112,7 +15046,7 @@ function findBox(bytes, from, to, type) {
14112
15046
  }
14113
15047
 
14114
15048
  // src/adapters/luma.ts
14115
- var DEFAULT_BASE_URL = "https://agents.lumalabs.ai";
15049
+ var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
14116
15050
  var IMAGE_POLL_INTERVAL_MS = 3e3;
14117
15051
  var IMAGE_TIMEOUT_MS = 5 * 6e4;
14118
15052
  var VIDEO_POLL_INTERVAL_MS = 5e3;
@@ -14141,7 +15075,7 @@ function lumaModel(ctx) {
14141
15075
  return ctx.model.providerModelId.toLowerCase();
14142
15076
  }
14143
15077
  function lumaBase(ctx) {
14144
- return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
15078
+ return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
14145
15079
  }
14146
15080
  function lumaKey(ctx) {
14147
15081
  const key = ctx.keys.luma;
@@ -14273,17 +15207,17 @@ function lumaReframeResolution(req, ctx) {
14273
15207
  });
14274
15208
  return "720p";
14275
15209
  }
14276
- var lumaGenerationSchema = import_zod25.z.looseObject({
14277
- id: import_zod25.z.string(),
14278
- state: import_zod25.z.string().optional(),
14279
- output: import_zod25.z.array(
14280
- import_zod25.z.looseObject({
14281
- type: import_zod25.z.string().optional(),
14282
- url: import_zod25.z.string().optional()
15210
+ var lumaGenerationSchema = import_zod27.z.looseObject({
15211
+ id: import_zod27.z.string(),
15212
+ state: import_zod27.z.string().optional(),
15213
+ output: import_zod27.z.array(
15214
+ import_zod27.z.looseObject({
15215
+ type: import_zod27.z.string().optional(),
15216
+ url: import_zod27.z.string().optional()
14283
15217
  })
14284
15218
  ).optional(),
14285
- failure_reason: import_zod25.z.string().optional().nullable(),
14286
- failure_code: import_zod25.z.string().optional().nullable()
15219
+ failure_reason: import_zod27.z.string().optional().nullable(),
15220
+ failure_code: import_zod27.z.string().optional().nullable()
14287
15221
  });
14288
15222
  function lumaFailure(ctx, code, reason) {
14289
15223
  const detail = reason ?? code ?? "unknown_error";
@@ -14715,7 +15649,7 @@ var lumaAdapter = {
14715
15649
 
14716
15650
  // src/adapters/openai-image.ts
14717
15651
  var import_openai2 = __toESM(require("openai"), 1);
14718
- var import_zod26 = require("zod");
15652
+ var import_zod28 = require("zod");
14719
15653
  var MAX_EDIT_REFERENCES = 16;
14720
15654
  function aspectRatioToSize(ratio, tier) {
14721
15655
  const TIER_LONG_EDGE = {
@@ -14798,9 +15732,9 @@ function toProviderError2(cause, ctx) {
14798
15732
  ctx.model.id
14799
15733
  );
14800
15734
  }
14801
- var openaiUsageSchema = import_zod26.z.object({
14802
- input_tokens: import_zod26.z.number().optional(),
14803
- output_tokens: import_zod26.z.number().optional()
15735
+ var openaiUsageSchema = import_zod28.z.object({
15736
+ input_tokens: import_zod28.z.number().optional(),
15737
+ output_tokens: import_zod28.z.number().optional()
14804
15738
  });
14805
15739
  var openaiImageAdapter = {
14806
15740
  id: "openai-image",
@@ -14925,7 +15859,7 @@ var openaiImageAdapter = {
14925
15859
  const usageParsed = openaiUsageSchema.safeParse(response.usage);
14926
15860
  const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
14927
15861
  const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
14928
- const usage3 = {
15862
+ const usage5 = {
14929
15863
  model: ctx.model.id,
14930
15864
  provider: "openai-image",
14931
15865
  modality: "IMAGE",
@@ -14933,10 +15867,10 @@ var openaiImageAdapter = {
14933
15867
  quantity: images.length,
14934
15868
  imageQuality: quality
14935
15869
  };
14936
- if (inputTokens !== void 0) usage3.inputTokens = inputTokens;
14937
- if (outputTokens !== void 0) usage3.outputTokens = outputTokens;
14938
- if (req.size !== void 0) usage3.imageSize = req.size;
14939
- return { images, usage: usage3, raw: response };
15870
+ if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
15871
+ if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
15872
+ if (req.size !== void 0) usage5.imageSize = req.size;
15873
+ return { images, usage: usage5, raw: response };
14940
15874
  }
14941
15875
  };
14942
15876
 
@@ -15192,16 +16126,16 @@ async function generateProdiaImage(req, ctx) {
15192
16126
  new Uint8Array(await res.arrayBuffer()),
15193
16127
  res.headers.get("content-type")
15194
16128
  );
15195
- const usage3 = {
16129
+ const usage5 = {
15196
16130
  model: ctx.model.id,
15197
16131
  provider: "prodia",
15198
16132
  modality: "IMAGE",
15199
16133
  unit: "images",
15200
16134
  quantity: 1
15201
16135
  };
15202
- if (req.size !== void 0) usage3.imageSize = req.size;
15203
- if (req.quality !== void 0) usage3.imageQuality = req.quality;
15204
- return { images: [{ bytes, mime }], usage: usage3, raw: void 0 };
16136
+ if (req.size !== void 0) usage5.imageSize = req.size;
16137
+ if (req.quality !== void 0) usage5.imageQuality = req.quality;
16138
+ return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
15205
16139
  }
15206
16140
  var prodiaAdapter = {
15207
16141
  id: "prodia",
@@ -15212,13 +16146,13 @@ var prodiaAdapter = {
15212
16146
  var import_replicate = __toESM(require("replicate"), 1);
15213
16147
 
15214
16148
  // src/adapters/replicate-http.ts
15215
- var import_zod27 = require("zod");
15216
- var predictionSchema = import_zod27.z.object({
15217
- id: import_zod27.z.string(),
15218
- status: import_zod27.z.string(),
16149
+ var import_zod29 = require("zod");
16150
+ var predictionSchema = import_zod29.z.object({
16151
+ id: import_zod29.z.string(),
16152
+ status: import_zod29.z.string(),
15219
16153
  output: JsonValueSchema.optional(),
15220
16154
  error: JsonValueSchema.optional(),
15221
- metrics: import_zod27.z.object({ predict_time: import_zod27.z.number().optional() }).optional()
16155
+ metrics: import_zod29.z.object({ predict_time: import_zod29.z.number().optional() }).optional()
15222
16156
  });
15223
16157
  function createReplicateHttpClient(opts) {
15224
16158
  async function request(path, body, signal) {
@@ -15269,7 +16203,7 @@ function createReplicateHttpClient(opts) {
15269
16203
  }
15270
16204
 
15271
16205
  // src/adapters/replicate.ts
15272
- var import_zod28 = require("zod");
16206
+ var import_zod30 = require("zod");
15273
16207
  var POLL_INTERVAL_MS = 1e3;
15274
16208
  var POLL_TIMEOUT_MS = 15 * 6e4;
15275
16209
  var defaultReplicateDeps = {
@@ -15309,8 +16243,8 @@ function route(providerModelId) {
15309
16243
  if (!providerModelId.includes("/")) return { version: providerModelId };
15310
16244
  return { model: providerModelId };
15311
16245
  }
15312
- var replicateResponseStatusSchema = import_zod28.z.object({
15313
- response: import_zod28.z.object({ status: import_zod28.z.number() }).partial()
16246
+ var replicateResponseStatusSchema = import_zod30.z.object({
16247
+ response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
15314
16248
  });
15315
16249
  function replicateError(cause, ctx) {
15316
16250
  if (isModelKitError(cause)) return cause;
@@ -15333,7 +16267,7 @@ function isUrlFn(value) {
15333
16267
  function extractOutputUrl(output) {
15334
16268
  const root = Array.isArray(output) ? output[0] : output;
15335
16269
  if (root === void 0) throw noOutput();
15336
- const asString = import_zod28.z.string().safeParse(root);
16270
+ const asString = import_zod30.z.string().safeParse(root);
15337
16271
  if (asString.success && asString.data) return asString.data;
15338
16272
  if (root instanceof URL) return root.href;
15339
16273
  if (isObjectOutput(root)) {
@@ -15342,15 +16276,15 @@ function extractOutputUrl(output) {
15342
16276
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
15343
16277
  const called = urlValue();
15344
16278
  if (called instanceof URL) return called.href;
15345
- const calledString = import_zod28.z.string().safeParse(called);
16279
+ const calledString = import_zod30.z.string().safeParse(called);
15346
16280
  if (calledString.success && calledString.data) return calledString.data;
15347
16281
  } else {
15348
- const direct = import_zod28.z.string().safeParse(urlValue);
16282
+ const direct = import_zod30.z.string().safeParse(urlValue);
15349
16283
  if (direct.success && direct.data) return direct.data;
15350
16284
  }
15351
16285
  }
15352
16286
  if ("default" in root) {
15353
- const fallback = import_zod28.z.string().safeParse(root.default);
16287
+ const fallback = import_zod30.z.string().safeParse(root.default);
15354
16288
  if (fallback.success && fallback.data) return fallback.data;
15355
16289
  }
15356
16290
  }
@@ -15411,7 +16345,7 @@ async function runPrediction(ctx, input, deps) {
15411
16345
  }
15412
16346
  return void 0;
15413
16347
  }, pollOpts);
15414
- const predictTime = import_zod28.z.number().safeParse(done.metrics?.predict_time);
16348
+ const predictTime = import_zod30.z.number().safeParse(done.metrics?.predict_time);
15415
16349
  if (done.output === void 0) throw noOutput();
15416
16350
  return {
15417
16351
  url: extractOutputUrl(done.output),
@@ -15657,9 +16591,9 @@ async function generateReplicateImage(req, ctx, deps) {
15657
16591
  }
15658
16592
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15659
16593
  const file = await download(ctx, url);
15660
- const usage3 = imageUsage3(ctx, req);
15661
- usage3.quantity = predictTime;
15662
- return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage3, raw, outputUrl: url };
16594
+ const usage5 = imageUsage3(ctx, req);
16595
+ usage5.quantity = predictTime;
16596
+ return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
15663
16597
  }
15664
16598
  function klingInput(req) {
15665
16599
  const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
@@ -15764,7 +16698,7 @@ async function generateReplicateVideo(req, ctx, deps) {
15764
16698
  throw replicateError(cause, ctx);
15765
16699
  }
15766
16700
  if (current.status === "succeeded") {
15767
- const predictTime = import_zod28.z.number().safeParse(current.metrics?.predict_time);
16701
+ const predictTime = import_zod30.z.number().safeParse(current.metrics?.predict_time);
15768
16702
  if (current.output === void 0) throw noOutput();
15769
16703
  return {
15770
16704
  url: extractOutputUrl(current.output),
@@ -15783,9 +16717,9 @@ async function generateReplicateVideo(req, ctx, deps) {
15783
16717
  return void 0;
15784
16718
  };
15785
16719
  const toResult = (done) => {
15786
- const usage3 = videoUsage5(ctx, req);
15787
- usage3.quantity = done.predictTime;
15788
- return { video: { url: done.url }, usage: usage3, raw: done.raw };
16720
+ const usage5 = videoUsage5(ctx, req);
16721
+ usage5.quantity = done.predictTime;
16722
+ return { video: { url: done.url }, usage: usage5, raw: done.raw };
15789
16723
  };
15790
16724
  return {
15791
16725
  jobId,
@@ -15892,21 +16826,21 @@ async function generateReplicateAudio(req, ctx, deps) {
15892
16826
  input = specResult.input;
15893
16827
  }
15894
16828
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
15895
- const usage3 = audioUsage(ctx, req);
16829
+ const usage5 = audioUsage(ctx, req);
15896
16830
  if (ctx.model.usage.unit === "seconds") {
15897
16831
  const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
15898
- usage3.quantity = seconds3;
15899
- usage3.durationSeconds = seconds3;
16832
+ usage5.quantity = seconds3;
16833
+ usage5.durationSeconds = seconds3;
15900
16834
  } else {
15901
- usage3.quantity = predictTime;
16835
+ usage5.quantity = predictTime;
15902
16836
  }
15903
- return { audio: { url }, usage: usage3, raw: predictionRaw(raw) };
16837
+ return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
15904
16838
  }
15905
16839
 
15906
16840
  // src/adapters/xai-video.ts
15907
16841
  var import_ai3 = require("ai");
15908
16842
  var import_xai2 = require("@ai-sdk/xai");
15909
- var import_zod29 = require("zod");
16843
+ var import_zod31 = require("zod");
15910
16844
  var POLL_INTERVAL_MS2 = 1e4;
15911
16845
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
15912
16846
  var defaultXaiDeps = {
@@ -15919,8 +16853,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
15919
16853
  };
15920
16854
  }
15921
16855
  var xaiVideoAdapter = createXaiVideoAdapter();
15922
- var xaiResponseStatusSchema = import_zod29.z.object({
15923
- response: import_zod29.z.object({ status: import_zod29.z.number() }).partial()
16856
+ var xaiResponseStatusSchema = import_zod31.z.object({
16857
+ response: import_zod31.z.object({ status: import_zod31.z.number() }).partial()
15924
16858
  });
15925
16859
  function xaiError(cause, ctx) {
15926
16860
  const info = describeThrown(cause);
@@ -15928,12 +16862,12 @@ function xaiError(cause, ctx) {
15928
16862
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
15929
16863
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
15930
16864
  }
15931
- var xaiMetaSchema = import_zod29.z.object({
16865
+ var xaiMetaSchema = import_zod31.z.object({
15932
16866
  videoUrl: JsonValueSchema.optional(),
15933
16867
  costInUsdTicks: JsonValueSchema.optional(),
15934
16868
  duration: JsonValueSchema.optional()
15935
16869
  });
15936
- var xaiProviderMetadataSchema = import_zod29.z.object({ xai: xaiMetaSchema });
16870
+ var xaiProviderMetadataSchema = import_zod31.z.object({ xai: xaiMetaSchema });
15937
16871
  function metaOf(result) {
15938
16872
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
15939
16873
  if (!parsed.success) return {};
@@ -16045,12 +16979,12 @@ async function mapResult(ctx, req, result) {
16045
16979
  if (first) {
16046
16980
  return {
16047
16981
  video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
16048
- usage: usage2(ctx, req, metaOf(result)),
16982
+ usage: usage4(ctx, req, metaOf(result)),
16049
16983
  raw: result.providerMetadata
16050
16984
  };
16051
16985
  }
16052
16986
  const meta = metaOf(result);
16053
- const videoUrl = import_zod29.z.string().safeParse(meta.videoUrl);
16987
+ const videoUrl = import_zod31.z.string().safeParse(meta.videoUrl);
16054
16988
  if (videoUrl.success && videoUrl.data) {
16055
16989
  const res = await ctx.fetch(videoUrl.data);
16056
16990
  if (!res.ok) {
@@ -16060,7 +16994,7 @@ async function mapResult(ctx, req, result) {
16060
16994
  const mime = res.headers.get("content-type") ?? "video/mp4";
16061
16995
  return {
16062
16996
  video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
16063
- usage: usage2(ctx, req, meta),
16997
+ usage: usage4(ctx, req, meta),
16064
16998
  raw: result.providerMetadata
16065
16999
  };
16066
17000
  }
@@ -16072,8 +17006,8 @@ async function mapResult(ctx, req, result) {
16072
17006
  retryable: false
16073
17007
  });
16074
17008
  }
16075
- function usage2(ctx, req, meta) {
16076
- const costTicks = import_zod29.z.number().safeParse(meta.costInUsdTicks);
17009
+ function usage4(ctx, req, meta) {
17010
+ const costTicks = import_zod31.z.number().safeParse(meta.costInUsdTicks);
16077
17011
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
16078
17012
  const event = {
16079
17013
  model: ctx.model.id,
@@ -16112,7 +17046,9 @@ var DEFAULT_ADAPTERS = {
16112
17046
  prodia: prodiaAdapter,
16113
17047
  higgsfield: higgsfieldAdapter,
16114
17048
  "xai-video": xaiVideoAdapter,
16115
- luma: lumaAdapter
17049
+ luma: lumaAdapter,
17050
+ fish: fishAdapter,
17051
+ elevenlabs: elevenLabsAdapter
16116
17052
  };
16117
17053
 
16118
17054
  // src/catalog/data-only.ts
@@ -16136,6 +17072,8 @@ function adapterServesType(adapter, type) {
16136
17072
  if (type === "dubbing") return adapter.dub !== void 0;
16137
17073
  if (type === "lipsync") return adapter.lipsync !== void 0;
16138
17074
  if (type === "transcription") return adapter.transcribe !== void 0;
17075
+ if (type === "voice-clone") return adapter.createVoice !== void 0;
17076
+ if (type === "voice-design") return adapter.designVoice !== void 0;
16139
17077
  if (type === "video-tool") return adapter.submitVideoTool !== void 0;
16140
17078
  if (type === "model3d") return adapter.submitModel3d !== void 0;
16141
17079
  return adapter.languageModel !== void 0;
@@ -16149,12 +17087,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
16149
17087
  "transcription",
16150
17088
  "mask"
16151
17089
  ]);
17090
+ function directSpeech(row2) {
17091
+ return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
17092
+ }
16152
17093
  function dataOnlyCapable(row2) {
16153
17094
  const adapter = DEFAULT_ADAPTERS[row2.adapter];
16154
17095
  if (!adapterServesType(adapter, row2.type)) {
16155
17096
  return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
16156
17097
  }
16157
- if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
17098
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
16158
17099
  return { ok: false, reason: `only fal serves ${row2.type} rows` };
16159
17100
  }
16160
17101
  switch (row2.adapter) {
@@ -16232,6 +17173,14 @@ function dataOnlyCapable(row2) {
16232
17173
  const reason = lumaRowRefusal(row2);
16233
17174
  return reason === void 0 ? { ok: true } : { ok: false, reason };
16234
17175
  }
17176
+ case "fish": {
17177
+ const reason = fishRowRefusal(row2);
17178
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17179
+ }
17180
+ case "elevenlabs": {
17181
+ const reason = elevenLabsRowRefusal(row2);
17182
+ return reason === void 0 ? { ok: true } : { ok: false, reason };
17183
+ }
16235
17184
  default: {
16236
17185
  return assertNever(row2.adapter);
16237
17186
  }
@@ -16251,22 +17200,22 @@ var liveState = store[KEY] ??= {
16251
17200
  var liveCatalog = liveState.catalog;
16252
17201
 
16253
17202
  // src/catalog/load.ts
16254
- var import_zod30 = require("zod");
17203
+ var import_zod32 = require("zod");
16255
17204
  function rowCount() {
16256
17205
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
16257
17206
  }
16258
17207
  function authHeaders(auth) {
16259
17208
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
16260
17209
  }
16261
- var EnvelopeSchema = import_zod30.z.object({
16262
- rows: import_zod30.z.array(JsonValueSchema),
16263
- revision: import_zod30.z.string().optional()
17210
+ var EnvelopeSchema = import_zod32.z.object({
17211
+ rows: import_zod32.z.array(JsonValueSchema),
17212
+ revision: import_zod32.z.string().optional()
16264
17213
  });
16265
17214
  function dropReason(path, message) {
16266
17215
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
16267
17216
  }
16268
17217
  function rowId(raw) {
16269
- const parsed = import_zod30.z.object({ id: import_zod30.z.string().min(1) }).loose().safeParse(raw);
17218
+ const parsed = import_zod32.z.object({ id: import_zod32.z.string().min(1) }).loose().safeParse(raw);
16270
17219
  if (!parsed.success) return "?";
16271
17220
  return parsed.data.id;
16272
17221
  }
@@ -17182,8 +18131,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
17182
18131
  const warnings = [];
17183
18132
  checkScript(model, request.text);
17184
18133
  const resolved = { model: model.id, text: request.text };
17185
- const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
17186
- if (voice !== void 0) resolved.voice = voice;
18134
+ const customVoice = request.customVoice?.trim();
18135
+ if (customVoice) {
18136
+ if (model.capabilities?.customVoices !== true) {
18137
+ throw unsupported3(model, "does not take a custom voice");
18138
+ }
18139
+ if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
18140
+ resolved.customVoice = customVoice;
18141
+ } else {
18142
+ const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
18143
+ if (voice !== void 0) resolved.voice = voice;
18144
+ }
17187
18145
  const language = resolveListed(
17188
18146
  model,
17189
18147
  {
@@ -17305,6 +18263,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
17305
18263
  return { request: resolved, warnings };
17306
18264
  }
17307
18265
 
18266
+ // src/resolve-voice.ts
18267
+ function refuse(model, code, message) {
18268
+ return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
18269
+ }
18270
+ function checkSample(model, sample, index) {
18271
+ const limits = model.constraints.references?.audioSeconds;
18272
+ const length = sample.audio.durationSeconds;
18273
+ if (limits === void 0 || length === void 0) return;
18274
+ if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
18275
+ const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
18276
+ throw refuse(
18277
+ model,
18278
+ "unsupported_option",
18279
+ `takes samples of ${range2}; sample ${index + 1} is ${length} s`
18280
+ );
18281
+ }
18282
+ }
18283
+ function resolveVoiceCloneOptions(model, request) {
18284
+ const title = request.title.trim();
18285
+ if (!title) throw refuse(model, "missing_input", "needs a title");
18286
+ if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
18287
+ const max = model.constraints.references?.audios;
18288
+ if (max !== void 0 && request.samples.length > max) {
18289
+ throw refuse(
18290
+ model,
18291
+ "unsupported_option",
18292
+ `takes up to ${max} samples; got ${request.samples.length}`
18293
+ );
18294
+ }
18295
+ request.samples.forEach((sample, index) => checkSample(model, sample, index));
18296
+ const total = model.constraints.references?.audioSeconds?.total;
18297
+ const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
18298
+ if (total !== void 0 && seconds3 > total) {
18299
+ throw refuse(
18300
+ model,
18301
+ "unsupported_option",
18302
+ `takes up to ${total} s of samples; got ${seconds3} s`
18303
+ );
18304
+ }
18305
+ for (const field of ["transcript", "designSignature"]) {
18306
+ const set = request.samples.filter((s) => s[field]?.trim()).length;
18307
+ if (set !== 0 && set !== request.samples.length) {
18308
+ throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
18309
+ }
18310
+ }
18311
+ return { request: { ...request, model: model.id, title }, warnings: [] };
18312
+ }
18313
+ function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
18314
+ const warnings = [];
18315
+ const prompt = request.prompt.trim();
18316
+ if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
18317
+ const maxChars = promptConventions(model).maxChars;
18318
+ if (maxChars !== void 0 && prompt.length > maxChars) {
18319
+ throw refuse(
18320
+ model,
18321
+ "unsupported_option",
18322
+ `takes up to ${maxChars} characters; got ${prompt.length}`
18323
+ );
18324
+ }
18325
+ const limits = model.constraints.voiceDesign;
18326
+ const resolved = { model: model.id, prompt };
18327
+ const preview2 = request.previewText?.trim();
18328
+ if (preview2) {
18329
+ if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
18330
+ throw refuse(
18331
+ model,
18332
+ "unsupported_option",
18333
+ `takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
18334
+ );
18335
+ }
18336
+ resolved.previewText = preview2;
18337
+ }
18338
+ const language = request.language?.trim();
18339
+ if (language) resolved.language = language;
18340
+ if (request.seed !== void 0) resolved.seed = request.seed;
18341
+ const count2 = request.count ?? model.defaults.count;
18342
+ if (count2 !== void 0) {
18343
+ const cap = limits?.maxCandidates ?? count2;
18344
+ if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
18345
+ if (onUnsupported === "error" || !Number.isInteger(count2)) {
18346
+ throw refuse(
18347
+ model,
18348
+ "unsupported_option",
18349
+ `returns 1-${cap} candidates; got ${count2}`
18350
+ );
18351
+ }
18352
+ const to = Math.min(Math.max(count2, 1), cap);
18353
+ warnings.push({
18354
+ code: "option_ignored",
18355
+ field: "count",
18356
+ from: String(count2),
18357
+ to: String(to),
18358
+ message: `count ${count2} replaced by ${to} for ${model.id}`
18359
+ });
18360
+ resolved.count = to;
18361
+ } else resolved.count = count2;
18362
+ }
18363
+ return { request: resolved, warnings };
18364
+ }
18365
+
17308
18366
  // src/keys.ts
17309
18367
  var ADAPTER_KEYS = {
17310
18368
  "ai-sdk-text": [],
@@ -17317,7 +18375,9 @@ var ADAPTER_KEYS = {
17317
18375
  prodia: ["prodia"],
17318
18376
  higgsfield: ["higgsfield"],
17319
18377
  "xai-video": ["xai"],
17320
- luma: ["luma"]
18378
+ luma: ["luma"],
18379
+ fish: ["fish"],
18380
+ elevenlabs: ["elevenlabs"]
17321
18381
  };
17322
18382
  function hasAll(keys, names) {
17323
18383
  if (!keys) return false;
@@ -17376,6 +18436,8 @@ function keysFromEnv(env, prefix = "") {
17376
18436
  set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
17377
18437
  set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
17378
18438
  set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
18439
+ set("fish", pick2("FISH_AUDIO_API_KEY"));
18440
+ set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
17379
18441
  set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
17380
18442
  const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
17381
18443
  const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
@@ -17398,7 +18460,7 @@ function keysFromEnv(env, prefix = "") {
17398
18460
 
17399
18461
  // src/text.ts
17400
18462
  var import_ai4 = require("ai");
17401
- var import_zod31 = require("zod");
18463
+ var import_zod33 = require("zod");
17402
18464
  function mergeTextProviderOptions(catalog, caller) {
17403
18465
  const merged = {};
17404
18466
  const catalogOptions = catalog.providerOptions ?? {};
@@ -17437,17 +18499,17 @@ function passthroughTextModel(model) {
17437
18499
  pricingKind: "token"
17438
18500
  };
17439
18501
  }
17440
- var perplexityCostSchema = import_zod31.z.object({
17441
- perplexity: import_zod31.z.object({ cost: import_zod31.z.object({ totalCost: import_zod31.z.number().finite().nonnegative() }) })
18502
+ var perplexityCostSchema = import_zod33.z.object({
18503
+ perplexity: import_zod33.z.object({ cost: import_zod33.z.object({ totalCost: import_zod33.z.number().finite().nonnegative() }) })
17442
18504
  });
17443
18505
  function reportedCostUsd(metadata) {
17444
18506
  const parsed = perplexityCostSchema.safeParse(metadata);
17445
18507
  return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
17446
18508
  }
17447
- function textUsageEvent(model, provider, usage3, providerMetadata) {
17448
- const inputTokens = usage3.inputTokens ?? 0;
17449
- const outputTokens = usage3.outputTokens ?? 0;
17450
- const total = usage3.totalTokens ?? inputTokens + outputTokens;
18509
+ function textUsageEvent(model, provider, usage5, providerMetadata) {
18510
+ const inputTokens = usage5.inputTokens ?? 0;
18511
+ const outputTokens = usage5.outputTokens ?? 0;
18512
+ const total = usage5.totalTokens ?? inputTokens + outputTokens;
17451
18513
  const event = {
17452
18514
  model: model.id,
17453
18515
  provider,
@@ -17482,7 +18544,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17482
18544
  return { ...prepared, providerOptions };
17483
18545
  };
17484
18546
  }
17485
- function usage3(results) {
18547
+ function usage5(results) {
17486
18548
  const grouped = /* @__PURE__ */ new Map();
17487
18549
  for (const [index, step] of results.entries()) {
17488
18550
  const target = steps.get(index) ?? initial;
@@ -17506,12 +18568,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
17506
18568
  }
17507
18569
  return [...grouped.values()];
17508
18570
  }
17509
- return { wrap, usage: usage3 };
18571
+ return { wrap, usage: usage5 };
17510
18572
  }
17511
18573
 
17512
18574
  // src/client.ts
17513
18575
  var import_ai5 = require("ai");
17514
- var import_zod32 = require("zod");
18576
+ var import_zod34 = require("zod");
17515
18577
 
17516
18578
  // src/generated-image.ts
17517
18579
  function toGeneratedImage(image) {
@@ -17633,9 +18695,9 @@ function providerJobMethods(kind, deps) {
17633
18695
  if (!methods.result) throw missing3(adapter, ctx.model);
17634
18696
  const result = await methods.result(sub, ctx, webhook);
17635
18697
  const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
17636
- const usage3 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
17637
- await deps.emit(usage3);
17638
- return { ...result, usage: usage3 };
18698
+ const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
18699
+ await deps.emit(usage5);
18700
+ return { ...result, usage: usage5 };
17639
18701
  },
17640
18702
  async cancel(sub, call = {}) {
17641
18703
  const { methods, adapter, ctx } = target(sub.model, call);
@@ -17660,6 +18722,9 @@ var MEDIA_METHODS = {
17660
18722
  lipsync: ["lipsync"],
17661
18723
  dubbing: ["dub"],
17662
18724
  transcription: ["transcribe"],
18725
+ // deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
18726
+ "voice-clone": ["createVoice"],
18727
+ "voice-design": ["designVoice"],
17663
18728
  "video-tool": ["submitVideoTool"],
17664
18729
  // 3D jobs run through submitModel3d, which checks the row type itself; their preflight
17665
18730
  // is model3dInputRefusal, not resolveOptions.
@@ -17674,6 +18739,8 @@ var METHOD_NOUN = {
17674
18739
  lipsync: "a lipsync model",
17675
18740
  dub: "a dubbing model",
17676
18741
  transcribe: "a transcription model",
18742
+ createVoice: "a voice cloning model",
18743
+ designVoice: "a voice design model",
17677
18744
  submitVideoTool: "a video tool"
17678
18745
  };
17679
18746
  function assertMethod(model, method) {
@@ -17716,6 +18783,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
17716
18783
  assertMethod(model, "transcribe");
17717
18784
  return resolveTranscriptionOptions(model, request, onUnsupported);
17718
18785
  }
18786
+ function resolveVoiceCloneCall(model, request) {
18787
+ assertMethod(model, "createVoice");
18788
+ return resolveVoiceCloneOptions(model, request);
18789
+ }
18790
+ function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
18791
+ assertMethod(model, "designVoice");
18792
+ return resolveVoiceDesignOptions(model, request, onUnsupported);
18793
+ }
17719
18794
 
17720
18795
  // src/client-audio.ts
17721
18796
  function noMethod(adapter, model, what) {
@@ -17805,6 +18880,49 @@ function audioNodeMethods(deps) {
17805
18880
  const result = await adapter.transcribe(resolved, ctx);
17806
18881
  return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
17807
18882
  },
18883
+ async createVoice(req, call = {}) {
18884
+ mediaRetryOptions(call);
18885
+ const { abortSignal, ...request } = req;
18886
+ const model = catalog.require(req.model);
18887
+ const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
18888
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18889
+ if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
18890
+ const startedAt = Date.now();
18891
+ const result = await adapter.createVoice(resolved, ctx);
18892
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18893
+ },
18894
+ async designVoice(req, call = {}) {
18895
+ mediaRetryOptions(call);
18896
+ const { abortSignal, ...request } = req;
18897
+ const model = catalog.require(req.model);
18898
+ const { request: resolved, warnings } = resolveVoiceDesignCall(
18899
+ model,
18900
+ request,
18901
+ call.onUnsupported ?? "error"
18902
+ );
18903
+ const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
18904
+ if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
18905
+ const startedAt = Date.now();
18906
+ const result = await adapter.designVoice(resolved, ctx);
18907
+ return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
18908
+ },
18909
+ async deleteVoice(req, call = {}) {
18910
+ mediaRetryOptions(call);
18911
+ const { abortSignal, ...request } = req;
18912
+ const model = catalog.require(req.model);
18913
+ assertMethod(model, "createVoice");
18914
+ const voiceId = request.voiceId.trim();
18915
+ if (!voiceId) {
18916
+ throw new ModelKitError({
18917
+ code: "missing_input",
18918
+ message: `${model.id} requires voiceId`,
18919
+ model: model.id
18920
+ });
18921
+ }
18922
+ const { adapter, ctx } = prepare(model, call, abortSignal, []);
18923
+ if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
18924
+ await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
18925
+ },
17808
18926
  async dub(req, call = {}) {
17809
18927
  mediaRetryOptions(call);
17810
18928
  const { abortSignal, ...request } = req;
@@ -17819,10 +18937,10 @@ function audioNodeMethods(deps) {
17819
18937
  const startedAt = Date.now();
17820
18938
  const outcome = await adapter.dub(resolved, ctx);
17821
18939
  if (outcome.kind === "audio") {
17822
- const { audio, usage: usage3, raw } = outcome.result;
18940
+ const { audio, usage: usage5, raw } = outcome.result;
17823
18941
  return {
17824
18942
  audio,
17825
- usage: await deps.settle(model, usage3, startedAt),
18943
+ usage: await deps.settle(model, usage5, startedAt),
17826
18944
  ...raw !== void 0 && { raw }
17827
18945
  };
17828
18946
  }
@@ -17860,10 +18978,10 @@ function textAbortOptions(sdk, context) {
17860
18978
  if (abortSignal) return { abortSignal };
17861
18979
  return {};
17862
18980
  }
17863
- var catalogId = import_zod32.z.string();
17864
- var exactSize = import_zod32.z.templateLiteral([import_zod32.z.number(), "x", import_zod32.z.number()]);
17865
- var sdkRatio = import_zod32.z.templateLiteral([import_zod32.z.number(), ":", import_zod32.z.number()]);
17866
- var sizeTier = import_zod32.z.enum(["512", "1K", "2K", "4K"]);
18981
+ var catalogId = import_zod34.z.string();
18982
+ var exactSize = import_zod34.z.templateLiteral([import_zod34.z.number(), "x", import_zod34.z.number()]);
18983
+ var sdkRatio = import_zod34.z.templateLiteral([import_zod34.z.number(), ":", import_zod34.z.number()]);
18984
+ var sizeTier = import_zod34.z.enum(["512", "1K", "2K", "4K"]);
17867
18985
  function isCatalogId(model) {
17868
18986
  return catalogId.safeParse(model).success;
17869
18987
  }
@@ -18076,7 +19194,7 @@ function createModelKit(config, adapters) {
18076
19194
  const images = result.images.map(
18077
19195
  (file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
18078
19196
  );
18079
- const usage3 = timed(
19197
+ const usage5 = timed(
18080
19198
  {
18081
19199
  model: model.modelId,
18082
19200
  provider: model.provider,
@@ -18086,8 +19204,8 @@ function createModelKit(config, adapters) {
18086
19204
  },
18087
19205
  startedAt
18088
19206
  );
18089
- await emit(usage3);
18090
- return { image: images[0], images, usage: usage3, raw: result, warnings };
19207
+ await emit(usage5);
19208
+ return { image: images[0], images, usage: usage5, raw: result, warnings };
18091
19209
  }
18092
19210
  function passthroughVideo(req, call) {
18093
19211
  const {
@@ -18163,7 +19281,7 @@ function createModelKit(config, adapters) {
18163
19281
  let settled;
18164
19282
  let failed = false;
18165
19283
  const done = pending.then(async (result) => {
18166
- const usage3 = timed(
19284
+ const usage5 = timed(
18167
19285
  {
18168
19286
  model: model.modelId,
18169
19287
  provider: model.provider,
@@ -18176,10 +19294,10 @@ function createModelKit(config, adapters) {
18176
19294
  );
18177
19295
  settled = {
18178
19296
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
18179
- usage: usage3,
19297
+ usage: usage5,
18180
19298
  raw: result
18181
19299
  };
18182
- await emit(usage3);
19300
+ await emit(usage5);
18183
19301
  return settled;
18184
19302
  });
18185
19303
  done.catch(() => {
@@ -18206,12 +19324,12 @@ function createModelKit(config, adapters) {
18206
19324
  if (settled) return settled;
18207
19325
  const pending = result(opts).then(
18208
19326
  async (out) => {
18209
- const usage3 = timed(
19327
+ const usage5 = timed(
18210
19328
  { ...out.usage, model: model.id, unit: model.usage.unit },
18211
19329
  startedAt
18212
19330
  );
18213
- await emit(usage3);
18214
- return { ...out, usage: usage3 };
19331
+ await emit(usage5);
19332
+ return { ...out, usage: usage5 };
18215
19333
  },
18216
19334
  (cause) => {
18217
19335
  settled = void 0;
@@ -18231,9 +19349,9 @@ function createModelKit(config, adapters) {
18231
19349
  return context(model, signal ? { ...call, signal } : call, warnings);
18232
19350
  },
18233
19351
  async settle(model, event, startedAt) {
18234
- const usage3 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
18235
- await emit(usage3);
18236
- return usage3;
19352
+ const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
19353
+ await emit(usage5);
19354
+ return usage5;
18237
19355
  },
18238
19356
  wrapVideoJob
18239
19357
  });
@@ -18269,11 +19387,11 @@ function createModelKit(config, adapters) {
18269
19387
  });
18270
19388
  const startedAt = Date.now();
18271
19389
  const result = await adapter.generateImage(request, ctx);
18272
- const usage3 = timed(
19390
+ const usage5 = timed(
18273
19391
  { ...result.usage, model: model.id, unit: model.usage.unit },
18274
19392
  startedAt
18275
19393
  );
18276
- await emit(usage3);
19394
+ await emit(usage5);
18277
19395
  const images = result.images.map(toGeneratedImage);
18278
19396
  const first = images[0];
18279
19397
  if (!first)
@@ -18282,7 +19400,7 @@ function createModelKit(config, adapters) {
18282
19400
  message: `${model.id} returned no image`,
18283
19401
  model: model.id
18284
19402
  });
18285
- return { ...result, usage: usage3, image: first, images, warnings };
19403
+ return { ...result, usage: usage5, image: first, images, warnings };
18286
19404
  },
18287
19405
  async generateVideo(req, call = {}) {
18288
19406
  mediaRetryOptions(call);
@@ -18381,12 +19499,12 @@ function createModelKit(config, adapters) {
18381
19499
  }
18382
19500
  const startedAt = Date.now();
18383
19501
  const result = await adapter.generateAudio(resolved, ctx);
18384
- const usage3 = timed(
19502
+ const usage5 = timed(
18385
19503
  { ...result.usage, model: model.id, unit: model.usage.unit },
18386
19504
  startedAt
18387
19505
  );
18388
- await emit(usage3);
18389
- return { ...result, usage: usage3 };
19506
+ await emit(usage5);
19507
+ return { ...result, usage: usage5 };
18390
19508
  },
18391
19509
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
18392
19510
  mediaRetryOptions(call);
@@ -18466,8 +19584,8 @@ function createModelKit(config, adapters) {
18466
19584
  options.prepareStep ?? options.experimental_prepareStep
18467
19585
  ),
18468
19586
  onFinish: async (event) => {
18469
- for (const usage3 of steps.usage(event.steps))
18470
- await emit(textTimed(withRowUnit(usage3), event.steps.length, startedAt));
19587
+ for (const usage5 of steps.usage(event.steps))
19588
+ await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
18471
19589
  await callerOnFinish?.(event);
18472
19590
  }
18473
19591
  });
@@ -18586,10 +19704,12 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
18586
19704
  dataOnlyCapable,
18587
19705
  describe,
18588
19706
  describeThrown,
19707
+ elevenLabsAdapter,
18589
19708
  experimental_generateImage,
18590
19709
  falAdapter,
18591
19710
  falWebhookBodySchema,
18592
19711
  fileCatalogCache,
19712
+ fishAdapter,
18593
19713
  generateAudio,
18594
19714
  generateImage,
18595
19715
  generateObject,
@@ -18642,6 +19762,8 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
18642
19762
  resolveTranscriptionOptions,
18643
19763
  resolveVideoOptions,
18644
19764
  resolveVoiceChangeOptions,
19765
+ resolveVoiceCloneOptions,
19766
+ resolveVoiceDesignOptions,
18645
19767
  shouldRetry,
18646
19768
  sleep,
18647
19769
  sortCatalogRows,