@happyvertical/ai 0.85.3 → 0.85.5

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 (84) hide show
  1. package/README.md +87 -1
  2. package/dist/chunks/{anthropic-DA8sdt12.js → anthropic-DuYUnw8j.js} +20 -4
  3. package/dist/chunks/anthropic-DuYUnw8j.js.map +1 -0
  4. package/dist/chunks/{bedrock-DDiYFUw0.js → bedrock-ikQJAwWB.js} +19 -3
  5. package/dist/chunks/bedrock-ikQJAwWB.js.map +1 -0
  6. package/dist/chunks/{bifrost-fM9FpW_w.js → bifrost-CaYhelVL.js} +5 -4
  7. package/dist/chunks/bifrost-CaYhelVL.js.map +1 -0
  8. package/dist/chunks/byteplus-modelark-B8l8sPXu.js +473 -0
  9. package/dist/chunks/byteplus-modelark-B8l8sPXu.js.map +1 -0
  10. package/dist/chunks/{claude-cli-CnJh5KQT.js → claude-cli-DeTKk9nu.js} +19 -3
  11. package/dist/chunks/claude-cli-DeTKk9nu.js.map +1 -0
  12. package/dist/chunks/{gateway-admin-CiKvHst7.js → gateway-admin-DJXEDpUP.js} +2 -2
  13. package/dist/chunks/{gateway-admin-CiKvHst7.js.map → gateway-admin-DJXEDpUP.js.map} +1 -1
  14. package/dist/chunks/{gemini-Bu7Fke7c.js → gemini-BT8fjXWz.js} +294 -11
  15. package/dist/chunks/gemini-BT8fjXWz.js.map +1 -0
  16. package/dist/chunks/{huggingface-B07_6wHW.js → huggingface-CqzyxeLB.js} +19 -3
  17. package/dist/chunks/huggingface-CqzyxeLB.js.map +1 -0
  18. package/dist/chunks/{litellm-D_Oo9OQ_.js → litellm-viqTuSY8.js} +5 -4
  19. package/dist/chunks/litellm-viqTuSY8.js.map +1 -0
  20. package/dist/chunks/{ollama-D4ksOTO8.js → ollama-CdWqwZ05.js} +19 -3
  21. package/dist/chunks/ollama-CdWqwZ05.js.map +1 -0
  22. package/dist/chunks/{openai--F38QHiJ.js → openai-BgrK3OfW.js} +20 -4
  23. package/dist/chunks/openai-BgrK3OfW.js.map +1 -0
  24. package/dist/chunks/openai-compat-video-D_U7jo0d.js +369 -0
  25. package/dist/chunks/openai-compat-video-D_U7jo0d.js.map +1 -0
  26. package/dist/chunks/{qwen-tts-DRRbOrhA.js → qwen-tts-BXjzY7DX.js} +21 -4
  27. package/dist/chunks/qwen-tts-BXjzY7DX.js.map +1 -0
  28. package/dist/chunks/{rate-limit-BwyPGXFW.js → rate-limit-DgEhanDL.js} +4 -3
  29. package/dist/chunks/rate-limit-DgEhanDL.js.map +1 -0
  30. package/dist/chunks/{safety-CEnoJS6X.js → safety-C415clBm.js} +25 -7
  31. package/dist/chunks/safety-C415clBm.js.map +1 -0
  32. package/dist/chunks/src-CU4qWJ2c.js +740 -0
  33. package/dist/chunks/src-CU4qWJ2c.js.map +1 -0
  34. package/dist/chunks/{types-FHs-KbGL.js → types-CINwUPDo.js} +4 -2
  35. package/dist/chunks/types-CINwUPDo.js.map +1 -0
  36. package/dist/index.js +3 -717
  37. package/dist/node/factory.d.ts +9 -0
  38. package/dist/node/factory.d.ts.map +1 -1
  39. package/dist/node.d.ts +29 -0
  40. package/dist/node.d.ts.map +1 -0
  41. package/dist/node.js +198 -0
  42. package/dist/node.js.map +1 -0
  43. package/dist/shared/factory.d.ts.map +1 -1
  44. package/dist/shared/providers/anthropic.d.ts +6 -1
  45. package/dist/shared/providers/anthropic.d.ts.map +1 -1
  46. package/dist/shared/providers/bedrock.d.ts +6 -1
  47. package/dist/shared/providers/bedrock.d.ts.map +1 -1
  48. package/dist/shared/providers/bifrost.d.ts.map +1 -1
  49. package/dist/shared/providers/byteplus-modelark.d.ts +91 -0
  50. package/dist/shared/providers/byteplus-modelark.d.ts.map +1 -0
  51. package/dist/shared/providers/claude-cli.d.ts +6 -1
  52. package/dist/shared/providers/claude-cli.d.ts.map +1 -1
  53. package/dist/shared/providers/gemini.d.ts +115 -2
  54. package/dist/shared/providers/gemini.d.ts.map +1 -1
  55. package/dist/shared/providers/huggingface.d.ts +6 -1
  56. package/dist/shared/providers/huggingface.d.ts.map +1 -1
  57. package/dist/shared/providers/litellm.d.ts.map +1 -1
  58. package/dist/shared/providers/ollama.d.ts +6 -1
  59. package/dist/shared/providers/ollama.d.ts.map +1 -1
  60. package/dist/shared/providers/openai-compat-video.d.ts +98 -0
  61. package/dist/shared/providers/openai-compat-video.d.ts.map +1 -0
  62. package/dist/shared/providers/openai.d.ts +6 -1
  63. package/dist/shared/providers/openai.d.ts.map +1 -1
  64. package/dist/shared/providers/qwen-tts.d.ts +6 -1
  65. package/dist/shared/providers/qwen-tts.d.ts.map +1 -1
  66. package/dist/shared/rate-limit.d.ts.map +1 -1
  67. package/dist/shared/safety.d.ts.map +1 -1
  68. package/dist/shared/types.d.ts +343 -5
  69. package/dist/shared/types.d.ts.map +1 -1
  70. package/package.json +7 -3
  71. package/dist/chunks/anthropic-DA8sdt12.js.map +0 -1
  72. package/dist/chunks/bedrock-DDiYFUw0.js.map +0 -1
  73. package/dist/chunks/bifrost-fM9FpW_w.js.map +0 -1
  74. package/dist/chunks/claude-cli-CnJh5KQT.js.map +0 -1
  75. package/dist/chunks/gemini-Bu7Fke7c.js.map +0 -1
  76. package/dist/chunks/huggingface-B07_6wHW.js.map +0 -1
  77. package/dist/chunks/litellm-D_Oo9OQ_.js.map +0 -1
  78. package/dist/chunks/ollama-D4ksOTO8.js.map +0 -1
  79. package/dist/chunks/openai--F38QHiJ.js.map +0 -1
  80. package/dist/chunks/qwen-tts-DRRbOrhA.js.map +0 -1
  81. package/dist/chunks/rate-limit-BwyPGXFW.js.map +0 -1
  82. package/dist/chunks/safety-CEnoJS6X.js.map +0 -1
  83. package/dist/chunks/types-FHs-KbGL.js.map +0 -1
  84. package/dist/index.js.map +0 -1
