@happyvertical/ai 0.86.4 → 0.87.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.
Files changed (52) hide show
  1. package/README.md +60 -2
  2. package/dist/chunks/{anthropic-DuYUnw8j.js → anthropic-ByuqC5mC.js} +4 -4
  3. package/dist/chunks/{anthropic-DuYUnw8j.js.map → anthropic-ByuqC5mC.js.map} +1 -1
  4. package/dist/chunks/{bedrock-ikQJAwWB.js → bedrock-BeVCmkrS.js} +3 -3
  5. package/dist/chunks/{bedrock-ikQJAwWB.js.map → bedrock-BeVCmkrS.js.map} +1 -1
  6. package/dist/chunks/{bifrost-CaYhelVL.js → bifrost-DvYZ3LNf.js} +4 -4
  7. package/dist/chunks/{bifrost-CaYhelVL.js.map → bifrost-DvYZ3LNf.js.map} +1 -1
  8. package/dist/chunks/{byteplus-modelark-B8l8sPXu.js → byteplus-modelark-DaF0U4n1.js} +4 -4
  9. package/dist/chunks/{byteplus-modelark-B8l8sPXu.js.map → byteplus-modelark-DaF0U4n1.js.map} +1 -1
  10. package/dist/chunks/{claude-cli-DeTKk9nu.js → claude-cli-BH_C62dV.js} +3 -3
  11. package/dist/chunks/{claude-cli-DeTKk9nu.js.map → claude-cli-BH_C62dV.js.map} +1 -1
  12. package/dist/chunks/{gateway-admin-DJXEDpUP.js → gateway-admin-B4RSBDmo.js} +2 -2
  13. package/dist/chunks/{gateway-admin-DJXEDpUP.js.map → gateway-admin-B4RSBDmo.js.map} +1 -1
  14. package/dist/chunks/{gemini-BT8fjXWz.js → gemini-GQdugon1.js} +4 -4
  15. package/dist/chunks/{gemini-BT8fjXWz.js.map → gemini-GQdugon1.js.map} +1 -1
  16. package/dist/chunks/{huggingface-CqzyxeLB.js → huggingface-DxPspM6Q.js} +3 -3
  17. package/dist/chunks/{huggingface-CqzyxeLB.js.map → huggingface-DxPspM6Q.js.map} +1 -1
  18. package/dist/chunks/{litellm-viqTuSY8.js → litellm-nOCNI7Vd.js} +4 -4
  19. package/dist/chunks/{litellm-viqTuSY8.js.map → litellm-nOCNI7Vd.js.map} +1 -1
  20. package/dist/chunks/{ollama-CdWqwZ05.js → ollama-BrB6bjnz.js} +3 -3
  21. package/dist/chunks/{ollama-CdWqwZ05.js.map → ollama-BrB6bjnz.js.map} +1 -1
  22. package/dist/chunks/{openai-BgrK3OfW.js → openai-BuwvBruA.js} +4 -4
  23. package/dist/chunks/{openai-BgrK3OfW.js.map → openai-BuwvBruA.js.map} +1 -1
  24. package/dist/chunks/{openai-compat-video-D_U7jo0d.js → openai-compat-video-DNE1Yvp6.js} +4 -4
  25. package/dist/chunks/{openai-compat-video-D_U7jo0d.js.map → openai-compat-video-DNE1Yvp6.js.map} +1 -1
  26. package/dist/chunks/{qwen-tts-BXjzY7DX.js → qwen-tts-CAh1upii.js} +2 -2
  27. package/dist/chunks/{qwen-tts-BXjzY7DX.js.map → qwen-tts-CAh1upii.js.map} +1 -1
  28. package/dist/chunks/{rate-limit-DgEhanDL.js → rate-limit-C2oPwLGI.js} +6 -5
  29. package/dist/chunks/rate-limit-C2oPwLGI.js.map +1 -0
  30. package/dist/chunks/{safety-C415clBm.js → safety-ClfpyKEN.js} +2 -2
  31. package/dist/chunks/{safety-C415clBm.js.map → safety-ClfpyKEN.js.map} +1 -1
  32. package/dist/chunks/seevio-Bbu_hTUF.js +451 -0
  33. package/dist/chunks/seevio-Bbu_hTUF.js.map +1 -0
  34. package/dist/chunks/{src-CU4qWJ2c.js → src-B091S0I4.js} +23 -16
  35. package/dist/chunks/src-B091S0I4.js.map +1 -0
  36. package/dist/chunks/{types-CINwUPDo.js → types-sSecpd_N.js} +3 -2
  37. package/dist/chunks/types-sSecpd_N.js.map +1 -0
  38. package/dist/index.js +3 -3
  39. package/dist/node/factory.d.ts +2 -1
  40. package/dist/node/factory.d.ts.map +1 -1
  41. package/dist/node.js +21 -6
  42. package/dist/node.js.map +1 -1
  43. package/dist/shared/factory.d.ts.map +1 -1
  44. package/dist/shared/providers/seevio.d.ts +48 -0
  45. package/dist/shared/providers/seevio.d.ts.map +1 -0
  46. package/dist/shared/rate-limit.d.ts.map +1 -1
  47. package/dist/shared/types.d.ts +61 -2
  48. package/dist/shared/types.d.ts.map +1 -1
  49. package/package.json +2 -2
  50. package/dist/chunks/rate-limit-DgEhanDL.js.map +0 -1
  51. package/dist/chunks/src-CU4qWJ2c.js.map +0 -1
  52. package/dist/chunks/types-CINwUPDo.js.map +0 -1
