@tanstack/ai-byteplus 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-byteplus",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "BytePlus ModelArk adapter for TanStack AI: Seed LLM chat, Seedance video, Seedream image, and Seed Speech TTS/ASR.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -48,18 +48,18 @@
48
48
  "text-to-speech"
49
49
  ],
50
50
  "devDependencies": {
51
- "@vitest/coverage-v8": "4.0.14",
52
- "vite": "^8.1.4",
53
- "@tanstack/ai": "0.43.0"
51
+ "@vitest/coverage-v8": "4.1.10",
52
+ "vite": "^8.2.1",
53
+ "@tanstack/ai": "0.45.0"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "zod": "^4.0.0",
57
- "@tanstack/ai": "^0.43.0"
57
+ "@tanstack/ai": "^0.45.0"
58
58
  },
59
59
  "dependencies": {
60
60
  "openai": "^6.41.0",
61
- "@tanstack/ai-utils": "0.4.0",
62
- "@tanstack/openai-base": "0.9.10"
61
+ "@tanstack/ai-utils": "^0.4.0",
62
+ "@tanstack/openai-base": "^0.9.13"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "vite build",
@@ -334,21 +334,20 @@ export class BytePlusTextAdapter<
334
334
  // Mirror the base's contract: failures inside structuredOutputStream
335
335
  // surface as a RUN_STARTED → RUN_ERROR pair rather than a throw, so
336
336
  // consumers keep a single error-handling path.
337
- const timestamp = Date.now()
338
337
  const runId = generateId(this.name)
339
338
  yield {
340
339
  type: EventType.RUN_STARTED,
341
340
  runId,
342
341
  threadId: options.chatOptions.threadId ?? generateId(this.name),
343
342
  model: options.chatOptions.model,
344
- timestamp,
343
+ timestamp: Date.now(),
345
344
  parentRunId: options.chatOptions.parentRunId,
346
345
  }
347
346
  yield {
348
347
  type: EventType.RUN_ERROR,
349
348
  runId,
350
349
  model: options.chatOptions.model,
351
- timestamp,
350
+ timestamp: Date.now(),
352
351
  message: unsupported,
353
352
  code: 'unsupported-structured-output',
354
353
  error: { message: unsupported, code: 'unsupported-structured-output' },
@@ -17,6 +17,7 @@ import {
17
17
  import {
18
18
  resolveBytePlusVideoResolution,
19
19
  resolveBytePlusVideoSize,
20
+ supportsAudioOnlyReference,
20
21
  supportsLastFrame,
21
22
  supportsReferenceMedia,
22
23
  } from '../video/video-provider-options'
@@ -161,7 +162,8 @@ function describeTaskFailure(task: BytePlusVideoTask): string {
161
162
  * `seedance-1-0-pro-fast-251015` does not support it at all.
162
163
  * - `'reference'` / `'character'` → `reference_image`, video parts →
163
164
  * `reference_video`, audio parts → `reference_audio` — subject and style
164
- * references the model draws on (`r2v`, Seedance 2.0 family only).
165
+ * references the model draws on (`r2v`, Seedance 2.5 and 2.0 family).
166
+ * Seedance 2.5 also accepts audio-only reference input; 2.0 does not.
165
167
  *
166
168
  * Frame roles and reference roles cannot be combined in one request, so the
167
169
  * adapter rejects a mix up front rather than surfacing a raw 400.
@@ -232,18 +234,18 @@ export class BytePlusVideoAdapter<
232
234
  if (resolved.text) content.push({ type: 'text', text: resolved.text })
233
235
 
234
236
  // Every rule below except the role vocabulary itself is a claim about a
235
- // *specific* model's capabilities, drawn from probing the six models that
236
- // exist today. None of it can be true of a model that does not exist yet,
237
- // so for an unknown id the guards stand down and Ark rules — otherwise the
238
- // escape hatch would block exactly the requests it exists to enable (see
237
+ // *specific* model's capabilities, drawn from the known Seedance catalog.
238
+ // None of it can be true of a model that does not exist yet, so for an
239
+ // unknown id the guards stand down and Ark rules — otherwise the escape
240
+ // hatch would block exactly the requests it exists to enable (see
239
241
  // BytePlusVideoModelOrString). 'mask' / 'control' still throw: Seedance's
240
242
  // wire format has no field to carry them on any model.
241
243
  const gated = isKnownBytePlusVideoModel(model)
242
244
 
243
245
  let firstFrames = 0
244
246
  let lastFrames = 0
245
- // Audio counts as a reference for the mode-exclusivity check but not for
246
- // the "audio can't be the only reference" rule, which wants a visual.
247
+ // Audio counts as a reference for the mode-exclusivity check. On Seedance
248
+ // 2.0 it also needs a visual reference; 2.5 allows audio-only.
247
249
  let visualReferences = 0
248
250
  let audioReferences = 0
249
251
 
@@ -277,8 +279,8 @@ export class BytePlusVideoAdapter<
277
279
  if (gated && !supportsReferenceMedia(model)) {
278
280
  throw new Error(
279
281
  `byteplus: ${model} does not support reference images. Reference ` +
280
- `media is available on the Seedance 2.0 family; on this model use ` +
281
- `'start_frame' / 'end_frame' images instead.`,
282
+ `media is available on Seedance 2.5 and the 2.0 family; on this ` +
283
+ `model use 'start_frame' / 'end_frame' images instead.`,
282
284
  )
283
285
  }
284
286
  visualReferences++
@@ -311,7 +313,7 @@ export class BytePlusVideoAdapter<
311
313
  if (gated && !supportsReferenceMedia(model)) {
312
314
  throw new Error(
313
315
  `byteplus: ${model} does not accept video prompt parts. Reference ` +
314
- `video is available on the Seedance 2.0 family only.`,
316
+ `video is available on Seedance 2.5 and the 2.0 family only.`,
315
317
  )
316
318
  }
317
319
  visualReferences++
@@ -326,7 +328,7 @@ export class BytePlusVideoAdapter<
326
328
  if (gated && !supportsReferenceMedia(model)) {
327
329
  throw new Error(
328
330
  `byteplus: ${model} does not accept audio prompt parts. Reference ` +
329
- `audio is available on the Seedance 2.0 family only.`,
331
+ `audio is available on Seedance 2.5 and the 2.0 family only.`,
330
332
  )
331
333
  }
332
334
  audioReferences++
@@ -372,10 +374,16 @@ export class BytePlusVideoAdapter<
372
374
  )
373
375
  }
374
376
 
375
- if (gated && audioReferences > 0 && visualReferences === 0) {
377
+ if (
378
+ gated &&
379
+ audioReferences > 0 &&
380
+ visualReferences === 0 &&
381
+ !supportsAudioOnlyReference(model)
382
+ ) {
376
383
  throw new Error(
377
384
  `byteplus: a reference audio input cannot be the only reference on ` +
378
- `model ${model}. Pair it with a reference image or video.`,
385
+ `model ${model}. Pair it with a reference image or video, or use ` +
386
+ `Seedance 2.5 which accepts audio-only reference input.`,
379
387
  )
380
388
  }
381
389
 
package/src/index.ts CHANGED
@@ -21,11 +21,13 @@ export {
21
21
  parseBytePlusVideoSize,
22
22
  resolveBytePlusVideoResolution,
23
23
  resolveBytePlusVideoSize,
24
+ supportsAudioOnlyReference,
24
25
  supportsLastFrame,
25
26
  supportsReferenceMedia,
26
27
  } from './video/video-provider-options'
27
28
  export type {
28
29
  BytePlusVideoModelProviderOptionsByName,
30
+ BytePlusVideoOutputFormat,
29
31
  BytePlusVideoProviderOptions,
30
32
  BytePlusVideoServiceTier,
31
33
  } from './video/video-provider-options'
package/src/model-meta.ts CHANGED
@@ -488,10 +488,11 @@ export type BytePlusVideoRatio =
488
488
  /**
489
489
  * Resolution tiers accepted by the Seedance task API.
490
490
  *
491
- * All four are probe-verified per model (2026-07-31). Two findings contradict
492
- * the BytePlus prose docs: there is **no 2K tier on any Seedance model** —
493
- * `2k`/`2K` is rejected everywhere, including on the 2.0 flagship documented
494
- * as reaching 4K — and `4k` exists only on `dreamina-seedance-2-0-260128`.
491
+ * Resolution tiers are model-specific (see
492
+ * {@link BytePlusVideoModelResolutionByName}). Two findings that still
493
+ * contradict older BytePlus prose: there is **no 2K tier on any Seedance
494
+ * model**, and `4k` exists only on `dreamina-seedance-2-0-260128` (Seedance
495
+ * 2.5 is 480p/720p only, per the live ModelArk docs).
495
496
  *
496
497
  * The API matches this field case-insensitively (`4K`, `4k` and `1080P` are
497
498
  * all accepted), so this package standardizes on the lowercase spelling.
@@ -508,11 +509,18 @@ export type BytePlusVideoSize<
508
509
  TResolution extends BytePlusVideoResolution = BytePlusVideoResolution,
509
510
  > = BytePlusVideoRatio | `${BytePlusVideoRatio}_${TResolution}`
510
511
 
511
- // The Seedance 2.0 family's `audio` input modality is docs-derived, not
512
- // live-probed: the docs' multimodal-reference caps list `reference_audio`
513
- // parts (up to 3, never sent without a visual reference). Every 2.0 model id
514
- // below is itself probe-verified live; only the audio-reference capability
515
- // rests on the docs.
512
+ // Multimodal reference-media capabilities (reference images / video / audio)
513
+ // are docs-derived from the ModelArk create-task page. Model ids and the
514
+ // resolution / duration tables for 2.0 were also live-probed on 2026-07-31;
515
+ // 2.5 lands from the public docs once the model was fully opened (2026-08-07).
516
+ const DREAMINA_SEEDANCE_2_5 = {
517
+ name: 'dreamina-seedance-2-5-260628',
518
+ supports: {
519
+ input: ['text', 'image', 'video', 'audio'],
520
+ output: ['video', 'audio'],
521
+ },
522
+ } as const satisfies ModelMeta
523
+
516
524
  const DREAMINA_SEEDANCE_2_0 = {
517
525
  name: 'dreamina-seedance-2-0-260128',
518
526
  supports: {
@@ -565,6 +573,7 @@ const SEEDANCE_1_0_PRO_FAST = {
565
573
  * All supported Seedance video model identifiers.
566
574
  */
567
575
  export const BYTEPLUS_VIDEO_MODELS = [
576
+ DREAMINA_SEEDANCE_2_5.name,
568
577
  DREAMINA_SEEDANCE_2_0.name,
569
578
  DREAMINA_SEEDANCE_2_0_FAST.name,
570
579
  DREAMINA_SEEDANCE_2_0_MINI.name,
@@ -580,11 +589,12 @@ export type BytePlusVideoModel = (typeof BYTEPLUS_VIDEO_MODELS)[number]
580
589
 
581
590
  /**
582
591
  * Type-only map from video model name to the non-text prompt modalities it
583
- * accepts. The Seedance 2.0 family takes multimodal references (start/end
584
- * frames, reference images, reference video and audio); the 1.x models take
585
- * start/end frames only.
592
+ * accepts. Seedance 2.5 and the 2.0 family take multimodal references
593
+ * (start/end frames, reference images, reference video and audio); the 1.x
594
+ * models take start/end frames only.
586
595
  */
587
596
  export type BytePlusVideoModelInputModalitiesByName = {
597
+ [DREAMINA_SEEDANCE_2_5.name]: readonly ['image', 'video', 'audio']
588
598
  [DREAMINA_SEEDANCE_2_0.name]: readonly ['image', 'video', 'audio']
589
599
  [DREAMINA_SEEDANCE_2_0_FAST.name]: readonly ['image', 'video', 'audio']
590
600
  [DREAMINA_SEEDANCE_2_0_MINI.name]: readonly ['image', 'video', 'audio']
@@ -596,10 +606,13 @@ export type BytePlusVideoModelInputModalitiesByName = {
596
606
  /**
597
607
  * Type-only map from video model name to the resolutions it accepts.
598
608
  *
599
- * Probe-verified per model on 2026-07-31. Note `seedance-1-0-pro-fast-251015`
600
- * does accept `1080p`, despite the BytePlus docs listing it as 480p/720p.
609
+ * 2.0 / 1.x cells were probe-verified on 2026-07-31; 2.5 comes from the
610
+ * public ModelArk create-task docs (2026-08-07). Note
611
+ * `seedance-1-0-pro-fast-251015` does accept `1080p`, despite older BytePlus
612
+ * prose listing it as 480p/720p.
601
613
  */
602
614
  export type BytePlusVideoModelResolutionByName = {
615
+ [DREAMINA_SEEDANCE_2_5.name]: '480p' | '720p'
603
616
  [DREAMINA_SEEDANCE_2_0.name]: '480p' | '720p' | '1080p' | '4k'
604
617
  [DREAMINA_SEEDANCE_2_0_FAST.name]: '480p' | '720p'
605
618
  [DREAMINA_SEEDANCE_2_0_MINI.name]: '480p' | '720p'
@@ -621,24 +634,16 @@ export type BytePlusVideoModelSizeByName = {
621
634
  * A Seedance model id: one this package knows, or any other string.
622
635
  *
623
636
  * The open half is a deliberate escape hatch for models BytePlus ships between
624
- * releases of this package. **Seedance 2.5 is the live example.** Its real id
625
- * is `dreamina-seedance-2-5-260628` — note the June date suffix, which is why
626
- * guessing ids around its 2026-07-31 announcement never landed. It is absent
627
- * from the table below because its capability cells are unverified, not
628
- * because it is unreachable: probing it returns 404 `ModelNotOpen` ("your
629
- * account has not activated the model"), so no capability question can be
630
- * answered until someone enables it in the Ark Console. Passing it through
631
- * the escape hatch works today for an account that has.
632
- *
633
- * Adding a model here *narrows* it — the adapter's guards switch on and reject
634
- * against this file's tables. For a model whose real limits are unknown that
635
- * is strictly worse than the open path, which lets Ark judge. So an id lands
636
- * here only once probed.
637
+ * releases of this package. Adding a model to {@link BYTEPLUS_VIDEO_MODELS}
638
+ * *narrows* it — the adapter's guards switch on and reject against this
639
+ * file's tables. For a model whose real limits are unknown that is strictly
640
+ * worse than the open path, which lets Ark judge. So an id lands in the
641
+ * known table only once its capability cells are documented or probed.
637
642
  *
638
643
  * Discovering ids: `GET /models` on the Ark data plane enumerates the catalog
639
- * (id, `task_type`, `modalities`, `status`) and is how 2.5 was found. It is
640
- * not exhaustive — `seedream-5-0-lite-260128` answers requests but is missing
641
- * from the listing — so absence there is not evidence of absence. The ModelArk
644
+ * (id, `task_type`, `modalities`, `status`). It is not exhaustive —
645
+ * `seedream-5-0-lite-260128` answers requests but is missing from the
646
+ * listing — so absence there is not evidence of absence. The ModelArk
642
647
  * release notes (https://docs.byteplus.com/en/docs/ModelArk/1159178) are the
643
648
  * other watch surface.
644
649
  *
@@ -651,7 +656,7 @@ export type BytePlusVideoModelSizeByName = {
651
656
  * Unknown ids trade compile-time narrowing for reach: the full size surface is
652
657
  * accepted, provider options are ungated, and the adapter's model-specific
653
658
  * runtime guards stand down so a new model's legitimate request reaches Ark.
654
- * Known ids keep their probe-verified narrowing.
659
+ * Known ids keep their documented / probe-verified narrowing.
655
660
  */
656
661
  export type BytePlusVideoModelOrString = BytePlusVideoModel | (string & {})
657
662
 
@@ -694,8 +699,8 @@ export function isKnownBytePlusVideoModel(
694
699
  * Per-model duration type. Seedance accepts any integer second inside the
695
700
  * model's range, so this is a continuous range expressed as `number` — a
696
701
  * literal union cannot represent it. (The API also accepts `duration: -1` on
697
- * Seedance 2.0 and 1.5-pro to let the model choose; that is reachable through
698
- * provider options, not through the generic `duration`.)
702
+ * Seedance 2.5, 2.0 and 1.5-pro to let the model choose; that is reachable
703
+ * through provider options, not through the generic `duration`.)
699
704
  */
700
705
  export type BytePlusVideoModelDurationByName = {
701
706
  [K in BytePlusVideoModel]: number
@@ -709,6 +714,13 @@ export const BYTEPLUS_VIDEO_DURATIONS: {
709
714
  BytePlusVideoModelDurationByName[TModel]
710
715
  >
711
716
  } = {
717
+ 'dreamina-seedance-2-5-260628': {
718
+ kind: 'range',
719
+ min: 4,
720
+ max: 30,
721
+ step: 1,
722
+ unit: 'seconds',
723
+ },
712
724
  'dreamina-seedance-2-0-260128': {
713
725
  kind: 'range',
714
726
  min: 4,
@@ -757,15 +769,15 @@ export const BYTEPLUS_VIDEO_DURATIONS: {
757
769
  * Duration hint for a model this package has no table for.
758
770
  *
759
771
  * Spans every range Seedance has shipped so far (2s on the 1.0 models through
760
- * 15s on the 2.0 family) so `availableDurations()` can still drive a UI. It is
772
+ * 30s on Seedance 2.5) so `availableDurations()` can still drive a UI. It is
761
773
  * a hint, not a contract: the adapter does **not** snap an unknown model's
762
- * duration against it, because clamping a future model's legitimate 20-second
763
- * request down to 15 would corrupt the request rather than protect it.
774
+ * duration against it, because clamping a future model's legitimate longer
775
+ * request down to 30 would corrupt the request rather than protect it.
764
776
  */
765
777
  export const BYTEPLUS_VIDEO_FALLBACK_DURATIONS: DurationOptions<number> = {
766
778
  kind: 'range',
767
779
  min: 2,
768
- max: 15,
780
+ max: 30,
769
781
  step: 1,
770
782
  unit: 'seconds',
771
783
  }
@@ -2,13 +2,15 @@
2
2
  * Provider options and per-model capability tables for the BytePlus Seedance
3
3
  * video models.
4
4
  *
5
- * Every applicability claim below was probed live against
5
+ * Applicability for Seedance 1.x / 2.0 was probed live against
6
6
  * `https://ark.ap-southeast.bytepluses.com/api/v3` on 2026-07-31. The probe
7
7
  * sent an out-of-range `seed` alongside the field under test, so requests that
8
8
  * passed validation still failed before a task was created (nothing billed):
9
9
  * an error naming the field under test means "rejected", an error naming
10
10
  * `seed` means "accepted". Ark reports only one arbitrary invalid parameter
11
- * per request, so each cell was retried until a verdict repeated.
11
+ * per request, so each cell was retried until a verdict repeated. Seedance 2.5
12
+ * cells come from the public ModelArk create-task docs once the model was
13
+ * fully opened (2026-08-07).
12
14
  *
13
15
  * Ark rejects an inapplicable field outright — "the specified parameter
14
16
  * `draft` is not supported for model seedance-1-0-pro in t2v, must be empty" —
@@ -17,15 +19,15 @@
17
19
  *
18
20
  * **Where the adapter guards, and where it doesn't** (deliberate, not an
19
21
  * 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.
22
+ * `frames`, `camera_fixed`, `output_format` — is left to Ark, whose 400 names
23
+ * the offending field and the model precisely enough to act on, and whose
24
+ * per-model rules shift as BytePlus ships models. Duplicating that here would
25
+ * mean a table that silently goes stale and starts rejecting requests the API
26
+ * would have accepted. The adapter guards locally only where the API's own
27
+ * error is misleading or arrives too late to be actionable: prompt media shape
28
+ * (role vocabulary, frame-vs-reference exclusivity, frame cardinality,
29
+ * audio-only reference) and the resolution tier, both of which are derived
30
+ * from a caller's `prompt` / `size` rather than passed through verbatim.
29
31
  *
30
32
  * @experimental Video generation is an experimental feature and may change.
31
33
  */
@@ -47,13 +49,24 @@ import type {
47
49
  * price, with no latency guarantee. Task ids come back with a `cgt-batch-`
48
50
  * prefix (live-verified).
49
51
  *
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
+ * Only the Seedance 1.x models accept this field. Seedance 2.5 and the 2.0
53
+ * family reject it ("service_tier is not supported … must be empty" / "not
54
+ * currently supported").
52
55
  *
53
56
  * @experimental Video generation is an experimental feature and may change.
54
57
  */
55
58
  export type BytePlusVideoServiceTier = 'default' | 'flex'
56
59
 
60
+ /**
61
+ * Container format of the generated video.
62
+ *
63
+ * Seedance 2.5 documents `mp4` (default) and `mov`. Other models historically
64
+ * return `mp4` only; scalar applicability is left to Ark (see file header).
65
+ *
66
+ * @experimental Video generation is an experimental feature and may change.
67
+ */
68
+ export type BytePlusVideoOutputFormat = 'mp4' | 'mov'
69
+
57
70
  /**
58
71
  * Provider-specific options for Seedance video generation. These map one-to-one
59
72
  * onto the create-task request body and take precedence over the values the
@@ -69,8 +82,8 @@ export interface BytePlusVideoProviderOptions {
69
82
  /**
70
83
  * Output aspect ratio. Overrides the ratio half of the generic `size`.
71
84
  *
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
85
+ * `adaptive` (follow the input frame) is the default on Seedance 2.5, 2.0
86
+ * and 1.5-pro but is rejected by Seedance 1.0-pro / 1.0-pro-fast for
74
87
  * text-to-video.
75
88
  */
76
89
  ratio?: BytePlusVideoRatio
@@ -78,8 +91,8 @@ export interface BytePlusVideoProviderOptions {
78
91
  /**
79
92
  * Output resolution tier. Overrides the resolution half of the generic
80
93
  * `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.
94
+ * lowercase throughout. `4k` exists only on `dreamina-seedance-2-0-260128`
95
+ * (Seedance 2.5 is 480p/720p only), and there is no 2K tier on any model.
83
96
  */
84
97
  resolution?: BytePlusVideoResolution
85
98
 
@@ -87,8 +100,8 @@ export interface BytePlusVideoProviderOptions {
87
100
  * Whole seconds of output. Overrides the generic `duration`, and unlike it
88
101
  * is sent verbatim rather than snapped into the model's range.
89
102
  *
90
- * `-1` asks the model to choose its own length; accepted by Seedance 2.0
91
- * and 1.5-pro only.
103
+ * `-1` asks the model to choose its own length; accepted by Seedance 2.5,
104
+ * 2.0 and 1.5-pro only. On 2.5 video-editing tasks, `-1` is required.
92
105
  */
93
106
  duration?: number
94
107
 
@@ -111,7 +124,7 @@ export interface BytePlusVideoProviderOptions {
111
124
  * Appends a "fix the camera" instruction to the prompt. Best-effort — the
112
125
  * model is not constrained to obey it.
113
126
  *
114
- * Seedance 1.5-pro, 1.0-pro and 1.0-pro-fast only; the 2.0 family rejects
127
+ * Seedance 1.5-pro, 1.0-pro and 1.0-pro-fast only; the 2.x family rejects
115
128
  * it.
116
129
  */
117
130
  camera_fixed?: boolean
@@ -125,12 +138,13 @@ export interface BytePlusVideoProviderOptions {
125
138
  * better results.
126
139
  *
127
140
  * Accepted by every model at the API's validation layer, but only Seedance
128
- * 2.0 and 1.5-pro actually produce audio.
141
+ * 2.5, 2.0 and 1.5-pro actually produce audio.
129
142
  */
130
143
  generate_audio?: boolean
131
144
 
132
145
  /**
133
- * Inference queue. Seedance 1.x only — the 2.0 family has no offline tier.
146
+ * Inference queue. Seedance 1.x only — Seedance 2.5 and the 2.0 family have
147
+ * no offline tier.
134
148
  */
135
149
  service_tier?: BytePlusVideoServiceTier
136
150
 
@@ -150,15 +164,21 @@ export interface BytePlusVideoProviderOptions {
150
164
  draft?: boolean
151
165
 
152
166
  /**
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.
167
+ * Queue priority, `[0, 9]`. Seedance 2.5 and the 2.0 family — 1.5-pro
168
+ * rejects it, and the 1.0 models accept it without acting on it.
155
169
  */
156
170
  priority?: number
157
171
 
172
+ /**
173
+ * Container of the generated video. Seedance 2.5 documents `mp4` (default)
174
+ * and `mov`; other models historically ship `mp4` only.
175
+ */
176
+ output_format?: BytePlusVideoOutputFormat
177
+
158
178
  /**
159
179
  * Seconds after `created_at` at which an unfinished task is abandoned and
160
180
  * 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
181
+ * (48 hours). The floor is enforced on Seedance 1.x but not on the 2.x
162
182
  * family.
163
183
  */
164
184
  execution_expires_after?: number
@@ -206,17 +226,19 @@ const BYTEPLUS_VIDEO_RATIOS: ReadonlyArray<string> = [
206
226
  ]
207
227
 
208
228
  /**
209
- * Resolutions each model accepts, live-probed.
229
+ * Resolutions each model accepts.
210
230
  *
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.
231
+ * 2.0 / 1.x cells were live-probed; 2.5 comes from the public ModelArk docs.
232
+ * Two findings still contradict older prose: there is no 2K tier on any
233
+ * Seedance model (`2k`/`2K` is rejected everywhere), and
234
+ * `seedance-1-0-pro-fast-251015` does accept `1080p` despite being documented
235
+ * as 480p/720p only. Seedance 2.5 is 480p/720p only — it does **not** offer
236
+ * the 2.0 flagship's 4k tier.
216
237
  */
217
238
  const BYTEPLUS_VIDEO_RESOLUTIONS: {
218
239
  readonly [K in BytePlusVideoModel]: ReadonlyArray<BytePlusVideoResolution>
219
240
  } = {
241
+ 'dreamina-seedance-2-5-260628': ['480p', '720p'],
220
242
  'dreamina-seedance-2-0-260128': ['480p', '720p', '1080p', '4k'],
221
243
  'dreamina-seedance-2-0-fast-260128': ['480p', '720p'],
222
244
  'dreamina-seedance-2-0-mini-260615': ['480p', '720p'],
@@ -231,6 +253,7 @@ const BYTEPLUS_VIDEO_RESOLUTIONS: {
231
253
  * models reject it with "the specified task_type r2v does not support model …".
232
254
  */
233
255
  const BYTEPLUS_VIDEO_REFERENCE_MEDIA_MODELS: ReadonlySet<string> = new Set([
256
+ 'dreamina-seedance-2-5-260628',
234
257
  'dreamina-seedance-2-0-260128',
235
258
  'dreamina-seedance-2-0-fast-260128',
236
259
  'dreamina-seedance-2-0-mini-260615',
@@ -242,6 +265,7 @@ const BYTEPLUS_VIDEO_REFERENCE_MEDIA_MODELS: ReadonlySet<string> = new Set([
242
265
  * does text-to-video and single-first-frame image-to-video only.
243
266
  */
244
267
  const BYTEPLUS_VIDEO_LAST_FRAME_MODELS: ReadonlySet<string> = new Set([
268
+ 'dreamina-seedance-2-5-260628',
245
269
  'dreamina-seedance-2-0-260128',
246
270
  'dreamina-seedance-2-0-fast-260128',
247
271
  'dreamina-seedance-2-0-mini-260615',
@@ -249,6 +273,15 @@ const BYTEPLUS_VIDEO_LAST_FRAME_MODELS: ReadonlySet<string> = new Set([
249
273
  'seedance-1-0-pro-250528',
250
274
  ])
251
275
 
276
+ /**
277
+ * Models that accept a reference-audio input without a visual reference
278
+ * alongside it. Seedance 2.5 documents audio-only reference-to-video; the 2.0
279
+ * family rejects it with "reference_audio cannot be the only reference input".
280
+ */
281
+ const BYTEPLUS_VIDEO_AUDIO_ONLY_REFERENCE_MODELS: ReadonlySet<string> = new Set(
282
+ ['dreamina-seedance-2-5-260628'],
283
+ )
284
+
252
285
  /**
253
286
  * True when the model is *known* to support reference-media mode (reference
254
287
  * images, video and audio). An id this package has no metadata for answers
@@ -271,6 +304,16 @@ export function supportsLastFrame(model: string): boolean {
271
304
  return BYTEPLUS_VIDEO_LAST_FRAME_MODELS.has(model)
272
305
  }
273
306
 
307
+ /**
308
+ * True when the model is *known* to accept a reference-audio input without a
309
+ * visual reference. Same unknown-id caveat as {@link supportsReferenceMedia}.
310
+ *
311
+ * @experimental Video generation is an experimental feature and may change.
312
+ */
313
+ export function supportsAudioOnlyReference(model: string): boolean {
314
+ return BYTEPLUS_VIDEO_AUDIO_ONLY_REFERENCE_MODELS.has(model)
315
+ }
316
+
274
317
  /**
275
318
  * Splits a `size` template into its Seedance request fields.
276
319
  *
@@ -85,8 +85,11 @@ export interface BytePlusVideoVideoContent {
85
85
  }
86
86
 
87
87
  /**
88
- * An audio input. Live-verified: audio can only accompany another reference
89
- * input — "reference_audio cannot be the only reference input".
88
+ * An audio input.
89
+ *
90
+ * On Seedance 2.0, audio can only accompany another reference input —
91
+ * "reference_audio cannot be the only reference input". Seedance 2.5
92
+ * documents audio-only reference-to-video.
90
93
  */
91
94
  export interface BytePlusVideoAudioContent {
92
95
  type: 'audio_url'
@@ -98,9 +101,10 @@ export interface BytePlusVideoAudioContent {
98
101
  * One entry of the `content[]` array.
99
102
  *
100
103
  * 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
+ * it — Seedance 2.5 accepts up to 30 reference images plus videos and audio,
105
+ * and 7 entries were accepted on `dreamina-seedance-2-0-260128`. The adapter
106
+ * therefore does not cap the array locally; a genuinely over-long request
107
+ * gets whatever Ark decides to say.
104
108
  */
105
109
  export type BytePlusVideoContentPart =
106
110
  | BytePlusVideoTextContent
@@ -115,14 +119,13 @@ export type BytePlusVideoContentPart =
115
119
  * model-dependent — Ark rejects an inapplicable field outright ("the
116
120
  * specified parameter `draft` is not supported for model … must be empty")
117
121
  * 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.
122
+ * for. See `video-provider-options.ts` for the applicability matrix.
120
123
  */
121
124
  export interface BytePlusVideoCreateRequest {
122
125
  /** Seedance model id (or a preconfigured endpoint id). */
123
126
  model: string
124
127
 
125
- /** Prompt text plus any image / video / audio inputs, max 5 entries. */
128
+ /** Prompt text plus any image / video / audio inputs. */
126
129
  content: Array<BytePlusVideoContentPart>
127
130
 
128
131
  /** Output aspect ratio, e.g. `16:9`. `adaptive` follows the input frame. */
@@ -131,7 +134,10 @@ export interface BytePlusVideoCreateRequest {
131
134
  /** Resolution tier, e.g. `720p`. Matched case-insensitively by the API. */
132
135
  resolution?: string
133
136
 
134
- /** Whole seconds of output. `-1` lets the model choose (Seedance 2.0 / 1.5). */
137
+ /**
138
+ * Whole seconds of output. `-1` lets the model choose (Seedance 2.5 / 2.0 /
139
+ * 1.5-pro).
140
+ */
135
141
  duration?: number
136
142
 
137
143
  /** Frame count, an alternative to `duration` that allows fractional seconds. */
@@ -161,6 +167,9 @@ export interface BytePlusVideoCreateRequest {
161
167
  /** Queue priority `[0, 9]`. */
162
168
  priority?: number
163
169
 
170
+ /** Container of the generated video, e.g. `mp4` or `mov`. */
171
+ output_format?: string
172
+
164
173
  /** Seconds from `created_at` after which the task is marked `expired`. */
165
174
  execution_expires_after?: number
166
175