@@ -0,0 +1,473 @@
1
+ import { r as AuthenticationError, s as RateLimitError, t as AIError } from "./types-CINwUPDo.js";
2
+ import { n as extractRetryAfterSeconds } from "./rate-limit-DgEhanDL.js";
3
+ import { a as normalizeBaseAIOptions } from "./safety-C415clBm.js";
4
+ import { t as emitUsage } from "./usage-C1Y1Nlg4.js";
5
+ //#region src/shared/providers/byteplus-modelark.ts
6
+ /**
7
+ * BytePlus ModelArk (Seedance) video-generation provider implementation
8
+ *
9
+ * Raw-HTTP provider following the `qwen3-tts` precedent: no vendor SDK, just
10
+ * the ModelArk video-generation task API (create task / poll / fetch /
11
+ * cancel). This provider is video-generation only; it throws
12
+ * `NOT_IMPLEMENTED` for chat, embeddings, and other text/TTS operations.
13
+ *
14
+ * The base URL, endpoint paths (`/contents/generations/tasks`), request/
15
+ * response field names, and the `queued|running|cancelled|succeeded|failed|
16
+ * expired` status enum were confirmed directly against BytePlus's own
17
+ * published docs and blog examples at the time this was written (see the
18
+ * link below). The `expired` status, the `page_num`/`page_size`/`filter.*`
19
+ * list query params, and the DELETE-as-cancel-or-delete semantics
20
+ * (`queued` → cancelled, `running` → rejected, terminal → deleted) are
21
+ * corroborated from that same documentation but have not been exercised
22
+ * against a live ModelArk account by this package's test suite — see
23
+ * `packages/ai/src/byteplus-modelark.integration.test.ts` for an opt-in
24
+ * check (skipped unless `MODELARK_API_KEY` is set) that exercises those
25
+ * specifics against the real API.
26
+ *
27
+ * @see https://docs.byteplus.com/en/docs/ModelArk/Video_Generation_API
28
+ */
29
+ var DEFAULT_MODELARK_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
30
+ var DEFAULT_MODELARK_MODEL = "seedance-1-0-lite-t2v-250428";
31
+ var DEFAULT_MODELARK_I2V_MODEL = "seedance-1-0-lite-i2v-250428";
32
+ /** Burst capacity for the submit token bucket — see {@link SubmitRateLimiter}. */
33
+ var SUBMIT_BURST_CAPACITY = 2;
34
+ /**
35
+ * Resolve after `ms` milliseconds, or as soon as `signal` aborts —
36
+ * whichever comes first. Never rejects; callers re-check `signal.aborted`
37
+ * themselves immediately after, so a single check covers both "timed out
38
+ * normally" and "woke up early because of an abort."
39
+ */
40
+ function delayOrAbort(ms, signal) {
41
+ return new Promise((resolve) => {
42
+ if (signal?.aborted) {
43
+ resolve();
44
+ return;
45
+ }
46
+ const timer = setTimeout(resolve, ms);
47
+ signal?.addEventListener("abort", () => {
48
+ clearTimeout(timer);
49
+ resolve();
50
+ }, { once: true });
51
+ });
52
+ }
53
+ /**
54
+ * Local token-bucket + concurrency limiter for submit-time throttling.
55
+ *
56
+ * ModelArk documents Seedance account limits of QPS 2 / 3 *concurrent
57
+ * submissions*; this only gates `submitVideoGenerationJob` (task creation
58
+ * HTTP calls), matching the "submit-time throttling" requirement — polling
59
+ * and cancellation are not subject to the same account-level task-creation
60
+ * limits. `maxConcurrent` bounds concurrent in-flight *submit HTTP
61
+ * requests*, not the lifetime of the provider-side render tasks those
62
+ * submissions create — this limiter has no way to observe when a task
63
+ * actually finishes rendering on ModelArk's infrastructure, so
64
+ * task-lifetime concurrency is not, and cannot be, tracked here.
65
+ *
66
+ * The bucket's burst capacity is capped at {@link SUBMIT_BURST_CAPACITY}
67
+ * (independent of `requestsPerMinute`) so the bucket doesn't start full —
68
+ * without this cap, a bucket sized to `requestsPerMinute` (e.g. 120) would
69
+ * start with 120 tokens and let the first 120 submits through instantly,
70
+ * defeating the QPS limit entirely.
71
+ */
72
+ var SubmitRateLimiter = class {
73
+ tokens;
74
+ lastRefill;
75
+ maxTokens;
76
+ refillRate;
77
+ activeRequests = 0;
78
+ maxConcurrent;
79
+ constructor(options) {
80
+ const requestsPerMinute = options.requestsPerMinute ?? 120;
81
+ this.refillRate = requestsPerMinute / 60;
82
+ this.maxTokens = SUBMIT_BURST_CAPACITY;
83
+ this.tokens = this.maxTokens;
84
+ this.lastRefill = Date.now();
85
+ this.maxConcurrent = options.maxConcurrent ?? 3;
86
+ }
87
+ /**
88
+ * Acquire a submit slot + token, honoring `signal` throughout the wait.
89
+ *
90
+ * The concurrency slot and the token are checked and committed together
91
+ * in one synchronous section (no `await` between the check and the
92
+ * `tokens -=`/`activeRequests +=` mutations below), so a waiter can never
93
+ * observe a stale "slot available" snapshot from before another waiter's
94
+ * own commit — closing the TOCTOU window where two callers could both
95
+ * pass the checks and push `activeRequests` past `maxConcurrent`.
96
+ *
97
+ * An aborted `signal` — whether already aborted at entry or aborted
98
+ * while waiting for a slot/token — throws before any token is consumed
99
+ * or `activeRequests` is incremented, so an aborted submission never
100
+ * silently proceeds to create a billable job.
101
+ */
102
+ async acquire(signal) {
103
+ const throwIfAborted = () => {
104
+ if (signal?.aborted) throw new AIError("ModelArk submission aborted by caller while waiting for the rate limiter", "AI_ABORTED", "byteplus-modelark");
105
+ };
106
+ throwIfAborted();
107
+ const now = Date.now();
108
+ const elapsed = (now - this.lastRefill) / 1e3;
109
+ this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
110
+ this.lastRefill = now;
111
+ for (;;) {
112
+ throwIfAborted();
113
+ if (this.activeRequests < this.maxConcurrent && this.tokens >= 1) {
114
+ this.tokens -= 1;
115
+ this.activeRequests += 1;
116
+ return;
117
+ }
118
+ if (this.activeRequests >= this.maxConcurrent) await delayOrAbort(100, signal);
119
+ else {
120
+ await delayOrAbort(Math.max(1, (1 - this.tokens) / this.refillRate * 1e3), signal);
121
+ const elapsedNow = (Date.now() - this.lastRefill) / 1e3;
122
+ this.tokens = Math.min(this.maxTokens, this.tokens + elapsedNow * this.refillRate);
123
+ this.lastRefill = Date.now();
124
+ }
125
+ }
126
+ }
127
+ release() {
128
+ this.activeRequests = Math.max(0, this.activeRequests - 1);
129
+ }
130
+ };
131
+ /**
132
+ * FNV-1a hash, used only to avoid retaining raw API keys as in-memory Map
133
+ * keys in {@link sharedSubmitLimiters}. Not cryptographic — collisions just
134
+ * mean two distinct keys share a rate-limit bucket, which is a pacing
135
+ * inefficiency, not a security issue.
136
+ */
137
+ function hashKey(value) {
138
+ let hash = 2166136261;
139
+ for (let index = 0; index < value.length; index += 1) {
140
+ hash ^= value.charCodeAt(index);
141
+ hash = Math.imul(hash, 16777619);
142
+ }
143
+ return (hash >>> 0).toString(36);
144
+ }
145
+ /**
146
+ * Submit-time limiters keyed by credential/config, shared module-wide.
147
+ *
148
+ * Provider instances are frequently constructed per pipeline step (a fresh
149
+ * `getAI({ type: 'byteplus-modelark', ... })` per job), so a limiter owned
150
+ * by a single provider instance would reset on every construction and never
151
+ * actually enforce the account-wide QPS/concurrency limits. Keying by the
152
+ * resolved credentials (or an explicit `rateLimit.key`) lets independently
153
+ * constructed instances that target the same ModelArk account share one
154
+ * bucket, mirroring how {@link createRateLimitedAI}'s budget coordinators
155
+ * are shared by `rateLimit.key`.
156
+ */
157
+ var sharedSubmitLimiters = /* @__PURE__ */ new Map();
158
+ function getSharedSubmitLimiter(options) {
159
+ const key = options.rateLimit?.key?.trim() || `byteplus-modelark:${hashKey(options.apiKey || "default")}`;
160
+ let limiter = sharedSubmitLimiters.get(key);
161
+ if (!limiter) {
162
+ limiter = new SubmitRateLimiter({
163
+ requestsPerMinute: options.rateLimit?.requestsPerMinute,
164
+ maxConcurrent: options.rateLimit?.maxConcurrent
165
+ });
166
+ sharedSubmitLimiters.set(key, limiter);
167
+ }
168
+ return limiter;
169
+ }
170
+ /**
171
+ * BytePlus ModelArk provider implementation for asynchronous video
172
+ * generation (Seedance). Focuses on video-generation capabilities and
173
+ * throws `NOT_IMPLEMENTED` for text generation methods.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * import { getAI } from '@happyvertical/ai';
178
+ *
179
+ * const modelark = await getAI({
180
+ * type: 'byteplus-modelark',
181
+ * apiKey: process.env.MODELARK_API_KEY!,
182
+ * });
183
+ *
184
+ * const job = await modelark.submitVideoGenerationJob({
185
+ * prompt: 'A drone shot flying over a coastal cliff at sunrise',
186
+ * durationSeconds: 5,
187
+ * resolution: '720p',
188
+ * aspectRatio: '16:9',
189
+ * });
190
+ *
191
+ * // Persist `job`, poll later (even after a restart):
192
+ * const status = await modelark.getVideoGenerationJob(job);
193
+ * ```
194
+ */
195
+ var ByteplusModelArkProvider = class {
196
+ options;
197
+ submitLimiter;
198
+ constructor(options) {
199
+ this.options = normalizeBaseAIOptions({ ...options });
200
+ this.submitLimiter = getSharedSubmitLimiter(this.options);
201
+ }
202
+ get baseUrl() {
203
+ return (this.options.baseUrl || DEFAULT_MODELARK_BASE_URL).replace(/\/+$/, "");
204
+ }
205
+ async request(path, options = {}) {
206
+ if (options.signal?.aborted) throw new AIError("ModelArk request aborted by caller", "AI_ABORTED", "byteplus-modelark");
207
+ const url = new URL(`${this.baseUrl}${path}`);
208
+ for (const [key, value] of Object.entries(options.query ?? {})) url.searchParams.set(key, String(value));
209
+ const controller = new AbortController();
210
+ const timeoutMs = options.timeout ?? this.options.timeout;
211
+ let timedOut = false;
212
+ const timer = timeoutMs ? setTimeout(() => {
213
+ timedOut = true;
214
+ controller.abort();
215
+ }, timeoutMs) : void 0;
216
+ const onExternalAbort = () => controller.abort(options.signal?.reason);
217
+ if (options.signal?.aborted) onExternalAbort();
218
+ else options.signal?.addEventListener("abort", onExternalAbort, { once: true });
219
+ try {
220
+ let response;
221
+ try {
222
+ response = await fetch(url, {
223
+ method: options.method || "GET",
224
+ headers: {
225
+ "Content-Type": "application/json",
226
+ Authorization: `Bearer ${this.options.apiKey ?? ""}`,
227
+ ...this.options.headers || {}
228
+ },
229
+ body: options.body ? JSON.stringify(options.body) : void 0,
230
+ signal: controller.signal
231
+ });
232
+ } catch (error) {
233
+ if (timedOut) throw new AIError(`ModelArk request to ${path} timed out after ${timeoutMs}ms`, "AI_TIMEOUT", "byteplus-modelark", void 0, true);
234
+ if (options.signal?.aborted) throw new AIError("ModelArk request aborted by caller", "AI_ABORTED", "byteplus-modelark");
235
+ throw new AIError(`Network error calling ModelArk ${path}: ${error instanceof Error ? error.message : String(error)}`, "NETWORK_ERROR", "byteplus-modelark", void 0, true);
236
+ }
237
+ if (!response.ok) {
238
+ const errorText = await response.text();
239
+ if (response.status === 401 || response.status === 403) throw new AuthenticationError("byteplus-modelark");
240
+ if (response.status === 429) throw new RateLimitError("byteplus-modelark", extractRetryAfterSeconds({ headers: response.headers }));
241
+ throw new AIError(`ModelArk request to ${path} failed: ${response.status} ${errorText}`, "MODELARK_REQUEST_FAILED", "byteplus-modelark");
242
+ }
243
+ if (response.status === 204) return {};
244
+ const text = await response.text();
245
+ return text ? JSON.parse(text) : {};
246
+ } finally {
247
+ if (timer) clearTimeout(timer);
248
+ options.signal?.removeEventListener("abort", onExternalAbort);
249
+ }
250
+ }
251
+ toImageUrl(reference) {
252
+ if (typeof reference.image === "string") return reference.image;
253
+ return `data:${reference.mimeType || "image/png"};base64,${reference.image.toString("base64")}`;
254
+ }
255
+ /**
256
+ * Submit an asynchronous Seedance video-generation task.
257
+ *
258
+ * Submission is locally throttled to approximate ModelArk's documented
259
+ * Seedance account limits (QPS 2, capped at {@link SUBMIT_BURST_CAPACITY}
260
+ * burst / 3 concurrent *submissions* — task-lifetime concurrency on
261
+ * ModelArk's infrastructure is not tracked; see {@link SubmitRateLimiter}).
262
+ *
263
+ * When `referenceImages` are supplied and no explicit `model` is chosen,
264
+ * this selects the image-to-video default model rather than silently
265
+ * generating text-to-video with the image ignored.
266
+ */
267
+ async submitVideoGenerationJob(options) {
268
+ const startTime = Date.now();
269
+ await this.submitLimiter.acquire(options.signal);
270
+ try {
271
+ const hasReferenceImages = (options.referenceImages?.length ?? 0) > 0;
272
+ const model = options.model || this.options.defaultModel || (hasReferenceImages ? DEFAULT_MODELARK_I2V_MODEL : DEFAULT_MODELARK_MODEL);
273
+ const content = [];
274
+ if (options.prompt) content.push({
275
+ type: "text",
276
+ text: options.prompt
277
+ });
278
+ for (const reference of options.referenceImages ?? []) content.push({
279
+ type: "image_url",
280
+ image_url: { url: this.toImageUrl(reference) },
281
+ role: reference.role || "reference_image"
282
+ });
283
+ if (content.length === 0) throw new AIError("submitVideoGenerationJob requires a prompt or at least one reference image", "INVALID_INPUT", "byteplus-modelark");
284
+ const body = {
285
+ model,
286
+ content,
287
+ resolution: options.resolution,
288
+ ratio: options.aspectRatio,
289
+ duration: options.durationSeconds,
290
+ seed: options.seed
291
+ };
292
+ const response = await this.request("/contents/generations/tasks", {
293
+ method: "POST",
294
+ body,
295
+ signal: options.signal,
296
+ timeout: options.timeout
297
+ });
298
+ emitUsage(this.options, "byteplus-modelark", "submitVideoGenerationJob", model, void 0, startTime, {
299
+ ...options.durationSeconds !== void 0 ? { durationSeconds: String(options.durationSeconds) } : {},
300
+ ...options.resolution ? { resolution: options.resolution } : {},
301
+ ...options.aspectRatio ? { aspectRatio: options.aspectRatio } : {},
302
+ ...options.usageTags
303
+ });
304
+ return {
305
+ jobId: response.id,
306
+ provider: "byteplus-modelark",
307
+ model,
308
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
309
+ };
310
+ } finally {
311
+ this.submitLimiter.release();
312
+ }
313
+ }
314
+ /**
315
+ * Poll the status of a ModelArk video-generation task.
316
+ */
317
+ async getVideoGenerationJob(handle) {
318
+ const task = await this.request(`/contents/generations/tasks/${handle.jobId}`);
319
+ return this.mapTask(task);
320
+ }
321
+ /**
322
+ * Fetch the result of a completed ModelArk video-generation task.
323
+ *
324
+ * @throws {AIError} When the job has not succeeded yet
325
+ */
326
+ async fetchVideoGenerationResult(handle) {
327
+ const status = await this.getVideoGenerationJob(handle);
328
+ if (status.status !== "succeeded" || !status.result) throw new AIError(`ModelArk video-generation job ${handle.jobId} has not succeeded (status: ${status.status})`, "VIDEO_JOB_NOT_READY", "byteplus-modelark", handle.model);
329
+ return status.result;
330
+ }
331
+ /**
332
+ * Cancel a ModelArk video-generation task.
333
+ *
334
+ * ModelArk's DELETE endpoint only transitions a `queued` task to
335
+ * `cancelled`; a task that is already `running` cannot be cancelled and
336
+ * the request fails with an {@link AIError} describing why. Terminal
337
+ * tasks (`succeeded`/`failed`/`expired`) are deleted instead.
338
+ */
339
+ async cancelVideoGenerationJob(handle) {
340
+ await this.request(`/contents/generations/tasks/${handle.jobId}`, { method: "DELETE" });
341
+ }
342
+ /**
343
+ * Cheap auth-shaped check for ModelArk access: lists tasks with a page
344
+ * size of 1. Callers on a hot path must cache the result themselves.
345
+ */
346
+ async validateVideoGenerationAccess() {
347
+ await this.request("/contents/generations/tasks", { query: { page_size: 1 } });
348
+ return true;
349
+ }
350
+ mapTask(task) {
351
+ switch (task.status) {
352
+ case "queued": return { status: "queued" };
353
+ case "running": return { status: "running" };
354
+ case "cancelled": return { status: "cancelled" };
355
+ case "expired": return {
356
+ status: "failed",
357
+ error: "ModelArk task expired before the result was retrieved"
358
+ };
359
+ case "failed": return {
360
+ status: "failed",
361
+ error: task.error?.message || "ModelArk video generation failed"
362
+ };
363
+ case "succeeded":
364
+ if (!task.content?.video_url) return {
365
+ status: "failed",
366
+ error: "ModelArk reported success with no video_url"
367
+ };
368
+ return {
369
+ status: "succeeded",
370
+ result: {
371
+ url: task.content.video_url,
372
+ mimeType: "video/mp4",
373
+ durationSeconds: task.duration
374
+ }
375
+ };
376
+ default: return {
377
+ status: "running",
378
+ rawStatus: task.status
379
+ };
380
+ }
381
+ }
382
+ async getModels() {
383
+ return [{
384
+ id: "seedance-1-0-lite-t2v-250428",
385
+ name: "Seedance 1.0 Lite (text-to-video)",
386
+ description: "ModelArk Seedance 1.0 Lite text-to-video model",
387
+ contextLength: 0,
388
+ capabilities: ["video_generation"],
389
+ supportsFunctions: false,
390
+ supportsVision: false
391
+ }, {
392
+ id: "seedance-1-0-lite-i2v-250428",
393
+ name: "Seedance 1.0 Lite (image-to-video)",
394
+ description: "ModelArk Seedance 1.0 Lite image-to-video model",
395
+ contextLength: 0,
396
+ capabilities: ["video_generation"],
397
+ supportsFunctions: false,
398
+ supportsVision: true
399
+ }];
400
+ }
401
+ async getCapabilities() {
402
+ return {
403
+ chat: false,
404
+ completion: false,
405
+ embeddings: false,
406
+ streaming: false,
407
+ functions: false,
408
+ vision: false,
409
+ fineTuning: false,
410
+ imageEmbeddings: false,
411
+ imageGeneration: false,
412
+ videoGeneration: true,
413
+ tts: false,
414
+ voiceCloning: false,
415
+ voiceDesign: false,
416
+ maxContextLength: 0,
417
+ supportedOperations: [
418
+ "submitVideoGenerationJob",
419
+ "getVideoGenerationJob",
420
+ "fetchVideoGenerationResult",
421
+ "cancelVideoGenerationJob"
422
+ ]
423
+ };
424
+ }
425
+ async chat(_messages, _options) {
426
+ throw new AIError("Chat is not supported by the BytePlus ModelArk provider. Use OpenAI, Anthropic, or another provider for text generation.", "NOT_IMPLEMENTED", "byteplus-modelark");
427
+ }
428
+ async complete(_prompt, _options) {
429
+ throw new AIError("Complete is not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
430
+ }
431
+ async message(_text, _options) {
432
+ throw new AIError("Message is not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
433
+ }
434
+ async embed(_text, _options) {
435
+ throw new AIError("Embeddings are not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
436
+ }
437
+ async embedImage(_image, _options) {
438
+ throw new AIError("Image embeddings are not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
439
+ }
440
+ async describeImage(_image, _prompt, _options) {
441
+ throw new AIError("Image description is not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
442
+ }
443
+ async generateImage(_prompt, _options) {
444
+ throw new AIError("Synchronous image generation is not yet implemented by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
445
+ }
446
+ stream(_messages, _options) {
447
+ const error = new AIError("Chat streaming is not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
448
+ return { [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }) };
449
+ }
450
+ async countTokens(_text) {
451
+ throw new AIError("Token counting is not supported by the BytePlus ModelArk provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
452
+ }
453
+ async synthesizeSpeech(_text, _options) {
454
+ throw new AIError("TTS is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
455
+ }
456
+ streamSpeech(_text, _options) {
457
+ const error = new AIError("TTS streaming is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
458
+ return { [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }) };
459
+ }
460
+ async cloneVoice(_options) {
461
+ throw new AIError("Voice cloning is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
462
+ }
463
+ async designVoice(_options) {
464
+ throw new AIError("Voice design is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
465
+ }
466
+ async getVoices(_options) {
467
+ throw new AIError("Voice listing is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "byteplus-modelark");
468
+ }
469
+ };
470
+ //#endregion
471
+ export { ByteplusModelArkProvider };
472
+
473
+ //# sourceMappingURL=byteplus-modelark-B8l8sPXu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byteplus-modelark-B8l8sPXu.js","names":[],"sources":["../../src/shared/providers/byteplus-modelark.ts"],"sourcesContent":["/**\n * BytePlus ModelArk (Seedance) video-generation provider implementation\n *\n * Raw-HTTP provider following the `qwen3-tts` precedent: no vendor SDK, just\n * the ModelArk video-generation task API (create task / poll / fetch /\n * cancel). This provider is video-generation only; it throws\n * `NOT_IMPLEMENTED` for chat, embeddings, and other text/TTS operations.\n *\n * The base URL, endpoint paths (`/contents/generations/tasks`), request/\n * response field names, and the `queued|running|cancelled|succeeded|failed|\n * expired` status enum were confirmed directly against BytePlus's own\n * published docs and blog examples at the time this was written (see the\n * link below). The `expired` status, the `page_num`/`page_size`/`filter.*`\n * list query params, and the DELETE-as-cancel-or-delete semantics\n * (`queued` → cancelled, `running` → rejected, terminal → deleted) are\n * corroborated from that same documentation but have not been exercised\n * against a live ModelArk account by this package's test suite — see\n * `packages/ai/src/byteplus-modelark.integration.test.ts` for an opt-in\n * check (skipped unless `MODELARK_API_KEY` is set) that exercises those\n * specifics against the real API.\n *\n * @see https://docs.byteplus.com/en/docs/ModelArk/Video_Generation_API\n */\n\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport { normalizeBaseAIOptions } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ByteplusModelArkOptions,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TTSOptions,\n TTSResponse,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationReferenceImage,\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_MODELARK_BASE_URL =\n 'https://ark.ap-southeast.bytepluses.com/api/v3';\nconst DEFAULT_MODELARK_MODEL = 'seedance-1-0-lite-t2v-250428';\nconst DEFAULT_MODELARK_I2V_MODEL = 'seedance-1-0-lite-i2v-250428';\n/** Burst capacity for the submit token bucket — see {@link SubmitRateLimiter}. */\nconst SUBMIT_BURST_CAPACITY = 2;\n\ntype ModelArkTaskStatus =\n | 'queued'\n | 'running'\n | 'cancelled'\n | 'succeeded'\n | 'failed'\n | 'expired';\n\ninterface ModelArkContentItem {\n type: 'text' | 'image_url';\n text?: string;\n image_url?: { url: string };\n role?: string;\n}\n\ninterface ModelArkCreateTaskRequest {\n model: string;\n content: ModelArkContentItem[];\n resolution?: string;\n ratio?: string;\n duration?: number;\n seed?: number;\n}\n\ninterface ModelArkCreateTaskResponse {\n id: string;\n}\n\ninterface ModelArkTaskResponse {\n id: string;\n model: string;\n status: ModelArkTaskStatus;\n content?: { video_url?: string; last_frame_url?: string };\n error?: { code: string; message: string } | null;\n created_at: number;\n updated_at: number;\n seed?: number;\n resolution?: string;\n ratio?: string;\n duration?: number;\n}\n\n/**\n * Resolve after `ms` milliseconds, or as soon as `signal` aborts —\n * whichever comes first. Never rejects; callers re-check `signal.aborted`\n * themselves immediately after, so a single check covers both \"timed out\n * normally\" and \"woke up early because of an abort.\"\n */\nfunction delayOrAbort(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/**\n * Local token-bucket + concurrency limiter for submit-time throttling.\n *\n * ModelArk documents Seedance account limits of QPS 2 / 3 *concurrent\n * submissions*; this only gates `submitVideoGenerationJob` (task creation\n * HTTP calls), matching the \"submit-time throttling\" requirement — polling\n * and cancellation are not subject to the same account-level task-creation\n * limits. `maxConcurrent` bounds concurrent in-flight *submit HTTP\n * requests*, not the lifetime of the provider-side render tasks those\n * submissions create — this limiter has no way to observe when a task\n * actually finishes rendering on ModelArk's infrastructure, so\n * task-lifetime concurrency is not, and cannot be, tracked here.\n *\n * The bucket's burst capacity is capped at {@link SUBMIT_BURST_CAPACITY}\n * (independent of `requestsPerMinute`) so the bucket doesn't start full —\n * without this cap, a bucket sized to `requestsPerMinute` (e.g. 120) would\n * start with 120 tokens and let the first 120 submits through instantly,\n * defeating the QPS limit entirely.\n */\nclass SubmitRateLimiter {\n private tokens: number;\n private lastRefill: number;\n private readonly maxTokens: number;\n private readonly refillRate: number; // tokens per second\n private activeRequests = 0;\n private readonly maxConcurrent: number;\n\n constructor(options: { requestsPerMinute?: number; maxConcurrent?: number }) {\n const requestsPerMinute = options.requestsPerMinute ?? 120; // ~QPS 2\n this.refillRate = requestsPerMinute / 60;\n this.maxTokens = SUBMIT_BURST_CAPACITY;\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n this.maxConcurrent = options.maxConcurrent ?? 3;\n }\n\n /**\n * Acquire a submit slot + token, honoring `signal` throughout the wait.\n *\n * The concurrency slot and the token are checked and committed together\n * in one synchronous section (no `await` between the check and the\n * `tokens -=`/`activeRequests +=` mutations below), so a waiter can never\n * observe a stale \"slot available\" snapshot from before another waiter's\n * own commit — closing the TOCTOU window where two callers could both\n * pass the checks and push `activeRequests` past `maxConcurrent`.\n *\n * An aborted `signal` — whether already aborted at entry or aborted\n * while waiting for a slot/token — throws before any token is consumed\n * or `activeRequests` is incremented, so an aborted submission never\n * silently proceeds to create a billable job.\n */\n async acquire(signal?: AbortSignal): Promise<void> {\n const throwIfAborted = () => {\n if (signal?.aborted) {\n throw new AIError(\n 'ModelArk submission aborted by caller while waiting for the rate limiter',\n 'AI_ABORTED',\n 'byteplus-modelark',\n );\n }\n };\n\n throwIfAborted();\n\n const now = Date.now();\n const elapsed = (now - this.lastRefill) / 1000;\n this.tokens = Math.min(\n this.maxTokens,\n this.tokens + elapsed * this.refillRate,\n );\n this.lastRefill = now;\n\n for (;;) {\n throwIfAborted();\n\n if (this.activeRequests < this.maxConcurrent && this.tokens >= 1) {\n this.tokens -= 1;\n this.activeRequests += 1;\n return;\n }\n\n if (this.activeRequests >= this.maxConcurrent) {\n await delayOrAbort(100, signal);\n } else {\n const waitTime = Math.max(\n 1,\n ((1 - this.tokens) / this.refillRate) * 1000,\n );\n await delayOrAbort(waitTime, signal);\n const elapsedNow = (Date.now() - this.lastRefill) / 1000;\n this.tokens = Math.min(\n this.maxTokens,\n this.tokens + elapsedNow * this.refillRate,\n );\n this.lastRefill = Date.now();\n }\n }\n }\n\n release(): void {\n this.activeRequests = Math.max(0, this.activeRequests - 1);\n }\n}\n\n/**\n * FNV-1a hash, used only to avoid retaining raw API keys as in-memory Map\n * keys in {@link sharedSubmitLimiters}. Not cryptographic — collisions just\n * mean two distinct keys share a rate-limit bucket, which is a pacing\n * inefficiency, not a security issue.\n */\nfunction hashKey(value: string): string {\n let hash = 2166136261;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Submit-time limiters keyed by credential/config, shared module-wide.\n *\n * Provider instances are frequently constructed per pipeline step (a fresh\n * `getAI({ type: 'byteplus-modelark', ... })` per job), so a limiter owned\n * by a single provider instance would reset on every construction and never\n * actually enforce the account-wide QPS/concurrency limits. Keying by the\n * resolved credentials (or an explicit `rateLimit.key`) lets independently\n * constructed instances that target the same ModelArk account share one\n * bucket, mirroring how {@link createRateLimitedAI}'s budget coordinators\n * are shared by `rateLimit.key`.\n */\nconst sharedSubmitLimiters = new Map<string, SubmitRateLimiter>();\n\nfunction getSharedSubmitLimiter(\n options: ByteplusModelArkOptions,\n): SubmitRateLimiter {\n const key =\n options.rateLimit?.key?.trim() ||\n `byteplus-modelark:${hashKey(options.apiKey || 'default')}`;\n\n let limiter = sharedSubmitLimiters.get(key);\n if (!limiter) {\n limiter = new SubmitRateLimiter({\n requestsPerMinute: options.rateLimit?.requestsPerMinute,\n maxConcurrent: options.rateLimit?.maxConcurrent,\n });\n sharedSubmitLimiters.set(key, limiter);\n }\n return limiter;\n}\n\n/** @internal Test-only: clear shared submit limiters between test cases. */\nexport function __resetByteplusModelArkRateLimitersForTests(): void {\n sharedSubmitLimiters.clear();\n}\n\n/**\n * BytePlus ModelArk provider implementation for asynchronous video\n * generation (Seedance). Focuses on video-generation capabilities and\n * throws `NOT_IMPLEMENTED` for text generation methods.\n *\n * @example\n * ```typescript\n * import { getAI } from '@happyvertical/ai';\n *\n * const modelark = await getAI({\n * type: 'byteplus-modelark',\n * apiKey: process.env.MODELARK_API_KEY!,\n * });\n *\n * const job = await modelark.submitVideoGenerationJob({\n * prompt: 'A drone shot flying over a coastal cliff at sunrise',\n * durationSeconds: 5,\n * resolution: '720p',\n * aspectRatio: '16:9',\n * });\n *\n * // Persist `job`, poll later (even after a restart):\n * const status = await modelark.getVideoGenerationJob(job);\n * ```\n */\nexport class ByteplusModelArkProvider implements AIInterface {\n private options: ByteplusModelArkOptions;\n private readonly submitLimiter: SubmitRateLimiter;\n\n constructor(options: ByteplusModelArkOptions) {\n // Note: deliberately no `defaultModel` fallback baked in here — the\n // model-selection logic in submitVideoGenerationJob picks between the\n // t2v and i2v defaults based on whether referenceImages are present,\n // and an unconditional default here would always shadow that.\n this.options = normalizeBaseAIOptions({ ...options });\n\n this.submitLimiter = getSharedSubmitLimiter(this.options);\n }\n\n private get baseUrl(): string {\n return (this.options.baseUrl || DEFAULT_MODELARK_BASE_URL).replace(\n /\\/+$/,\n '',\n );\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST' | 'DELETE';\n body?: unknown;\n query?: Record<string, string | number>;\n signal?: AbortSignal;\n timeout?: number;\n } = {},\n ): Promise<T> {\n if (options.signal?.aborted) {\n throw new AIError(\n 'ModelArk request aborted by caller',\n 'AI_ABORTED',\n 'byteplus-modelark',\n );\n }\n\n const url = new URL(`${this.baseUrl}${path}`);\n for (const [key, value] of Object.entries(options.query ?? {})) {\n url.searchParams.set(key, String(value));\n }\n\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.options.timeout;\n let timedOut = false;\n const timer = timeoutMs\n ? setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs)\n : undefined;\n // Mirrors `prepareRequestControls`'s pattern (packages/ai/src/shared/safety.ts):\n // addEventListener on an already-aborted signal never fires, so an\n // already-aborted `signal` must invoke the abort immediately instead of\n // only listening for a future 'abort' event.\n const onExternalAbort = () => controller.abort(options.signal?.reason);\n if (options.signal?.aborted) {\n onExternalAbort();\n } else {\n options.signal?.addEventListener('abort', onExternalAbort, {\n once: true,\n });\n }\n\n try {\n let response: Response;\n try {\n response = await fetch(url, {\n method: options.method || 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.options.apiKey ?? ''}`,\n ...(this.options.headers || {}),\n },\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n } catch (error) {\n // The fetch() call itself failed (network error, DNS failure,\n // timeout/abort) — wrap it into the AIError taxonomy so callers get\n // a consistent, retryable-vs-terminal-distinguishable error rather\n // than a raw TypeError/DOMException.\n if (timedOut) {\n throw new AIError(\n `ModelArk request to ${path} timed out after ${timeoutMs}ms`,\n 'AI_TIMEOUT',\n 'byteplus-modelark',\n undefined,\n true,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'ModelArk request aborted by caller',\n 'AI_ABORTED',\n 'byteplus-modelark',\n );\n }\n throw new AIError(\n `Network error calling ModelArk ${path}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'NETWORK_ERROR',\n 'byteplus-modelark',\n undefined,\n true,\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError('byteplus-modelark');\n }\n if (response.status === 429) {\n throw new RateLimitError(\n 'byteplus-modelark',\n extractRetryAfterSeconds({ headers: response.headers }),\n );\n }\n\n throw new AIError(\n `ModelArk request to ${path} failed: ${response.status} ${errorText}`,\n 'MODELARK_REQUEST_FAILED',\n 'byteplus-modelark',\n );\n }\n\n if (response.status === 204) {\n return {} as T;\n }\n\n const text = await response.text();\n return text ? (JSON.parse(text) as T) : ({} as T);\n } finally {\n if (timer) clearTimeout(timer);\n options.signal?.removeEventListener('abort', onExternalAbort);\n }\n }\n\n private toImageUrl(reference: VideoGenerationReferenceImage): string {\n if (typeof reference.image === 'string') {\n return reference.image;\n }\n const mimeType = reference.mimeType || 'image/png';\n return `data:${mimeType};base64,${reference.image.toString('base64')}`;\n }\n\n // ============================================================================\n // Video Generation Methods (Implemented)\n // ============================================================================\n\n /**\n * Submit an asynchronous Seedance video-generation task.\n *\n * Submission is locally throttled to approximate ModelArk's documented\n * Seedance account limits (QPS 2, capped at {@link SUBMIT_BURST_CAPACITY}\n * burst / 3 concurrent *submissions* — task-lifetime concurrency on\n * ModelArk's infrastructure is not tracked; see {@link SubmitRateLimiter}).\n *\n * When `referenceImages` are supplied and no explicit `model` is chosen,\n * this selects the image-to-video default model rather than silently\n * generating text-to-video with the image ignored.\n */\n async submitVideoGenerationJob(\n options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n const startTime = Date.now();\n await this.submitLimiter.acquire(options.signal);\n\n try {\n const hasReferenceImages = (options.referenceImages?.length ?? 0) > 0;\n const model =\n options.model ||\n this.options.defaultModel ||\n (hasReferenceImages\n ? DEFAULT_MODELARK_I2V_MODEL\n : DEFAULT_MODELARK_MODEL);\n\n const content: ModelArkContentItem[] = [];\n if (options.prompt) {\n content.push({ type: 'text', text: options.prompt });\n }\n for (const reference of options.referenceImages ?? []) {\n content.push({\n type: 'image_url',\n image_url: { url: this.toImageUrl(reference) },\n role: reference.role || 'reference_image',\n });\n }\n\n if (content.length === 0) {\n throw new AIError(\n 'submitVideoGenerationJob requires a prompt or at least one reference image',\n 'INVALID_INPUT',\n 'byteplus-modelark',\n );\n }\n\n const body: ModelArkCreateTaskRequest = {\n model,\n content,\n resolution: options.resolution,\n ratio: options.aspectRatio,\n duration: options.durationSeconds,\n seed: options.seed,\n };\n // Note: ModelArk's documented create-task schema has no negative_prompt\n // or fps fields, so those VideoGenerationOptions are intentionally not\n // forwarded for this provider.\n\n const response = await this.request<ModelArkCreateTaskResponse>(\n '/contents/generations/tasks',\n {\n method: 'POST',\n body,\n signal: options.signal,\n timeout: options.timeout,\n },\n );\n\n emitUsage(\n this.options,\n 'byteplus-modelark',\n 'submitVideoGenerationJob',\n model,\n undefined,\n startTime,\n {\n ...(options.durationSeconds !== undefined\n ? { durationSeconds: String(options.durationSeconds) }\n : {}),\n ...(options.resolution ? { resolution: options.resolution } : {}),\n ...(options.aspectRatio ? { aspectRatio: options.aspectRatio } : {}),\n ...options.usageTags,\n },\n );\n\n return {\n jobId: response.id,\n provider: 'byteplus-modelark',\n model,\n createdAt: new Date().toISOString(),\n };\n } finally {\n this.submitLimiter.release();\n }\n }\n\n /**\n * Poll the status of a ModelArk video-generation task.\n */\n async getVideoGenerationJob(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n const task = await this.request<ModelArkTaskResponse>(\n `/contents/generations/tasks/${handle.jobId}`,\n );\n return this.mapTask(task);\n }\n\n /**\n * Fetch the result of a completed ModelArk video-generation task.\n *\n * @throws {AIError} When the job has not succeeded yet\n */\n async fetchVideoGenerationResult(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n const status = await this.getVideoGenerationJob(handle);\n if (status.status !== 'succeeded' || !status.result) {\n throw new AIError(\n `ModelArk video-generation job ${handle.jobId} has not succeeded (status: ${status.status})`,\n 'VIDEO_JOB_NOT_READY',\n 'byteplus-modelark',\n handle.model,\n );\n }\n return status.result;\n }\n\n /**\n * Cancel a ModelArk video-generation task.\n *\n * ModelArk's DELETE endpoint only transitions a `queued` task to\n * `cancelled`; a task that is already `running` cannot be cancelled and\n * the request fails with an {@link AIError} describing why. Terminal\n * tasks (`succeeded`/`failed`/`expired`) are deleted instead.\n */\n async cancelVideoGenerationJob(handle: VideoGenerationJob): Promise<void> {\n await this.request(`/contents/generations/tasks/${handle.jobId}`, {\n method: 'DELETE',\n });\n }\n\n /**\n * Cheap auth-shaped check for ModelArk access: lists tasks with a page\n * size of 1. Callers on a hot path must cache the result themselves.\n */\n async validateVideoGenerationAccess(): Promise<boolean> {\n await this.request('/contents/generations/tasks', {\n query: { page_size: 1 },\n });\n return true;\n }\n\n private mapTask(task: ModelArkTaskResponse): VideoGenerationStatusResult {\n switch (task.status) {\n case 'queued':\n return { status: 'queued' };\n case 'running':\n return { status: 'running' };\n case 'cancelled':\n return { status: 'cancelled' };\n case 'expired':\n return {\n status: 'failed',\n error: 'ModelArk task expired before the result was retrieved',\n };\n case 'failed':\n return {\n status: 'failed',\n error: task.error?.message || 'ModelArk video generation failed',\n };\n case 'succeeded': {\n if (!task.content?.video_url) {\n return {\n status: 'failed',\n error: 'ModelArk reported success with no video_url',\n };\n }\n return {\n status: 'succeeded',\n result: {\n url: task.content.video_url,\n mimeType: 'video/mp4',\n durationSeconds: task.duration,\n },\n };\n }\n default:\n // Never invent a terminal state for a status this package doesn't\n // recognize (e.g. a future ModelArk status addition) — treat it as\n // still in flight so a caller doesn't misread a mid-render job as\n // failed, resubmit, and double-bill. The raw value is preserved for\n // diagnostics.\n return { status: 'running', rawStatus: task.status };\n }\n }\n\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: 'seedance-1-0-lite-t2v-250428',\n name: 'Seedance 1.0 Lite (text-to-video)',\n description: 'ModelArk Seedance 1.0 Lite text-to-video model',\n contextLength: 0,\n capabilities: ['video_generation'],\n supportsFunctions: false,\n supportsVision: false,\n },\n {\n id: 'seedance-1-0-lite-i2v-250428',\n name: 'Seedance 1.0 Lite (image-to-video)',\n description: 'ModelArk Seedance 1.0 Lite image-to-video model',\n contextLength: 0,\n capabilities: ['video_generation'],\n supportsFunctions: false,\n supportsVision: true,\n },\n ];\n }\n\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 'cancelVideoGenerationJob',\n ],\n };\n }\n\n // ============================================================================\n // Text Generation / TTS Methods (Not Implemented - Use another provider)\n // ============================================================================\n\n async chat(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): Promise<AIResponse> {\n throw new AIError(\n 'Chat is not supported by the BytePlus ModelArk provider. Use OpenAI, Anthropic, or another provider for text generation.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async complete(\n _prompt: string,\n _options?: CompletionOptions,\n ): Promise<AIResponse> {\n throw new AIError(\n 'Complete is not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async message(_text: string, _options?: MessageOptions): Promise<string> {\n throw new AIError(\n 'Message is not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async embed(\n _text: string | string[],\n _options?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n throw new AIError(\n 'Embeddings are not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async embedImage(\n _image: string | Buffer,\n _options?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n throw new AIError(\n 'Image embeddings are not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options?: ImageDescriptionOptions,\n ): Promise<string> {\n throw new AIError(\n 'Image description is not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async generateImage(\n _prompt: string,\n _options?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n throw new AIError(\n 'Synchronous image generation is not yet implemented by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n stream(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async countTokens(_text: string): Promise<number> {\n throw new AIError(\n 'Token counting is not supported by the BytePlus ModelArk provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n throw new AIError(\n 'TTS is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n throw new AIError(\n 'Voice cloning is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n throw new AIError(\n 'Voice design is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n throw new AIError(\n 'Voice listing is not supported by the BytePlus ModelArk provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'byteplus-modelark',\n );\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as ContextLengthError, c as extractTextContent, r as AuthenticationError, s as RateLimitError, t as AIError } from "./types-FHs-KbGL.js";
1
+ import { a as ContextLengthError, c as extractTextContent, r as AuthenticationError, s as RateLimitError, t as AIError } from "./types-CINwUPDo.js";
2
2
  import { t as emitUsage } from "./usage-C1Y1Nlg4.js";
3
3
  import { exec, spawn } from "node:child_process";
4
4
  import { promisify } from "node:util";
@@ -47,7 +47,7 @@ var ClaudeCliProvider = class {
47
47
  if (this.anthropicFallback !== null) return;
48
48
  const apiKey = process.env.ANTHROPIC_API_KEY;
49
49
  if (!apiKey) return;
50
- const { AnthropicProvider } = await import("./anthropic-DA8sdt12.js");
50
+ const { AnthropicProvider } = await import("./anthropic-DuYUnw8j.js");
51
51
  const defaultModel = {
52
52
  sonnet: "claude-3-5-sonnet-20241022",
53
53
  opus: "claude-3-opus-20240229",
@@ -464,6 +464,7 @@ var ClaudeCliProvider = class {
464
464
  fineTuning: false,
465
465
  imageEmbeddings: false,
466
466
  imageGeneration: false,
467
+ videoGeneration: false,
467
468
  tts: false,
468
469
  voiceCloning: false,
469
470
  voiceDesign: false,
@@ -475,6 +476,21 @@ var ClaudeCliProvider = class {
475
476
  ]
476
477
  };
477
478
  }
479
+ async submitVideoGenerationJob(_options) {
480
+ throw new AIError("Video generation is not supported by Claude CLI provider. Use gemini, byteplus-modelark, or openai-compat-video provider.", "NOT_IMPLEMENTED", "claude-cli");
481
+ }
482
+ async getVideoGenerationJob(_handle) {
483
+ throw new AIError("Video generation is not supported by Claude CLI provider. Use gemini, byteplus-modelark, or openai-compat-video provider.", "NOT_IMPLEMENTED", "claude-cli");
484
+ }
485
+ async fetchVideoGenerationResult(_handle) {
486
+ throw new AIError("Video generation is not supported by Claude CLI provider. Use gemini, byteplus-modelark, or openai-compat-video provider.", "NOT_IMPLEMENTED", "claude-cli");
487
+ }
488
+ async cancelVideoGenerationJob(_handle) {
489
+ throw new AIError("Video generation is not supported by Claude CLI provider. Use gemini, byteplus-modelark, or openai-compat-video provider.", "NOT_IMPLEMENTED", "claude-cli");
490
+ }
491
+ async validateVideoGenerationAccess() {
492
+ throw new AIError("Video generation is not supported by Claude CLI provider. Use gemini, byteplus-modelark, or openai-compat-video provider.", "NOT_IMPLEMENTED", "claude-cli");
493
+ }
478
494
  async synthesizeSpeech(_text, _options) {
479
495
  throw new AIError("TTS is not supported by Claude CLI provider. Use Qwen3-TTS provider.", "NOT_IMPLEMENTED", "claude-cli");
480
496
  }
@@ -495,4 +511,4 @@ var ClaudeCliProvider = class {
495
511
  //#endregion
496
512
  export { ClaudeCliProvider };
497
513
 
498
- //# sourceMappingURL=claude-cli-CnJh5KQT.js.map
514
+ //# sourceMappingURL=claude-cli-DeTKk9nu.js.map