@@ -0,0 +1,451 @@
1
+ import { r as AuthenticationError, s as RateLimitError, t as AIError } from "./types-sSecpd_N.js";
2
+ import { n as extractRetryAfterSeconds } from "./rate-limit-C2oPwLGI.js";
3
+ import { a as normalizeBaseAIOptions } from "./safety-ClfpyKEN.js";
4
+ import { t as emitUsage } from "./usage-C1Y1Nlg4.js";
5
+ import { ValidationError } from "@happyvertical/utils";
6
+ //#region src/shared/providers/seevio.ts
7
+ /**
8
+ * Seevio's native asynchronous Seedance 2.5 video-generation provider.
9
+ *
10
+ * Seevio is deliberately implemented as its own raw-HTTP adapter rather than
11
+ * being shaped to ModelArk. Both services can run Seedance, but their task,
12
+ * billing, and media contracts differ.
13
+ *
14
+ * @see https://seevio.ai/api-docs
15
+ */
16
+ var DEFAULT_BASE_URL = "https://api.seevio.ai";
17
+ var DEFAULT_RESULT_ORIGIN = "https://cdn.seevio.ai";
18
+ var MODEL = "seedance-2-5";
19
+ var MIN_POLL_INTERVAL_MS = 1e4;
20
+ var MAX_REDIRECTS = 5;
21
+ var DEFAULT_MAX_RESULT_BYTES = 200 * 1024 * 1024;
22
+ var COMPLETED_SNAPSHOT_TTL_MS = MIN_POLL_INTERVAL_MS;
23
+ var MAX_COMPLETED_SNAPSHOTS = 128;
24
+ function ensureOptions(options) {
25
+ const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).trim().replace(/\/+$/, "");
26
+ if (new URL(baseUrl).protocol !== "https:") throw new ValidationError("seevio baseUrl must use HTTPS", { provider: "seevio" });
27
+ const origins = options.resultUrlOrigins?.length ? options.resultUrlOrigins : [DEFAULT_RESULT_ORIGIN];
28
+ for (const origin of origins) {
29
+ const parsed = new URL(origin);
30
+ if (parsed.protocol !== "https:" || parsed.origin !== origin.replace(/\/+$/, "")) throw new ValidationError("seevio resultUrlOrigins must contain HTTPS origins only", { provider: "seevio" });
31
+ }
32
+ if (options.maxResultBytes !== void 0 && (!Number.isSafeInteger(options.maxResultBytes) || options.maxResultBytes <= 0)) throw new ValidationError("seevio maxResultBytes must be a positive safe integer", { provider: "seevio" });
33
+ return {
34
+ ...options,
35
+ baseUrl,
36
+ resultUrlOrigins: origins.map((origin) => origin.replace(/\/+$/, ""))
37
+ };
38
+ }
39
+ function validatedHttpsUrl(value, label) {
40
+ let url;
41
+ try {
42
+ url = new URL(value);
43
+ } catch {
44
+ throw new ValidationError(`${label} must be a valid public HTTPS URL`, { provider: "seevio" });
45
+ }
46
+ if (url.protocol !== "https:") throw new ValidationError(`${label} must use HTTPS`, { provider: "seevio" });
47
+ const host = url.hostname.toLowerCase();
48
+ if (url.username || url.password || host === "localhost" || host.endsWith(".localhost") || host.includes(":") || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) throw new ValidationError(`${label} must not use credentials, localhost, or an IP-literal host`, { provider: "seevio" });
49
+ return url.toString();
50
+ }
51
+ function normalizeBilling(task) {
52
+ if (task.credits === void 0 && !task.billing_status) return void 0;
53
+ const normalized = [
54
+ "reserved",
55
+ "charged",
56
+ "refunded",
57
+ "refund_failed"
58
+ ].includes(task.billing_status || "") ? task.billing_status : void 0;
59
+ return {
60
+ ...task.credits !== void 0 ? { credits: task.credits } : {},
61
+ ...normalized ? { status: normalized } : {},
62
+ ...!normalized && task.billing_status ? { rawStatus: task.billing_status } : {}
63
+ };
64
+ }
65
+ /** Native Seevio adapter for the pinned `seedance-2-5` model. */
66
+ var SeevioProvider = class {
67
+ options;
68
+ resultOrigins;
69
+ nextPollAt = /* @__PURE__ */ new Map();
70
+ completedSnapshots = /* @__PURE__ */ new Map();
71
+ /** Creates a Seevio task client using the documented HTTPS API root. */
72
+ constructor(options) {
73
+ this.options = normalizeBaseAIOptions(ensureOptions(options));
74
+ this.resultOrigins = new Set(this.options.resultUrlOrigins);
75
+ }
76
+ async request(path, options = {}) {
77
+ const text = await (await this.rawRequest(path, options)).text();
78
+ return text ? JSON.parse(text) : {};
79
+ }
80
+ async rawRequest(path, options = {}) {
81
+ if (options.signal?.aborted) throw new AIError("Seevio request aborted by caller", "AI_ABORTED", "seevio");
82
+ const controller = new AbortController();
83
+ const timeoutMs = options.timeout ?? this.options.timeout;
84
+ let timedOut = false;
85
+ const timer = setTimeout(() => {
86
+ timedOut = true;
87
+ controller.abort();
88
+ }, timeoutMs);
89
+ const abort = () => controller.abort(options.signal?.reason);
90
+ options.signal?.addEventListener("abort", abort, { once: true });
91
+ if (options.signal?.aborted) abort();
92
+ try {
93
+ let response;
94
+ try {
95
+ response = await fetch(`${this.options.baseUrl}${path}`, {
96
+ method: options.method || "GET",
97
+ headers: {
98
+ Authorization: `Bearer ${this.options.apiKey ?? ""}`,
99
+ ...options.body !== void 0 ? { "Content-Type": "application/json" } : {},
100
+ ...this.options.headers || {}
101
+ },
102
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
103
+ signal: controller.signal
104
+ });
105
+ } catch (error) {
106
+ if (timedOut) throw new AIError(`Seevio request to ${path} timed out after ${timeoutMs}ms`, "AI_TIMEOUT", "seevio", void 0, options.method !== "POST");
107
+ if (options.signal?.aborted) throw new AIError("Seevio request aborted by caller", "AI_ABORTED", "seevio");
108
+ throw new AIError(`Network error calling Seevio ${path}: ${error instanceof Error ? error.message : String(error)}`, "NETWORK_ERROR", "seevio", void 0, options.method !== "POST");
109
+ }
110
+ if (response.status === 404 && options.allowNotFound) return response;
111
+ if (response.ok) return response;
112
+ const errorText = await response.text();
113
+ let payload = {};
114
+ try {
115
+ payload = JSON.parse(errorText);
116
+ } catch {}
117
+ const message = payload.error?.message || `Seevio request to ${path} failed with HTTP ${response.status}`;
118
+ if (response.status === 401) throw new AuthenticationError("seevio");
119
+ if (response.status === 403) throw new AIError(message, "SEEVIO_FORBIDDEN", "seevio");
120
+ if (response.status === 402) throw new AIError(message, "INSUFFICIENT_CREDITS", "seevio");
121
+ if (response.status === 429) throw new RateLimitError("seevio", extractRetryAfterSeconds({ headers: response.headers }));
122
+ throw new AIError(message, "SEEVIO_REQUEST_FAILED", "seevio", void 0, response.status >= 500 && options.method !== "POST");
123
+ } finally {
124
+ clearTimeout(timer);
125
+ options.signal?.removeEventListener("abort", abort);
126
+ }
127
+ }
128
+ assertReviewedResultUrl(value) {
129
+ const url = validatedHttpsUrl(value, "Seevio result URL");
130
+ if (!this.resultOrigins.has(new URL(url).origin)) throw new AIError("Seevio returned a result URL outside configured reviewed origins", "UNTRUSTED_RESULT_URL", "seevio");
131
+ return url;
132
+ }
133
+ async downloadReviewedResult(initialUrl) {
134
+ let current = this.assertReviewedResultUrl(initialUrl);
135
+ const controller = new AbortController();
136
+ const timer = setTimeout(() => controller.abort(), this.options.timeout);
137
+ const maxBytes = this.options.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES;
138
+ try {
139
+ for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {
140
+ const response = await fetch(current, {
141
+ redirect: "manual",
142
+ signal: controller.signal
143
+ });
144
+ if (response.status >= 300 && response.status < 400) {
145
+ const location = response.headers.get("location");
146
+ if (!location) throw new AIError("Seevio result redirect omitted Location", "SEEVIO_RESULT_DOWNLOAD_FAILED", "seevio");
147
+ current = this.assertReviewedResultUrl(new URL(location, current).toString());
148
+ continue;
149
+ }
150
+ if (!response.ok) throw new AIError(`Seevio result download failed with HTTP ${response.status}`, "SEEVIO_RESULT_DOWNLOAD_FAILED", "seevio");
151
+ const contentType = response.headers.get("content-type");
152
+ if (!contentType?.toLowerCase().startsWith("video/")) throw new AIError(`Seevio result download returned non-video content type ${contentType}`, "SEEVIO_RESULT_MIME_INVALID", "seevio");
153
+ const contentLength = response.headers.get("content-length");
154
+ if (contentLength && Number(contentLength) > maxBytes) throw new AIError(`Seevio result exceeds configured ${maxBytes}-byte download limit`, "SEEVIO_RESULT_TOO_LARGE", "seevio");
155
+ if (!response.body) throw new AIError("Seevio result download had no response body", "SEEVIO_RESULT_DOWNLOAD_FAILED", "seevio");
156
+ const chunks = [];
157
+ let size = 0;
158
+ const reader = response.body.getReader();
159
+ for (;;) {
160
+ const { done, value } = await reader.read();
161
+ if (done) break;
162
+ size += value.byteLength;
163
+ if (size > maxBytes) {
164
+ await reader.cancel();
165
+ throw new AIError(`Seevio result exceeds configured ${maxBytes}-byte download limit`, "SEEVIO_RESULT_TOO_LARGE", "seevio");
166
+ }
167
+ chunks.push(value);
168
+ }
169
+ return {
170
+ data: Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))),
171
+ mimeType: contentType,
172
+ url: current
173
+ };
174
+ }
175
+ throw new AIError("Seevio result exceeded the maximum redirect count", "SEEVIO_RESULT_DOWNLOAD_FAILED", "seevio");
176
+ } catch (error) {
177
+ if (controller.signal.aborted) throw new AIError(`Seevio result download timed out after ${this.options.timeout}ms`, "AI_TIMEOUT", "seevio", void 0, true);
178
+ throw error;
179
+ } finally {
180
+ clearTimeout(timer);
181
+ }
182
+ }
183
+ mediaUrls(options) {
184
+ const images = (options.referenceImages ?? []).map((reference) => {
185
+ if (typeof reference.image !== "string" || reference.image.startsWith("data:")) throw new ValidationError("Seevio referenceImages must be public HTTPS URLs; it cannot retrieve bytes or data URLs", { provider: "seevio" });
186
+ return validatedHttpsUrl(reference.image, "Seevio reference image");
187
+ });
188
+ const references = options.referenceMedia ?? [];
189
+ if (references.length + images.length > 50) throw new ValidationError("Seevio accepts at most 50 total reference assets", { provider: "seevio" });
190
+ const collect = (type) => references.filter((reference) => reference.type === type).map((reference) => validatedHttpsUrl(reference.url, `Seevio ${type} reference`));
191
+ const mediaImages = collect("image");
192
+ const videos = collect("video");
193
+ const audio = collect("audio");
194
+ if (images.length + mediaImages.length > 30 || videos.length > 10 || audio.length > 10) throw new ValidationError("Seevio reference limits are 30 images, 10 videos, and 10 audio files", { provider: "seevio" });
195
+ for (const reference of references) if ((reference.type === "video" || reference.type === "audio") && reference.durationSeconds !== void 0 && (!Number.isFinite(reference.durationSeconds) || reference.durationSeconds < 2 || reference.durationSeconds > 30)) throw new ValidationError("Seevio video/audio reference durations must be 2-30 seconds when supplied", { provider: "seevio" });
196
+ for (const [label, type] of [["video", "video"], ["audio", "audio"]]) if (references.filter((reference) => reference.type === type).flatMap((reference) => reference.durationSeconds === void 0 ? [] : [reference.durationSeconds]).reduce((total, duration) => total + duration, 0) > 30) throw new ValidationError(`Seevio ${label} reference durations must total no more than 30 seconds`, { provider: "seevio" });
197
+ return {
198
+ images: [...images, ...mediaImages],
199
+ videos,
200
+ audio
201
+ };
202
+ }
203
+ async pollTask(jobId) {
204
+ const now = Date.now();
205
+ for (const [knownJobId, expiry] of this.nextPollAt) if (expiry <= now) this.nextPollAt.delete(knownJobId);
206
+ const next = this.nextPollAt.get(jobId);
207
+ if (next && now < next) throw new AIError(`Seevio tasks may be polled no more than once every 10 seconds; retry after ${Math.ceil((next - now) / 1e3)} seconds`, "VIDEO_POLL_TOO_FREQUENT", "seevio");
208
+ const expiry = now + MIN_POLL_INTERVAL_MS;
209
+ this.nextPollAt.set(jobId, expiry);
210
+ const cleanup = setTimeout(() => {
211
+ if (this.nextPollAt.get(jobId) === expiry) this.nextPollAt.delete(jobId);
212
+ }, MIN_POLL_INTERVAL_MS);
213
+ if (typeof cleanup === "object" && "unref" in cleanup) cleanup.unref();
214
+ const task = await this.request(`/v1/tasks/${encodeURIComponent(jobId)}`);
215
+ if (task.status === "completed") {
216
+ if (!this.completedSnapshots.has(jobId)) {
217
+ const oldestJobId = this.completedSnapshots.keys().next().value;
218
+ if (this.completedSnapshots.size >= MAX_COMPLETED_SNAPSHOTS && oldestJobId !== void 0) this.completedSnapshots.delete(oldestJobId);
219
+ }
220
+ this.completedSnapshots.set(jobId, {
221
+ task,
222
+ recordedAt: Date.now()
223
+ });
224
+ }
225
+ return task;
226
+ }
227
+ completedSnapshot(jobId) {
228
+ const snapshot = this.completedSnapshots.get(jobId);
229
+ if (!snapshot) return void 0;
230
+ if (Date.now() - snapshot.recordedAt >= COMPLETED_SNAPSHOT_TTL_MS) {
231
+ this.completedSnapshots.delete(jobId);
232
+ return;
233
+ }
234
+ return snapshot.task;
235
+ }
236
+ /** Submits one unambiguous, non-retried Seedance 2.5 task. */
237
+ async submitVideoGenerationJob(options) {
238
+ const startTime = Date.now();
239
+ if ((options.model || this.options.defaultModel || MODEL) !== MODEL) throw new ValidationError(`Seevio provider supports the pinned model ${MODEL}`, { provider: "seevio" });
240
+ if (!options.prompt?.trim()) throw new ValidationError("Seevio requires a non-empty prompt", { provider: "seevio" });
241
+ if (options.seed !== void 0) throw new ValidationError("seed is not supported by Seevio Seedance 2.5", { provider: "seevio" });
242
+ const duration = options.durationSeconds ?? 5;
243
+ if (!Number.isInteger(duration) || duration < 4 || duration > 30) throw new ValidationError("Seevio durationSeconds must be an integer from 4 through 30", { provider: "seevio" });
244
+ const resolution = options.resolution ?? "720p";
245
+ if (resolution !== "480p" && resolution !== "720p") throw new ValidationError("Seevio resolution must be 480p or 720p", { provider: "seevio" });
246
+ const { images, videos, audio } = this.mediaUrls(options);
247
+ const isImageToVideo = images.length >= 1 && images.length <= 2 && videos.length === 0 && audio.length === 0;
248
+ const generationType = isImageToVideo ? "image-to-video" : images.length || videos.length || audio.length ? "reference-to-video" : "text-to-video";
249
+ const aspectRatio = options.aspectRatio ?? "adaptive";
250
+ if (![
251
+ "adaptive",
252
+ "16:9",
253
+ "9:16",
254
+ "1:1",
255
+ "4:3",
256
+ "3:4",
257
+ "21:9"
258
+ ].includes(aspectRatio)) throw new ValidationError("Unsupported Seevio aspectRatio", { provider: "seevio" });
259
+ if (isImageToVideo && aspectRatio !== "adaptive") throw new ValidationError("Seevio image-to-video requires aspectRatio: adaptive", { provider: "seevio" });
260
+ const input = {
261
+ prompt: options.prompt.trim(),
262
+ generation_type: generationType,
263
+ duration,
264
+ aspect_ratio: aspectRatio,
265
+ resolution,
266
+ generate_audio: options.generateAudio ?? true,
267
+ return_last_frame: options.returnLastFrame ?? false,
268
+ ...images.length ? { image_urls: images } : {},
269
+ ...videos.length ? { video_urls: videos } : {},
270
+ ...audio.length ? { audio_urls: audio } : {}
271
+ };
272
+ const created = await this.request("/v1/videos/generations", {
273
+ method: "POST",
274
+ body: {
275
+ model: MODEL,
276
+ input
277
+ },
278
+ signal: options.signal,
279
+ timeout: options.timeout
280
+ });
281
+ if (!created.taskId) throw new AIError("Seevio accepted submission without a taskId", "SEEVIO_INVALID_RESPONSE", "seevio");
282
+ emitUsage(this.options, "seevio", "submitVideoGenerationJob", MODEL, void 0, startTime, {
283
+ durationSeconds: String(duration),
284
+ resolution,
285
+ aspectRatio,
286
+ ...options.usageTags
287
+ });
288
+ return {
289
+ jobId: created.taskId,
290
+ provider: "seevio",
291
+ model: MODEL,
292
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
293
+ raw: created.credits === void 0 ? void 0 : {
294
+ credits: created.credits,
295
+ billingStatus: "reserved"
296
+ }
297
+ };
298
+ }
299
+ /** Returns a normalized task snapshot, enforcing Seevio's 10-second poll cadence. */
300
+ async getVideoGenerationJob(handle) {
301
+ return this.mapTask(await this.pollTask(handle.jobId));
302
+ }
303
+ /** Downloads a completed video while validating the initial URL and every redirect. */
304
+ async fetchVideoGenerationResult(handle) {
305
+ const task = this.completedSnapshot(handle.jobId) ?? await this.pollTask(handle.jobId);
306
+ const status = this.mapTask(task);
307
+ if (status.status !== "succeeded" || !status.result?.url) throw new AIError(`Seevio job ${handle.jobId} has not succeeded (status: ${status.status})`, "VIDEO_JOB_NOT_READY", "seevio", handle.model);
308
+ try {
309
+ const downloaded = await this.downloadReviewedResult(status.result.url);
310
+ return {
311
+ ...status.result,
312
+ ...downloaded
313
+ };
314
+ } finally {
315
+ this.completedSnapshots.delete(handle.jobId);
316
+ }
317
+ }
318
+ /** Reports cancellation as unsupported because Seevio documents no cancellation endpoint. */
319
+ async cancelVideoGenerationJob(_handle) {
320
+ throw new AIError("Seevio does not document a video-task cancellation endpoint", "NOT_IMPLEMENTED", "seevio");
321
+ }
322
+ /** Performs an unbilled random task-id probe; an authenticated 404 is valid access. */
323
+ async validateVideoGenerationAccess() {
324
+ const response = await this.rawRequest(`/v1/tasks/have-ai-access-probe-${crypto.randomUUID()}`, { allowNotFound: true });
325
+ return response.ok || response.status === 404;
326
+ }
327
+ mapTask(task) {
328
+ const billing = normalizeBilling(task);
329
+ if (task.status === "queued") return {
330
+ status: "queued",
331
+ ...billing ? { billing } : {}
332
+ };
333
+ if (task.status === "generating") return {
334
+ status: "running",
335
+ ...billing ? { billing } : {}
336
+ };
337
+ if (task.status === "failed") return {
338
+ status: "failed",
339
+ error: task.failed_reason || "Seevio video generation failed",
340
+ ...billing ? { billing } : {}
341
+ };
342
+ if (task.status !== "completed") return {
343
+ status: "running",
344
+ rawStatus: task.status,
345
+ ...billing ? { billing } : {}
346
+ };
347
+ const url = task.data?.results?.[0];
348
+ if (!url) return {
349
+ status: "failed",
350
+ error: "Seevio reported completion with no result URL",
351
+ ...billing ? { billing } : {}
352
+ };
353
+ return {
354
+ status: "succeeded",
355
+ result: {
356
+ url: this.assertReviewedResultUrl(url),
357
+ mimeType: "video/mp4",
358
+ ...task.data?.video_expires_at ? { expiresAt: task.data.video_expires_at } : {},
359
+ ...task.data?.last_frame_url ? { lastFrameUrl: this.assertReviewedResultUrl(task.data.last_frame_url) } : {}
360
+ },
361
+ ...billing ? { billing } : {}
362
+ };
363
+ }
364
+ /** Lists the single intentional Seevio model selection. */
365
+ async getModels() {
366
+ return [{
367
+ id: MODEL,
368
+ name: "Seedance 2.5",
369
+ description: "Seevio Seedance 2.5 async video generation",
370
+ contextLength: 0,
371
+ capabilities: ["video_generation"],
372
+ supportsFunctions: false,
373
+ supportsVision: true
374
+ }];
375
+ }
376
+ /** Reports Seevio's video-only capability surface. */
377
+ async getCapabilities() {
378
+ return {
379
+ chat: false,
380
+ completion: false,
381
+ embeddings: false,
382
+ streaming: false,
383
+ functions: false,
384
+ vision: false,
385
+ fineTuning: false,
386
+ imageEmbeddings: false,
387
+ imageGeneration: false,
388
+ videoGeneration: true,
389
+ tts: false,
390
+ voiceCloning: false,
391
+ voiceDesign: false,
392
+ maxContextLength: 0,
393
+ supportedOperations: [
394
+ "submitVideoGenerationJob",
395
+ "getVideoGenerationJob",
396
+ "fetchVideoGenerationResult"
397
+ ]
398
+ };
399
+ }
400
+ unsupported() {
401
+ throw new AIError("This operation is not supported by the Seevio video-only provider.", "NOT_IMPLEMENTED", "seevio");
402
+ }
403
+ /** @inheritdoc */ async chat(_messages, _options) {
404
+ return this.unsupported();
405
+ }
406
+ /** @inheritdoc */ async complete(_prompt, _options) {
407
+ return this.unsupported();
408
+ }
409
+ /** @inheritdoc */ async message(_text, _options) {
410
+ return this.unsupported();
411
+ }
412
+ /** @inheritdoc */ async embed(_text, _options) {
413
+ return this.unsupported();
414
+ }
415
+ /** @inheritdoc */ async embedImage(_image, _options) {
416
+ return this.unsupported();
417
+ }
418
+ /** @inheritdoc */ async describeImage(_image, _prompt, _options) {
419
+ return this.unsupported();
420
+ }
421
+ /** @inheritdoc */ async generateImage(_prompt, _options) {
422
+ return this.unsupported();
423
+ }
424
+ /** @inheritdoc */ stream(_messages, _options) {
425
+ const error = new AIError("Chat streaming is not supported by the Seevio video-only provider.", "NOT_IMPLEMENTED", "seevio");
426
+ return { [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }) };
427
+ }
428
+ /** @inheritdoc */ async countTokens(_text) {
429
+ return this.unsupported();
430
+ }
431
+ /** @inheritdoc */ async synthesizeSpeech(_text, _options) {
432
+ return this.unsupported();
433
+ }
434
+ /** @inheritdoc */ streamSpeech(_text, _options) {
435
+ const error = new AIError("TTS streaming is not supported by the Seevio video-only provider.", "NOT_IMPLEMENTED", "seevio");
436
+ return { [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }) };
437
+ }
438
+ /** @inheritdoc */ async cloneVoice(_options) {
439
+ return this.unsupported();
440
+ }
441
+ /** @inheritdoc */ async designVoice(_options) {
442
+ return this.unsupported();
443
+ }
444
+ /** @inheritdoc */ async getVoices(_options) {
445
+ return this.unsupported();
446
+ }
447
+ };
448
+ //#endregion
449
+ export { SeevioProvider };
450
+
451
+ //# sourceMappingURL=seevio-Bbu_hTUF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seevio-Bbu_hTUF.js","names":[],"sources":["../../src/shared/providers/seevio.ts"],"sourcesContent":["/**\n * Seevio's native asynchronous Seedance 2.5 video-generation provider.\n *\n * Seevio is deliberately implemented as its own raw-HTTP adapter rather than\n * being shaped to ModelArk. Both services can run Seedance, but their task,\n * billing, and media contracts differ.\n *\n * @see https://seevio.ai/api-docs\n */\n\nimport { ValidationError } from '@happyvertical/utils';\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport { normalizeBaseAIOptions } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n SeevioOptions,\n TTSOptions,\n TTSResponse,\n VideoGenerationBillingMetadata,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationReferenceMedia,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError, RateLimitError } from '../types';\nimport { emitUsage } from './usage';\n\nconst DEFAULT_BASE_URL = 'https://api.seevio.ai';\nconst DEFAULT_RESULT_ORIGIN = 'https://cdn.seevio.ai';\nconst MODEL = 'seedance-2-5';\nconst MIN_POLL_INTERVAL_MS = 10_000;\nconst MAX_REDIRECTS = 5;\nconst DEFAULT_MAX_RESULT_BYTES = 200 * 1024 * 1024;\nconst COMPLETED_SNAPSHOT_TTL_MS = MIN_POLL_INTERVAL_MS;\nconst MAX_COMPLETED_SNAPSHOTS = 128;\n\ninterface SeevioTask {\n id: string;\n status: string;\n model?: string;\n billing_status?: string;\n credits?: number;\n failed_reason?: string | null;\n data?: {\n results?: string[];\n video_expires_at?: string;\n last_frame_url?: string | null;\n processing_time?: number;\n };\n}\n\ninterface SeevioErrorResponse {\n error?: {\n code?: string;\n message?: string;\n required?: number;\n available?: number;\n };\n}\n\ninterface SeevioCreateResponse {\n taskId: string;\n credits?: number;\n}\n\ninterface SeevioInput {\n prompt: string;\n generation_type: 'text-to-video' | 'image-to-video' | 'reference-to-video';\n image_urls?: string[];\n video_urls?: string[];\n audio_urls?: string[];\n duration: number;\n aspect_ratio: 'adaptive' | '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | '21:9';\n resolution: '480p' | '720p';\n generate_audio: boolean;\n return_last_frame: boolean;\n}\n\nfunction ensureOptions(options: SeevioOptions): SeevioOptions {\n const baseUrl = (options.baseUrl || DEFAULT_BASE_URL)\n .trim()\n .replace(/\\/+$/, '');\n const parsedBaseUrl = new URL(baseUrl);\n if (parsedBaseUrl.protocol !== 'https:') {\n throw new ValidationError('seevio baseUrl must use HTTPS', {\n provider: 'seevio',\n });\n }\n const origins = options.resultUrlOrigins?.length\n ? options.resultUrlOrigins\n : [DEFAULT_RESULT_ORIGIN];\n for (const origin of origins) {\n const parsed = new URL(origin);\n if (\n parsed.protocol !== 'https:' ||\n parsed.origin !== origin.replace(/\\/+$/, '')\n ) {\n throw new ValidationError(\n 'seevio resultUrlOrigins must contain HTTPS origins only',\n {\n provider: 'seevio',\n },\n );\n }\n }\n if (\n options.maxResultBytes !== undefined &&\n (!Number.isSafeInteger(options.maxResultBytes) ||\n options.maxResultBytes <= 0)\n ) {\n throw new ValidationError(\n 'seevio maxResultBytes must be a positive safe integer',\n { provider: 'seevio' },\n );\n }\n return {\n ...options,\n baseUrl,\n resultUrlOrigins: origins.map((origin) => origin.replace(/\\/+$/, '')),\n };\n}\n\nfunction validatedHttpsUrl(value: string, label: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new ValidationError(`${label} must be a valid public HTTPS URL`, {\n provider: 'seevio',\n });\n }\n if (url.protocol !== 'https:') {\n throw new ValidationError(`${label} must use HTTPS`, {\n provider: 'seevio',\n });\n }\n const host = url.hostname.toLowerCase();\n if (\n url.username ||\n url.password ||\n host === 'localhost' ||\n host.endsWith('.localhost') ||\n host.includes(':') ||\n /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host)\n ) {\n throw new ValidationError(\n `${label} must not use credentials, localhost, or an IP-literal host`,\n { provider: 'seevio' },\n );\n }\n return url.toString();\n}\n\nfunction normalizeBilling(\n task: SeevioTask,\n): VideoGenerationBillingMetadata | undefined {\n if (task.credits === undefined && !task.billing_status) return undefined;\n const normalized = [\n 'reserved',\n 'charged',\n 'refunded',\n 'refund_failed',\n ].includes(task.billing_status || '')\n ? (task.billing_status as VideoGenerationBillingMetadata['status'])\n : undefined;\n return {\n ...(task.credits !== undefined ? { credits: task.credits } : {}),\n ...(normalized ? { status: normalized } : {}),\n ...(!normalized && task.billing_status\n ? { rawStatus: task.billing_status }\n : {}),\n };\n}\n\n/** Native Seevio adapter for the pinned `seedance-2-5` model. */\nexport class SeevioProvider implements AIInterface {\n private readonly options: SeevioOptions;\n private readonly resultOrigins: Set<string>;\n private readonly nextPollAt = new Map<string, number>();\n private readonly completedSnapshots = new Map<\n string,\n { task: SeevioTask; recordedAt: number }\n >();\n\n /** Creates a Seevio task client using the documented HTTPS API root. */\n constructor(options: SeevioOptions) {\n this.options = normalizeBaseAIOptions(ensureOptions(options));\n this.resultOrigins = new Set(this.options.resultUrlOrigins);\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<T> {\n const response = await this.rawRequest(path, options);\n const text = await response.text();\n return text ? (JSON.parse(text) as T) : ({} as T);\n }\n\n private async rawRequest(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<Response> {\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.options.timeout;\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs);\n const abort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', abort, { once: true });\n // An abort may occur between the preflight check and listener\n // registration. Re-check after registration so that race still reaches\n // the fetch signal rather than allowing a paid request to continue.\n if (options.signal?.aborted) abort();\n try {\n let response: Response;\n try {\n response = await fetch(`${this.options.baseUrl}${path}`, {\n method: options.method || 'GET',\n headers: {\n Authorization: `Bearer ${this.options.apiKey ?? ''}`,\n ...(options.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(this.options.headers || {}),\n },\n body:\n options.body === undefined\n ? undefined\n : JSON.stringify(options.body),\n signal: controller.signal,\n });\n } catch (error) {\n if (timedOut)\n throw new AIError(\n `Seevio request to ${path} timed out after ${timeoutMs}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n throw new AIError(\n `Network error calling Seevio ${path}: ${error instanceof Error ? error.message : String(error)}`,\n 'NETWORK_ERROR',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n }\n if (response.status === 404 && options.allowNotFound) return response;\n if (response.ok) return response;\n const errorText = await response.text();\n let payload: SeevioErrorResponse = {};\n try {\n payload = JSON.parse(errorText) as SeevioErrorResponse;\n } catch {\n /* preserve status fallback below */\n }\n const message =\n payload.error?.message ||\n `Seevio request to ${path} failed with HTTP ${response.status}`;\n if (response.status === 401) throw new AuthenticationError('seevio');\n if (response.status === 403)\n throw new AIError(message, 'SEEVIO_FORBIDDEN', 'seevio');\n if (response.status === 402)\n throw new AIError(message, 'INSUFFICIENT_CREDITS', 'seevio');\n if (response.status === 429)\n throw new RateLimitError(\n 'seevio',\n extractRetryAfterSeconds({ headers: response.headers }),\n );\n throw new AIError(\n message,\n 'SEEVIO_REQUEST_FAILED',\n 'seevio',\n undefined,\n response.status >= 500 && options.method !== 'POST',\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', abort);\n }\n }\n\n private assertReviewedResultUrl(value: string): string {\n const url = validatedHttpsUrl(value, 'Seevio result URL');\n if (!this.resultOrigins.has(new URL(url).origin)) {\n throw new AIError(\n 'Seevio returned a result URL outside configured reviewed origins',\n 'UNTRUSTED_RESULT_URL',\n 'seevio',\n );\n }\n return url;\n }\n\n private async downloadReviewedResult(\n initialUrl: string,\n ): Promise<{ data: Buffer; mimeType: string; url: string }> {\n let current = this.assertReviewedResultUrl(initialUrl);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.options.timeout);\n const maxBytes = this.options.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES;\n try {\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {\n const response = await fetch(current, {\n redirect: 'manual',\n signal: controller.signal,\n });\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n if (!location)\n throw new AIError(\n 'Seevio result redirect omitted Location',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n current = this.assertReviewedResultUrl(\n new URL(location, current).toString(),\n );\n continue;\n }\n if (!response.ok)\n throw new AIError(\n `Seevio result download failed with HTTP ${response.status}`,\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const contentType = response.headers.get('content-type');\n if (!contentType?.toLowerCase().startsWith('video/'))\n throw new AIError(\n `Seevio result download returned non-video content type ${contentType}`,\n 'SEEVIO_RESULT_MIME_INVALID',\n 'seevio',\n );\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > maxBytes)\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n if (!response.body)\n throw new AIError(\n 'Seevio result download had no response body',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = response.body.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel();\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n }\n chunks.push(value);\n }\n return {\n data: Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))),\n mimeType: contentType,\n url: current,\n };\n }\n throw new AIError(\n 'Seevio result exceeded the maximum redirect count',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n } catch (error) {\n if (controller.signal.aborted)\n throw new AIError(\n `Seevio result download timed out after ${this.options.timeout}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n true,\n );\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private mediaUrls(options: VideoGenerationOptions): {\n images: string[];\n videos: string[];\n audio: string[];\n } {\n const images = (options.referenceImages ?? []).map((reference) => {\n if (\n typeof reference.image !== 'string' ||\n reference.image.startsWith('data:')\n ) {\n throw new ValidationError(\n 'Seevio referenceImages must be public HTTPS URLs; it cannot retrieve bytes or data URLs',\n { provider: 'seevio' },\n );\n }\n return validatedHttpsUrl(reference.image, 'Seevio reference image');\n });\n const references = options.referenceMedia ?? [];\n if (references.length + images.length > 50)\n throw new ValidationError(\n 'Seevio accepts at most 50 total reference assets',\n { provider: 'seevio' },\n );\n const collect = (type: VideoGenerationReferenceMedia['type']) =>\n references\n .filter((reference) => reference.type === type)\n .map((reference) =>\n validatedHttpsUrl(reference.url, `Seevio ${type} reference`),\n );\n const mediaImages = collect('image');\n const videos = collect('video');\n const audio = collect('audio');\n if (\n images.length + mediaImages.length > 30 ||\n videos.length > 10 ||\n audio.length > 10\n ) {\n throw new ValidationError(\n 'Seevio reference limits are 30 images, 10 videos, and 10 audio files',\n { provider: 'seevio' },\n );\n }\n for (const reference of references) {\n if (\n (reference.type === 'video' || reference.type === 'audio') &&\n reference.durationSeconds !== undefined &&\n (!Number.isFinite(reference.durationSeconds) ||\n reference.durationSeconds < 2 ||\n reference.durationSeconds > 30)\n ) {\n throw new ValidationError(\n 'Seevio video/audio reference durations must be 2-30 seconds when supplied',\n { provider: 'seevio' },\n );\n }\n }\n for (const [label, type] of [\n ['video', 'video'],\n ['audio', 'audio'],\n ] as const) {\n const durations = references\n .filter((reference) => reference.type === type)\n .flatMap((reference) =>\n reference.durationSeconds === undefined\n ? []\n : [reference.durationSeconds],\n );\n if (durations.reduce((total, duration) => total + duration, 0) > 30) {\n throw new ValidationError(\n `Seevio ${label} reference durations must total no more than 30 seconds`,\n { provider: 'seevio' },\n );\n }\n }\n return { images: [...images, ...mediaImages], videos, audio };\n }\n\n private async pollTask(jobId: string): Promise<SeevioTask> {\n const now = Date.now();\n for (const [knownJobId, expiry] of this.nextPollAt) {\n if (expiry <= now) this.nextPollAt.delete(knownJobId);\n }\n const next = this.nextPollAt.get(jobId);\n if (next && now < next)\n throw new AIError(\n `Seevio tasks may be polled no more than once every 10 seconds; retry after ${Math.ceil((next - now) / 1000)} seconds`,\n 'VIDEO_POLL_TOO_FREQUENT',\n 'seevio',\n );\n const expiry = now + MIN_POLL_INTERVAL_MS;\n this.nextPollAt.set(jobId, expiry);\n const cleanup = setTimeout(() => {\n if (this.nextPollAt.get(jobId) === expiry) this.nextPollAt.delete(jobId);\n }, MIN_POLL_INTERVAL_MS);\n // Let idle Node workers exit rather than keeping the process alive for a\n // cadence cleanup timer. Browser timer handles do not expose `unref`.\n if (typeof cleanup === 'object' && 'unref' in cleanup) cleanup.unref();\n const task = await this.request<SeevioTask>(\n `/v1/tasks/${encodeURIComponent(jobId)}`,\n );\n if (task.status === 'completed') {\n // This is a bounded, short-lived handoff cache, not task history. A\n // completed task can be fetched without another status request only\n // within the provider's ten-second cadence window.\n if (!this.completedSnapshots.has(jobId)) {\n const oldestJobId = this.completedSnapshots.keys().next().value;\n if (\n this.completedSnapshots.size >= MAX_COMPLETED_SNAPSHOTS &&\n oldestJobId !== undefined\n ) {\n this.completedSnapshots.delete(oldestJobId);\n }\n }\n this.completedSnapshots.set(jobId, { task, recordedAt: Date.now() });\n }\n return task;\n }\n\n private completedSnapshot(jobId: string): SeevioTask | undefined {\n const snapshot = this.completedSnapshots.get(jobId);\n if (!snapshot) return undefined;\n if (Date.now() - snapshot.recordedAt >= COMPLETED_SNAPSHOT_TTL_MS) {\n this.completedSnapshots.delete(jobId);\n return undefined;\n }\n return snapshot.task;\n }\n\n /** Submits one unambiguous, non-retried Seedance 2.5 task. */\n async submitVideoGenerationJob(\n options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n const startTime = Date.now();\n const model = options.model || this.options.defaultModel || MODEL;\n if (model !== MODEL)\n throw new ValidationError(\n `Seevio provider supports the pinned model ${MODEL}`,\n { provider: 'seevio' },\n );\n if (!options.prompt?.trim())\n throw new ValidationError('Seevio requires a non-empty prompt', {\n provider: 'seevio',\n });\n if (options.seed !== undefined)\n throw new ValidationError(\n 'seed is not supported by Seevio Seedance 2.5',\n { provider: 'seevio' },\n );\n const duration = options.durationSeconds ?? 5;\n if (!Number.isInteger(duration) || duration < 4 || duration > 30)\n throw new ValidationError(\n 'Seevio durationSeconds must be an integer from 4 through 30',\n { provider: 'seevio' },\n );\n const resolution = options.resolution ?? '720p';\n if (resolution !== '480p' && resolution !== '720p')\n throw new ValidationError('Seevio resolution must be 480p or 720p', {\n provider: 'seevio',\n });\n const { images, videos, audio } = this.mediaUrls(options);\n const isImageToVideo =\n images.length >= 1 &&\n images.length <= 2 &&\n videos.length === 0 &&\n audio.length === 0;\n const generationType = isImageToVideo\n ? 'image-to-video'\n : images.length || videos.length || audio.length\n ? 'reference-to-video'\n : 'text-to-video';\n const aspectRatio = options.aspectRatio ?? 'adaptive';\n const supportedRatios: SeevioInput['aspect_ratio'][] = [\n 'adaptive',\n '16:9',\n '9:16',\n '1:1',\n '4:3',\n '3:4',\n '21:9',\n ];\n if (!supportedRatios.includes(aspectRatio as SeevioInput['aspect_ratio']))\n throw new ValidationError('Unsupported Seevio aspectRatio', {\n provider: 'seevio',\n });\n if (isImageToVideo && aspectRatio !== 'adaptive')\n throw new ValidationError(\n 'Seevio image-to-video requires aspectRatio: adaptive',\n { provider: 'seevio' },\n );\n const input: SeevioInput = {\n prompt: options.prompt.trim(),\n generation_type: generationType,\n duration,\n aspect_ratio: aspectRatio as SeevioInput['aspect_ratio'],\n resolution: resolution as '480p' | '720p',\n generate_audio: options.generateAudio ?? true,\n return_last_frame: options.returnLastFrame ?? false,\n ...(images.length ? { image_urls: images } : {}),\n ...(videos.length ? { video_urls: videos } : {}),\n ...(audio.length ? { audio_urls: audio } : {}),\n };\n const created = await this.request<SeevioCreateResponse>(\n '/v1/videos/generations',\n {\n method: 'POST',\n body: { model: MODEL, input },\n signal: options.signal,\n timeout: options.timeout,\n },\n );\n if (!created.taskId)\n throw new AIError(\n 'Seevio accepted submission without a taskId',\n 'SEEVIO_INVALID_RESPONSE',\n 'seevio',\n );\n emitUsage(\n this.options,\n 'seevio',\n 'submitVideoGenerationJob',\n MODEL,\n undefined,\n startTime,\n {\n durationSeconds: String(duration),\n resolution,\n aspectRatio,\n ...options.usageTags,\n },\n );\n return {\n jobId: created.taskId,\n provider: 'seevio',\n model: MODEL,\n createdAt: new Date().toISOString(),\n raw:\n created.credits === undefined\n ? undefined\n : { credits: created.credits, billingStatus: 'reserved' },\n };\n }\n\n /** Returns a normalized task snapshot, enforcing Seevio's 10-second poll cadence. */\n async getVideoGenerationJob(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.mapTask(await this.pollTask(handle.jobId));\n }\n\n /** Downloads a completed video while validating the initial URL and every redirect. */\n async fetchVideoGenerationResult(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n const task =\n this.completedSnapshot(handle.jobId) ??\n (await this.pollTask(handle.jobId));\n const status = this.mapTask(task);\n if (status.status !== 'succeeded' || !status.result?.url)\n throw new AIError(\n `Seevio job ${handle.jobId} has not succeeded (status: ${status.status})`,\n 'VIDEO_JOB_NOT_READY',\n 'seevio',\n handle.model,\n );\n try {\n const downloaded = await this.downloadReviewedResult(status.result.url);\n return { ...status.result, ...downloaded };\n } finally {\n // The handoff cache exists only to make an immediate status → fetch\n // flow cadence-safe. Do not retain expired signed URLs after any fetch\n // attempt; a later fetch will authenticate a fresh task snapshot.\n this.completedSnapshots.delete(handle.jobId);\n }\n }\n\n /** Reports cancellation as unsupported because Seevio documents no cancellation endpoint. */\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n throw new AIError(\n 'Seevio does not document a video-task cancellation endpoint',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n\n /** Performs an unbilled random task-id probe; an authenticated 404 is valid access. */\n async validateVideoGenerationAccess(): Promise<boolean> {\n const response = await this.rawRequest(\n `/v1/tasks/have-ai-access-probe-${crypto.randomUUID()}`,\n { allowNotFound: true },\n );\n return response.ok || response.status === 404;\n }\n\n private mapTask(task: SeevioTask): VideoGenerationStatusResult {\n const billing = normalizeBilling(task);\n if (task.status === 'queued')\n return { status: 'queued', ...(billing ? { billing } : {}) };\n if (task.status === 'generating')\n return { status: 'running', ...(billing ? { billing } : {}) };\n if (task.status === 'failed')\n return {\n status: 'failed',\n error: task.failed_reason || 'Seevio video generation failed',\n ...(billing ? { billing } : {}),\n };\n if (task.status !== 'completed')\n return {\n status: 'running',\n rawStatus: task.status,\n ...(billing ? { billing } : {}),\n };\n const url = task.data?.results?.[0];\n if (!url)\n return {\n status: 'failed',\n error: 'Seevio reported completion with no result URL',\n ...(billing ? { billing } : {}),\n };\n const result: VideoGenerationResult = {\n url: this.assertReviewedResultUrl(url),\n mimeType: 'video/mp4',\n ...(task.data?.video_expires_at\n ? { expiresAt: task.data.video_expires_at }\n : {}),\n ...(task.data?.last_frame_url\n ? {\n lastFrameUrl: this.assertReviewedResultUrl(\n task.data.last_frame_url,\n ),\n }\n : {}),\n };\n return { status: 'succeeded', result, ...(billing ? { billing } : {}) };\n }\n\n /** Lists the single intentional Seevio model selection. */\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: MODEL,\n name: 'Seedance 2.5',\n description: 'Seevio Seedance 2.5 async video generation',\n contextLength: 0,\n capabilities: ['video_generation'],\n supportsFunctions: false,\n supportsVision: true,\n },\n ];\n }\n /** Reports Seevio's video-only capability surface. */\n async getCapabilities(): Promise<AICapabilities> {\n return {\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: true,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: [\n 'submitVideoGenerationJob',\n 'getVideoGenerationJob',\n 'fetchVideoGenerationResult',\n ],\n };\n }\n\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n /** @inheritdoc */ async chat(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async complete(\n _prompt: string,\n _options?: CompletionOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async message(\n _text: string,\n _options?: MessageOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embed(\n _text: string | string[],\n _options?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embedImage(\n _image: string | Buffer,\n _options?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async generateImage(\n _prompt: string,\n _options?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ stream(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async countTokens(_text: string): Promise<number> {\n return this.unsupported();\n }\n /** @inheritdoc */ async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ streamSpeech(\n _text: string,\n _options?: TTSOptions,\n ): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async cloneVoice(\n _options: VoiceCloneOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async designVoice(\n _options: VoiceDesignOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async getVoices(\n _options?: VoiceListOptions,\n ): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { n as AI_PROVIDER_TYPES } from "./types-CINwUPDo.js";
2
- import { t as createRateLimitedAI } from "./rate-limit-DgEhanDL.js";
3
- import { a as normalizeBaseAIOptions, i as createObservedAI } from "./safety-C415clBm.js";
1
+ import { n as AI_PROVIDER_TYPES } from "./types-sSecpd_N.js";
2
+ import { t as createRateLimitedAI } from "./rate-limit-C2oPwLGI.js";
3
+ import { a as normalizeBaseAIOptions, i as createObservedAI } from "./safety-ClfpyKEN.js";
4
4
  import { ApiError, ValidationError, loadEnvConfig } from "@happyvertical/utils";
