@tanstack/ai-byteplus 0.0.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/dist/esm/adapters/image.d.ts +89 -0
  4. package/dist/esm/adapters/image.js +229 -0
  5. package/dist/esm/adapters/image.js.map +1 -0
  6. package/dist/esm/adapters/text.d.ts +163 -0
  7. package/dist/esm/adapters/text.js +347 -0
  8. package/dist/esm/adapters/text.js.map +1 -0
  9. package/dist/esm/adapters/transcription.d.ts +102 -0
  10. package/dist/esm/adapters/transcription.js +274 -0
  11. package/dist/esm/adapters/transcription.js.map +1 -0
  12. package/dist/esm/adapters/tts.d.ts +143 -0
  13. package/dist/esm/adapters/tts.js +307 -0
  14. package/dist/esm/adapters/tts.js.map +1 -0
  15. package/dist/esm/adapters/video.d.ts +182 -0
  16. package/dist/esm/adapters/video.js +442 -0
  17. package/dist/esm/adapters/video.js.map +1 -0
  18. package/dist/esm/audio/transcription-provider-options.d.ts +46 -0
  19. package/dist/esm/audio/tts-provider-options.d.ts +114 -0
  20. package/dist/esm/audio/wire-types.d.ts +261 -0
  21. package/dist/esm/audio/wire-types.js +28 -0
  22. package/dist/esm/audio/wire-types.js.map +1 -0
  23. package/dist/esm/image/image-provider-options.d.ts +165 -0
  24. package/dist/esm/image/image-provider-options.js +134 -0
  25. package/dist/esm/image/image-provider-options.js.map +1 -0
  26. package/dist/esm/image/wire-types.d.ts +149 -0
  27. package/dist/esm/index.d.ts +25 -0
  28. package/dist/esm/index.js +11 -0
  29. package/dist/esm/message-types.d.ts +154 -0
  30. package/dist/esm/model-meta.d.ts +594 -0
  31. package/dist/esm/model-meta.js +619 -0
  32. package/dist/esm/model-meta.js.map +1 -0
  33. package/dist/esm/text/text-provider-options.d.ts +109 -0
  34. package/dist/esm/utils/client.d.ts +183 -0
  35. package/dist/esm/utils/client.js +253 -0
  36. package/dist/esm/utils/client.js.map +1 -0
  37. package/dist/esm/video/video-provider-options.d.ts +197 -0
  38. package/dist/esm/video/video-provider-options.js +191 -0
  39. package/dist/esm/video/video-provider-options.js.map +1 -0
  40. package/dist/esm/video/wire-types.d.ts +248 -0
  41. package/package.json +77 -0
  42. package/src/adapters/image.ts +409 -0
  43. package/src/adapters/text.ts +539 -0
  44. package/src/adapters/transcription.ts +479 -0
  45. package/src/adapters/tts.ts +447 -0
  46. package/src/adapters/video.ts +732 -0
  47. package/src/audio/transcription-provider-options.ts +46 -0
  48. package/src/audio/tts-provider-options.ts +122 -0
  49. package/src/audio/wire-types.ts +290 -0
  50. package/src/image/image-provider-options.ts +288 -0
  51. package/src/image/wire-types.ts +169 -0
  52. package/src/index.ts +222 -0
  53. package/src/message-types.ts +169 -0
  54. package/src/model-meta.ts +954 -0
  55. package/src/text/text-provider-options.ts +151 -0
  56. package/src/utils/client.ts +377 -0
  57. package/src/video/video-provider-options.ts +361 -0
  58. package/src/video/wire-types.ts +293 -0
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Provider options and per-model capability tables for the BytePlus Seedance
3
+ * video models.
4
+ *
5
+ * Every applicability claim below was probed live against
6
+ * `https://ark.ap-southeast.bytepluses.com/api/v3` on 2026-07-31. The probe
7
+ * sent an out-of-range `seed` alongside the field under test, so requests that
8
+ * passed validation still failed before a task was created (nothing billed):
9
+ * an error naming the field under test means "rejected", an error naming
10
+ * `seed` means "accepted". Ark reports only one arbitrary invalid parameter
11
+ * per request, so each cell was retried until a verdict repeated.
12
+ *
13
+ * Ark rejects an inapplicable field outright — "the specified parameter
14
+ * `draft` is not supported for model seedance-1-0-pro in t2v, must be empty" —
15
+ * so these tables are not cosmetic: sending a field to the wrong model is a
16
+ * 400, not a no-op.
17
+ *
18
+ * **Where the adapter guards, and where it doesn't** (deliberate, not an
19
+ * oversight). Scalar applicability — `service_tier`, `draft`, `priority`,
20
+ * `frames`, `camera_fixed` — is left to Ark, whose 400 names the offending
21
+ * field and the model precisely enough to act on, and whose per-model rules
22
+ * shift as BytePlus ships models. Duplicating that here would mean a table
23
+ * that silently goes stale and starts rejecting requests the API would have
24
+ * accepted. The adapter guards locally only where the API's own error is
25
+ * misleading or arrives too late to be actionable: prompt media shape (role
26
+ * vocabulary, frame-vs-reference exclusivity, frame cardinality) and the
27
+ * resolution tier, both of which are derived from a caller's `prompt` /
28
+ * `size` rather than passed through verbatim.
29
+ *
30
+ * @experimental Video generation is an experimental feature and may change.
31
+ */
32
+
33
+ import { isKnownBytePlusVideoModel } from '../model-meta'
34
+ import type {
35
+ BytePlusVideoModel,
36
+ BytePlusVideoModelOrString,
37
+ BytePlusVideoRatio,
38
+ BytePlusVideoResolution,
39
+ } from '../model-meta'
40
+
41
+ /**
42
+ * Inference queue for the request.
43
+ *
44
+ * - `default` — online inference: lower RPM and concurrency quotas, lowest
45
+ * latency.
46
+ * - `flex` — offline batch inference: higher daily token quotas at half the
47
+ * price, with no latency guarantee. Task ids come back with a `cgt-batch-`
48
+ * prefix (live-verified).
49
+ *
50
+ * Only the Seedance 1.x models accept this field. The Seedance 2.0 family
51
+ * rejects it ("service_tier is not supported … must be empty").
52
+ *
53
+ * @experimental Video generation is an experimental feature and may change.
54
+ */
55
+ export type BytePlusVideoServiceTier = 'default' | 'flex'
56
+
57
+ /**
58
+ * Provider-specific options for Seedance video generation. These map one-to-one
59
+ * onto the create-task request body and take precedence over the values the
60
+ * adapter derives from the generic `size` / `duration` options.
61
+ *
62
+ * Fields are model-dependent; each one documents where it applies. Passing a
63
+ * field to a model that does not accept it is a 400 from Ark, not a silent
64
+ * ignore.
65
+ *
66
+ * @experimental Video generation is an experimental feature and may change.
67
+ */
68
+ export interface BytePlusVideoProviderOptions {
69
+ /**
70
+ * Output aspect ratio. Overrides the ratio half of the generic `size`.
71
+ *
72
+ * `adaptive` (follow the input frame) is the default on Seedance 2.0 and
73
+ * 1.5-pro but is rejected by Seedance 1.0-pro / 1.0-pro-fast for
74
+ * text-to-video.
75
+ */
76
+ ratio?: BytePlusVideoRatio
77
+
78
+ /**
79
+ * Output resolution tier. Overrides the resolution half of the generic
80
+ * `size`. Matched case-insensitively by the API; this package uses
81
+ * lowercase throughout. `4k` exists only on `dreamina-seedance-2-0-260128`,
82
+ * and there is no 2K tier on any model.
83
+ */
84
+ resolution?: BytePlusVideoResolution
85
+
86
+ /**
87
+ * Whole seconds of output. Overrides the generic `duration`, and unlike it
88
+ * is sent verbatim rather than snapped into the model's range.
89
+ *
90
+ * `-1` asks the model to choose its own length; accepted by Seedance 2.0
91
+ * and 1.5-pro only.
92
+ */
93
+ duration?: number
94
+
95
+ /**
96
+ * Frame count instead of `duration`, for fractional-second output. Takes
97
+ * precedence over `duration` server-side. Valid values are the integers of
98
+ * the form `25 + 4n` within `[29, 289]`, at 24 fps.
99
+ *
100
+ * Seedance 1.0-pro and 1.0-pro-fast only.
101
+ */
102
+ frames?: number
103
+
104
+ /**
105
+ * Randomness seed, an integer in `[-1, 2^32-1]`. `-1` (the default) leaves
106
+ * generation unseeded. Accepted by every Seedance model.
107
+ */
108
+ seed?: number
109
+
110
+ /**
111
+ * Appends a "fix the camera" instruction to the prompt. Best-effort — the
112
+ * model is not constrained to obey it.
113
+ *
114
+ * Seedance 1.5-pro, 1.0-pro and 1.0-pro-fast only; the 2.0 family rejects
115
+ * it.
116
+ */
117
+ camera_fixed?: boolean
118
+
119
+ /** Burn a watermark into the output. Defaults to `false`. */
120
+ watermark?: boolean
121
+
122
+ /**
123
+ * Generate an audio track synchronized with the visuals — dialogue, effects
124
+ * and score inferred from the prompt. Quote dialogue in the prompt for
125
+ * better results.
126
+ *
127
+ * Accepted by every model at the API's validation layer, but only Seedance
128
+ * 2.0 and 1.5-pro actually produce audio.
129
+ */
130
+ generate_audio?: boolean
131
+
132
+ /**
133
+ * Inference queue. Seedance 1.x only — the 2.0 family has no offline tier.
134
+ */
135
+ service_tier?: BytePlusVideoServiceTier
136
+
137
+ /**
138
+ * Also return the video's final frame as a watermark-free PNG, readable from
139
+ * the finished task as `content.last_frame_url`. Chain it into the next
140
+ * task's first frame to extend a shot. Accepted by every model.
141
+ */
142
+ return_last_frame?: boolean
143
+
144
+ /**
145
+ * Render a cheap, low-fidelity preview to sanity-check staging and camera
146
+ * work before paying for the real thing.
147
+ *
148
+ * Seedance 1.5-pro only.
149
+ */
150
+ draft?: boolean
151
+
152
+ /**
153
+ * Queue priority, `[0, 9]`. Seedance 2.0 family only — 1.5-pro rejects it,
154
+ * and the 1.0 models accept it without acting on it.
155
+ */
156
+ priority?: number
157
+
158
+ /**
159
+ * Seconds after `created_at` at which an unfinished task is abandoned and
160
+ * marked `expired`. Documented range `[3600, 259200]`, default 172800
161
+ * (48 hours). The floor is enforced on Seedance 1.x but not on the 2.0
162
+ * family.
163
+ */
164
+ execution_expires_after?: number
165
+
166
+ /**
167
+ * URL that receives a POST with the full task payload on every status
168
+ * change. BytePlus retries a failed delivery three times.
169
+ */
170
+ callback_url?: string
171
+
172
+ /**
173
+ * Stable opaque identifier for the end user driving the request, for abuse
174
+ * attribution. Max 64 characters — hash the real identifier rather than
175
+ * sending it.
176
+ */
177
+ safety_identifier?: string
178
+ }
179
+
180
+ /**
181
+ * Type-only map from video model name to its provider options. Seedance takes
182
+ * the same option surface across models; applicability is per-field and
183
+ * documented on {@link BytePlusVideoProviderOptions}.
184
+ *
185
+ * @experimental Video generation is an experimental feature and may change.
186
+ */
187
+ export type BytePlusVideoModelProviderOptionsByName = {
188
+ [K in BytePlusVideoModel]: BytePlusVideoProviderOptions
189
+ }
190
+
191
+ /**
192
+ * Aspect ratios accepted by the create endpoint.
193
+ *
194
+ * `adaptive` is rejected by Seedance 1.0-pro / 1.0-pro-fast for text-to-video
195
+ * but is the documented default for their image-to-video path, so it is not
196
+ * filtered per model here.
197
+ */
198
+ const BYTEPLUS_VIDEO_RATIOS: ReadonlyArray<string> = [
199
+ '16:9',
200
+ '9:16',
201
+ '4:3',
202
+ '3:4',
203
+ '1:1',
204
+ '21:9',
205
+ 'adaptive',
206
+ ]
207
+
208
+ /**
209
+ * Resolutions each model accepts, live-probed.
210
+ *
211
+ * Two findings here contradict the BytePlus prose docs and are worth calling
212
+ * out: there is no 2K tier on any Seedance model (`2k`/`2K` is rejected
213
+ * everywhere, including on the 2.0 flagship whose docs advertise "up to 4K"),
214
+ * and `seedance-1-0-pro-fast-251015` does accept `1080p` despite being
215
+ * documented as 480p/720p only.
216
+ */
217
+ const BYTEPLUS_VIDEO_RESOLUTIONS: {
218
+ readonly [K in BytePlusVideoModel]: ReadonlyArray<BytePlusVideoResolution>
219
+ } = {
220
+ 'dreamina-seedance-2-0-260128': ['480p', '720p', '1080p', '4k'],
221
+ 'dreamina-seedance-2-0-fast-260128': ['480p', '720p'],
222
+ 'dreamina-seedance-2-0-mini-260615': ['480p', '720p'],
223
+ 'seedance-1-5-pro-251215': ['480p', '720p', '1080p'],
224
+ 'seedance-1-0-pro-250528': ['480p', '720p', '1080p'],
225
+ 'seedance-1-0-pro-fast-251015': ['480p', '720p', '1080p'],
226
+ }
227
+
228
+ /**
229
+ * Models accepting reference-media mode (`r2v`): reference images, video and
230
+ * audio that the output draws on without pinning specific frames. The 1.x
231
+ * models reject it with "the specified task_type r2v does not support model …".
232
+ */
233
+ const BYTEPLUS_VIDEO_REFERENCE_MEDIA_MODELS: ReadonlySet<string> = new Set([
234
+ 'dreamina-seedance-2-0-260128',
235
+ 'dreamina-seedance-2-0-fast-260128',
236
+ 'dreamina-seedance-2-0-mini-260615',
237
+ ])
238
+
239
+ /**
240
+ * Models accepting a closing frame (`flf2v`, first-and-last-frame mode).
241
+ * `seedance-1-0-pro-fast-251015` is the one Seedance model without it — it
242
+ * does text-to-video and single-first-frame image-to-video only.
243
+ */
244
+ const BYTEPLUS_VIDEO_LAST_FRAME_MODELS: ReadonlySet<string> = new Set([
245
+ 'dreamina-seedance-2-0-260128',
246
+ 'dreamina-seedance-2-0-fast-260128',
247
+ 'dreamina-seedance-2-0-mini-260615',
248
+ 'seedance-1-5-pro-251215',
249
+ 'seedance-1-0-pro-250528',
250
+ ])
251
+
252
+ /**
253
+ * True when the model is *known* to support reference-media mode (reference
254
+ * images, video and audio). An id this package has no metadata for answers
255
+ * `false`; callers must decide whether that means "no" or "unknown" — the
256
+ * adapter treats it as unknown and lets Ark rule.
257
+ *
258
+ * @experimental Video generation is an experimental feature and may change.
259
+ */
260
+ export function supportsReferenceMedia(model: string): boolean {
261
+ return BYTEPLUS_VIDEO_REFERENCE_MEDIA_MODELS.has(model)
262
+ }
263
+
264
+ /**
265
+ * True when the model is *known* to support pinning the video's closing
266
+ * frame. Same unknown-id caveat as {@link supportsReferenceMedia}.
267
+ *
268
+ * @experimental Video generation is an experimental feature and may change.
269
+ */
270
+ export function supportsLastFrame(model: string): boolean {
271
+ return BYTEPLUS_VIDEO_LAST_FRAME_MODELS.has(model)
272
+ }
273
+
274
+ /**
275
+ * Splits a `size` template into its Seedance request fields.
276
+ *
277
+ * The template is either a bare aspect ratio (`'16:9'`) or
278
+ * `ratio_resolution` (`'16:9_720p'`), mirroring the grok video adapter.
279
+ * Returns `undefined` when the string doesn't match the template at all.
280
+ *
281
+ * The resolution half comes back lowercased. Ark itself matches the field
282
+ * case-insensitively, but this package standardizes on lowercase so callers
283
+ * can compare the result against {@link BytePlusVideoResolution} directly.
284
+ *
285
+ * @experimental Video generation is an experimental feature and may change.
286
+ */
287
+ export function parseBytePlusVideoSize(
288
+ size: string,
289
+ ): { ratio: string; resolution?: string } | undefined {
290
+ const match = /^(\d+:\d+|adaptive)(?:_(.+))?$/.exec(size)
291
+ const [, ratio, resolution] = match ?? []
292
+ if (ratio === undefined) return undefined
293
+ return {
294
+ ratio,
295
+ ...(resolution !== undefined && { resolution: resolution.toLowerCase() }),
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Validates a resolution against a model's tiers, returning it lowercased.
301
+ *
302
+ * Used for both halves of the request: the resolution parsed out of the
303
+ * generic `size`, and a `modelOptions.resolution` that overrides it. A model
304
+ * this package has no table for is normalized but not checked — see
305
+ * {@link BytePlusVideoModelOrString}.
306
+ *
307
+ * @throws Error when a known model does not offer the tier.
308
+ *
309
+ * @experimental Video generation is an experimental feature and may change.
310
+ */
311
+ export function resolveBytePlusVideoResolution(
312
+ model: BytePlusVideoModelOrString,
313
+ resolution: string,
314
+ ): string {
315
+ const normalized = resolution.toLowerCase()
316
+ if (!isKnownBytePlusVideoModel(model)) return normalized
317
+
318
+ const allowed = BYTEPLUS_VIDEO_RESOLUTIONS[model]
319
+ if (!allowed.includes(normalized as BytePlusVideoResolution)) {
320
+ throw new Error(
321
+ `byteplus: resolution "${resolution}" is not supported by model ` +
322
+ `"${model}". Supported resolutions: ${allowed.join(', ')}.`,
323
+ )
324
+ }
325
+ return normalized
326
+ }
327
+
328
+ /**
329
+ * Validates a `size` template against a model and returns the request fields
330
+ * it maps onto, with the resolution lowercased.
331
+ *
332
+ * For an unknown model only the template's *shape* is checked — enough to
333
+ * split it into `ratio` and `resolution` — because a future model may bring
334
+ * ratios and tiers that do not exist today. Ark validates the values.
335
+ *
336
+ * @throws Error when the template is malformed, or (known models only) the
337
+ * ratio is unknown or the resolution is not offered by this model.
338
+ *
339
+ * @experimental Video generation is an experimental feature and may change.
340
+ */
341
+ export function resolveBytePlusVideoSize(
342
+ model: BytePlusVideoModelOrString,
343
+ size: string,
344
+ ): { ratio: string; resolution?: string } {
345
+ const parsed = parseBytePlusVideoSize(size)
346
+ const known = isKnownBytePlusVideoModel(model)
347
+ if (!parsed || (known && !BYTEPLUS_VIDEO_RATIOS.includes(parsed.ratio))) {
348
+ throw new Error(
349
+ `byteplus: size "${size}" is not supported by model "${model}". Expected ` +
350
+ `"ratio" or "ratio_resolution" (e.g. "16:9_720p") with ratio one of: ` +
351
+ `${BYTEPLUS_VIDEO_RATIOS.join(', ')}.`,
352
+ )
353
+ }
354
+
355
+ return {
356
+ ratio: parsed.ratio,
357
+ ...(parsed.resolution !== undefined && {
358
+ resolution: resolveBytePlusVideoResolution(model, parsed.resolution),
359
+ }),
360
+ }
361
+ }
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Wire types for the BytePlus Ark Seedance video task API
3
+ * (`/contents/generations/tasks`).
4
+ *
5
+ * Hand-written minimal shapes covering only the fields this adapter sends and
6
+ * reads, with provenance noted inline. Three sources:
7
+ *
8
+ * 1. The harvested OpenAPI 3.1 documents for the `ark` service, actions
9
+ * `CreateContentsGenerationsTasks` (`x-updated-time: 2026-05-07`),
10
+ * `GetContentsGenerationsTask` (`2026-04-14`),
11
+ * `ListContentsGenerationsTasks` (`2026-03-24`) and
12
+ * `DeleteContentsGenerationsTasks` — authoritative for field names,
13
+ * defaults and response shapes.
14
+ * 2. Live calls against `https://ark.ap-southeast.bytepluses.com/api/v3` on
15
+ * 2026-07-31 with a real `ARK_API_KEY`, which pinned the create response,
16
+ * the per-model parameter applicability (see
17
+ * `video-provider-options.ts`) and the `content[]` role vocabulary.
18
+ * 3. The Seedance prose docs, for the retention windows.
19
+ *
20
+ * Two casing traps worth knowing: the response frame-rate field is
21
+ * `framespersecond` (all lowercase, no underscores), and `resolution` is
22
+ * matched case-insensitively on the way in (`4K`, `4k` and even `1080P` are
23
+ * all accepted — live-verified), so this package standardizes on lowercase.
24
+ */
25
+
26
+ /**
27
+ * Task lifecycle states.
28
+ *
29
+ * `queued` and `running` are non-terminal; the rest are terminal. `cancelled`
30
+ * records are dropped 24 hours after cancellation, and only a `queued` task
31
+ * can be cancelled at all.
32
+ *
33
+ * Source: `GetContentsGenerationsTask` / `ListContentsGenerationsTasks`
34
+ * `status` descriptions. (The Get document omits `expired` from its list
35
+ * while the List document includes it; `execution_expires_after` is documented
36
+ * as producing `expired` on both, so it is included here.)
37
+ */
38
+ export type BytePlusVideoTaskStatus =
39
+ | 'queued'
40
+ | 'running'
41
+ | 'succeeded'
42
+ | 'failed'
43
+ | 'cancelled'
44
+ | 'expired'
45
+
46
+ /**
47
+ * Role of a media item inside `content[]`.
48
+ *
49
+ * Live-verified: an unknown role is rejected with "invalid role specified for
50
+ * image content", and the API sorts requests into task types from the roles
51
+ * present — `i2v` (first frame), `flf2v` (first + last frame) and `r2v`
52
+ * (reference media). The two families are mutually exclusive: mixing them
53
+ * fails with "first/last frame content cannot be mixed with reference media
54
+ * content".
55
+ */
56
+ export type BytePlusVideoContentRole =
57
+ | 'first_frame'
58
+ | 'last_frame'
59
+ | 'reference_image'
60
+ | 'reference_video'
61
+ | 'reference_audio'
62
+
63
+ /** Instruction text for the generation. */
64
+ export interface BytePlusVideoTextContent {
65
+ type: 'text'
66
+ text: string
67
+ }
68
+
69
+ /**
70
+ * An image input. A public URL is fetched by BytePlus server-side; a
71
+ * `data:` URI carries the bytes inline.
72
+ */
73
+ export interface BytePlusVideoImageContent {
74
+ type: 'image_url'
75
+ image_url: { url: string }
76
+ /** Omitted for a bare first frame — the API defaults to `first_frame`. */
77
+ role?: BytePlusVideoContentRole
78
+ }
79
+
80
+ /** A video input. Reference-media mode requires `role: 'reference_video'`. */
81
+ export interface BytePlusVideoVideoContent {
82
+ type: 'video_url'
83
+ video_url: { url: string }
84
+ role?: BytePlusVideoContentRole
85
+ }
86
+
87
+ /**
88
+ * An audio input. Live-verified: audio can only accompany another reference
89
+ * input — "reference_audio cannot be the only reference input".
90
+ */
91
+ export interface BytePlusVideoAudioContent {
92
+ type: 'audio_url'
93
+ audio_url: { url: string }
94
+ role?: BytePlusVideoContentRole
95
+ }
96
+
97
+ /**
98
+ * One entry of the `content[]` array.
99
+ *
100
+ * The create schema declares `maxItems: 5`, but the live API does not enforce
101
+ * it — 7 entries (6 reference images plus text) were accepted on
102
+ * `dreamina-seedance-2-0-260128`. The adapter therefore does not cap the array
103
+ * locally; a genuinely over-long request gets whatever Ark decides to say.
104
+ */
105
+ export type BytePlusVideoContentPart =
106
+ | BytePlusVideoTextContent
107
+ | BytePlusVideoImageContent
108
+ | BytePlusVideoVideoContent
109
+ | BytePlusVideoAudioContent
110
+
111
+ /**
112
+ * Request body for `POST /contents/generations/tasks`.
113
+ *
114
+ * Only `model` and `content` are required. Every other field is
115
+ * model-dependent — Ark rejects an inapplicable field outright ("the
116
+ * specified parameter `draft` is not supported for model … must be empty")
117
+ * rather than ignoring it, so the adapter only sends what the caller asked
118
+ * for. See `video-provider-options.ts` for the live-probed applicability
119
+ * matrix.
120
+ */
121
+ export interface BytePlusVideoCreateRequest {
122
+ /** Seedance model id (or a preconfigured endpoint id). */
123
+ model: string
124
+
125
+ /** Prompt text plus any image / video / audio inputs, max 5 entries. */
126
+ content: Array<BytePlusVideoContentPart>
127
+
128
+ /** Output aspect ratio, e.g. `16:9`. `adaptive` follows the input frame. */
129
+ ratio?: string
130
+
131
+ /** Resolution tier, e.g. `720p`. Matched case-insensitively by the API. */
132
+ resolution?: string
133
+
134
+ /** Whole seconds of output. `-1` lets the model choose (Seedance 2.0 / 1.5). */
135
+ duration?: number
136
+
137
+ /** Frame count, an alternative to `duration` that allows fractional seconds. */
138
+ frames?: number
139
+
140
+ /** Randomness seed; integers in `[-1, 2^32-1]`, where `-1` means unseeded. */
141
+ seed?: number
142
+
143
+ /** Appends a "fix the camera" instruction to the prompt. Default `false`. */
144
+ camera_fixed?: boolean
145
+
146
+ /** Burn a watermark into the output. Default `false`. */
147
+ watermark?: boolean
148
+
149
+ /** Generate a synchronized audio track. Default `false`. */
150
+ generate_audio?: boolean
151
+
152
+ /** `default` (online) or `flex` (offline batch, half price). */
153
+ service_tier?: string
154
+
155
+ /** Also return the final frame as a PNG. Default `false`. */
156
+ return_last_frame?: boolean
157
+
158
+ /** Cheap low-fidelity preview render. Default `false`. */
159
+ draft?: boolean
160
+
161
+ /** Queue priority `[0, 9]`. */
162
+ priority?: number
163
+
164
+ /** Seconds from `created_at` after which the task is marked `expired`. */
165
+ execution_expires_after?: number
166
+
167
+ /** URL that receives a POST with the task payload on each status change. */
168
+ callback_url?: string
169
+
170
+ /** Opaque per-end-user identifier for abuse attribution, max 64 chars. */
171
+ safety_identifier?: string
172
+ }
173
+
174
+ /**
175
+ * Response of `POST /contents/generations/tasks`.
176
+ *
177
+ * Live-verified: the body is just the task id (e.g.
178
+ * `cgt-batch-20260731174311-zmz5s`; the `-batch` infix appears when the task
179
+ * is routed to the `flex` offline queue).
180
+ */
181
+ export interface BytePlusVideoCreateResponse {
182
+ id?: string
183
+ }
184
+
185
+ /**
186
+ * Error detail attached to a terminal task.
187
+ *
188
+ * Codes are the dotted/PascalCase Ark strings — the create, get and list
189
+ * documents enumerate `InputTextSensitiveContentDetected`,
190
+ * `InputImageSensitiveContentDetected`, `OutputVideoSensitiveContentDetected`
191
+ * and `QuotaExceeded` under `x-error-code`. The set is open-ended, so this
192
+ * stays a plain `string`.
193
+ */
194
+ export interface BytePlusVideoTaskError {
195
+ code?: string
196
+ message?: string
197
+ }
198
+
199
+ /**
200
+ * Token usage for a finished task. Video generation bills output only, so
201
+ * `total_tokens` equals `completion_tokens` and there is no prompt count.
202
+ *
203
+ * The schema types both counts as `string` while the documented example
204
+ * response shows bare numbers, so both are accepted and coerced.
205
+ */
206
+ export interface BytePlusVideoTaskUsage {
207
+ completion_tokens?: number | string
208
+ total_tokens?: number | string
209
+ /** Only present when a provider tool (web search) ran. */
210
+ tool_usage?: { web_search?: number }
211
+ }
212
+
213
+ /** Output URLs of a succeeded task. Both links expire 24 hours after success. */
214
+ export interface BytePlusVideoTaskContent {
215
+ /** MP4 download URL. */
216
+ video_url?: string
217
+ /** Final frame as PNG; only when `return_last_frame` was set. */
218
+ last_frame_url?: string
219
+ }
220
+
221
+ /**
222
+ * Response of `GET /contents/generations/tasks/{id}`.
223
+ *
224
+ * `content` appears once the task succeeds; `error` appears when it fails.
225
+ * Note `duration` comes back as a string here while the list endpoint types
226
+ * it as an integer, so both are accepted.
227
+ */
228
+ export interface BytePlusVideoTask {
229
+ id?: string
230
+ /** `{model name}-{version}` actually used — not necessarily the id sent. */
231
+ model?: string
232
+ status?: BytePlusVideoTaskStatus
233
+ error?: BytePlusVideoTaskError
234
+ /** Unix seconds. Anchors the 7-day task-record retention. */
235
+ created_at?: number
236
+ /** Unix seconds of the last status change — for a succeeded task, when the
237
+ * output (and its 24-hour URL) was produced. */
238
+ updated_at?: number
239
+ content?: BytePlusVideoTaskContent
240
+ seed?: number
241
+ resolution?: string
242
+ ratio?: string
243
+ duration?: number | string
244
+ frames?: number
245
+ /** Frame rate. Lowercase and unseparated on the wire — not `frames_per_second`. */
246
+ framespersecond?: number
247
+ generate_audio?: boolean
248
+ service_tier?: string
249
+ draft?: boolean
250
+ draft_task_id?: string
251
+ execution_expires_after?: number
252
+ safety_identifier?: string
253
+ usage?: BytePlusVideoTaskUsage
254
+
255
+ // The two fields below came back on a live succeeded task
256
+ // (`seedance-1-0-pro-fast-251015`, 2026-07-31) but are absent from the
257
+ // harvested Get schema.
258
+ /** Queue priority the task ran at. */
259
+ priority?: number
260
+ /** Container of the generated video, e.g. `mp4`. */
261
+ output_format?: string
262
+ }
263
+
264
+ /**
265
+ * One entry of the list response.
266
+ *
267
+ * The list document declares the same fields as the get document (including
268
+ * `error` — despite BytePlus prose elsewhere calling the list-side field
269
+ * `failure_reason`, no such field exists in the harvested schema, so it is
270
+ * not typed here).
271
+ */
272
+ export interface BytePlusVideoTaskListItem extends BytePlusVideoTask {}
273
+
274
+ /**
275
+ * Response of `GET /contents/generations/tasks`.
276
+ *
277
+ * Supported query parameters: `page_num` and `page_size` (both `[1, 500]`),
278
+ * `filter.status`, repeated `filter.task_ids`, and `filter.service_tier`.
279
+ *
280
+ * **`flex` tasks are missing from the default listing.** An unfiltered list
281
+ * returned `{total: 0, items: []}` both while a live `flex` task was running
282
+ * and immediately after it succeeded, so offline-tier work is invisible here
283
+ * unless `filter.service_tier=flex` is passed. Poll a known task id rather
284
+ * than relying on the listing to discover tasks.
285
+ */
286
+ export interface BytePlusVideoTaskListResponse {
287
+ items?: Array<BytePlusVideoTaskListItem>
288
+ total?: number
289
+ }
290
+
291
+ // `DELETE /contents/generations/tasks/{id}` cancels a `queued` task and
292
+ // deletes anything already terminal; its documented success body is an empty
293
+ // object, so no response interface is declared for it.