5
5
  import OpenAI from "openai";
6
6
  //#region \0rolldown/runtime.js
@@ -359,6 +359,10 @@ function isOpenAICompatVideoOptions(options) {
359
359
  function isByteplusModelArkOptions(options) {
360
360
  return options.type === "byteplus-modelark";
361
361
  }
362
+ /** Checks if options select Seevio's native Seedance task API. */
363
+ function isSeevioOptions(options) {
364
+ return options.type === "seevio";
365
+ }
362
366
  /**
363
367
  * Creates an AI provider instance based on the provided options.
364
368
  * Universal version that works in both browser and Node.js environments.
@@ -430,41 +434,44 @@ async function getAI(options = {}) {
430
434
  options = normalizeBaseAIOptions(options);
431
435
  let client;
432
436
  if (isOpenAIOptions(options)) {
433
- const { OpenAIProvider } = await import("./openai-BgrK3OfW.js");
437
+ const { OpenAIProvider } = await import("./openai-BuwvBruA.js");
434
438
  client = new OpenAIProvider(options);
435
439
  } else if (isLiteLLMOptions(options)) {
436
- const { LiteLLMProvider } = await import("./litellm-viqTuSY8.js");
440
+ const { LiteLLMProvider } = await import("./litellm-nOCNI7Vd.js");
437
441
  client = new LiteLLMProvider(options);
438
442
  } else if (isBifrostOptions(options)) {
439
- const { BifrostProvider } = await import("./bifrost-CaYhelVL.js");
443
+ const { BifrostProvider } = await import("./bifrost-DvYZ3LNf.js");
440
444
  client = new BifrostProvider(options);
441
445
  } else if (isOllamaOptions(options)) {
442
- const { OllamaProvider } = await import("./ollama-CdWqwZ05.js");
446
+ const { OllamaProvider } = await import("./ollama-BrB6bjnz.js");
443
447
  client = new OllamaProvider(options);
444
448
  } else if (isGeminiOptions(options)) {
445
- const { GeminiProvider } = await import("./gemini-BT8fjXWz.js");
449
+ const { GeminiProvider } = await import("./gemini-GQdugon1.js");
446
450
  client = new GeminiProvider(options);
447
451
  } else if (isAnthropicOptions(options)) {
448
- const { AnthropicProvider } = await import("./anthropic-DuYUnw8j.js");
452
+ const { AnthropicProvider } = await import("./anthropic-ByuqC5mC.js");
449
453
  client = new AnthropicProvider(options);
450
454
  } else if (isHuggingFaceOptions(options)) {
451
- const { HuggingFaceProvider } = await import("./huggingface-CqzyxeLB.js");
455
+ const { HuggingFaceProvider } = await import("./huggingface-DxPspM6Q.js");
452
456
  client = new HuggingFaceProvider(options);
453
457
  } else if (isBedrockOptions(options)) {
454
- const { BedrockProvider } = await import("./bedrock-ikQJAwWB.js");
458
+ const { BedrockProvider } = await import("./bedrock-BeVCmkrS.js");
455
459
  client = new BedrockProvider(options);
456
460
  } else if (isClaudeCliOptions(options)) {
457
- const { ClaudeCliProvider } = await import("./claude-cli-DeTKk9nu.js");
461
+ const { ClaudeCliProvider } = await import("./claude-cli-BH_C62dV.js");
458
462
  client = new ClaudeCliProvider(options);
459
463
  } else if (isQwen3TTSOptions(options)) {
460
- const { Qwen3TTSProvider } = await import("./qwen-tts-BXjzY7DX.js");
464
+ const { Qwen3TTSProvider } = await import("./qwen-tts-CAh1upii.js");
461
465
  client = new Qwen3TTSProvider(options);
462
466
  } else if (isOpenAICompatVideoOptions(options)) {
463
- const { OpenAICompatVideoProvider } = await import("./openai-compat-video-D_U7jo0d.js");
467
+ const { OpenAICompatVideoProvider } = await import("./openai-compat-video-DNE1Yvp6.js");
464
468
  client = new OpenAICompatVideoProvider(options);
465
469
  } else if (isByteplusModelArkOptions(options)) {
466
- const { ByteplusModelArkProvider } = await import("./byteplus-modelark-B8l8sPXu.js");
470
+ const { ByteplusModelArkProvider } = await import("./byteplus-modelark-DaF0U4n1.js");
467
471
  client = new ByteplusModelArkProvider(options);
472
+ } else if (isSeevioOptions(options)) {
473
+ const { SeevioProvider } = await import("./seevio-Bbu_hTUF.js");
474
+ client = new SeevioProvider(options);
468
475
  } else throw new ValidationError("Unsupported AI provider type", {
469
476
  supportedTypes: [...AI_PROVIDER_TYPES],
470
477
  providedType: options.type
@@ -737,4 +744,4 @@ var PACKAGE_VERSION_INITIALIZED = true;
737
744
  //#endregion
738
745
  export { getAI as a, OpenAIClient as c, factory_exports as i, getAIClient as l, AIThread as n, getAIAuto as o, AIMessage as r, AIClient as s, PACKAGE_VERSION_INITIALIZED as t, getOpenAI as u };
739
746
 
740
- //# sourceMappingURL=src-CU4qWJ2c.js.map
747
+ //# sourceMappingURL=src-B091S0I4.js.map