@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,954 @@
1
+ /**
2
+ * BytePlus ModelArk model metadata.
3
+ *
4
+ * Every Ark model id in this file — chat, video and image — was verified live
5
+ * against `https://ark.ap-southeast.bytepluses.com/api/v3` on 2026-07-31. The
6
+ * two Seed Speech ids are the exception: they live on the voice host, which
7
+ * needs a separate key that was not available, so they are docs-derived.
8
+ * Capability metadata is a mix of probed and docs-derived facts; anything not
9
+ * confirmed against the live API is annotated as such at its declaration.
10
+ * BytePlus
11
+ * deactivates model ids aggressively (the whole `seedance-1-0-lite-*` family,
12
+ * `seed-1-6-lite-*`, `seedream-3-0-*`, and the `doubao-`/`skylark-` names are
13
+ * all 404s internationally), so only dated, probe-confirmed ids are shipped.
14
+ *
15
+ * Prefix rules, also probe-confirmed:
16
+ * - `dola-seed-2-1-turbo-260628` and `dola-seedream-5-0-pro-260628` are the
17
+ * canonical ids; the bare forms resolve as aliases but the API echoes the
18
+ * prefixed id back.
19
+ * - The Seedance 2.0 family *requires* the `dreamina-` prefix.
20
+ * - Older models reject the `dola-` prefix outright.
21
+ */
22
+ import type { DurationOptions } from '@tanstack/ai/adapters'
23
+ import type { BytePlusTextProviderOptions } from './text/text-provider-options'
24
+
25
+ /**
26
+ * BytePlus exposes no server-side provider tools (no hosted web search, code
27
+ * interpreter, …) on the international Ark endpoint, so every chat model
28
+ * advertises an empty tool set. Typing it as `never` makes passing another
29
+ * provider's `ProviderTool` to a BytePlus adapter a compile-time error.
30
+ */
31
+ export type BytePlusProviderToolKind = never
32
+
33
+ /**
34
+ * Internal metadata structure describing a BytePlus model.
35
+ */
36
+ interface ModelMeta {
37
+ name: string
38
+ supports: {
39
+ input: ReadonlyArray<'text' | 'image' | 'audio' | 'video' | 'document'>
40
+ output: ReadonlyArray<'text' | 'image' | 'audio' | 'video'>
41
+ capabilities?: ReadonlyArray<
42
+ 'reasoning' | 'tool_calling' | 'structured_outputs'
43
+ >
44
+ tools?: ReadonlyArray<BytePlusProviderToolKind>
45
+ }
46
+ context_window?: number
47
+ max_input_tokens?: number
48
+ max_output_tokens?: number
49
+ }
50
+
51
+ // ============================================================================
52
+ // Chat models (Seed / GLM / DeepSeek / gpt-oss on Ark)
53
+ // ============================================================================
54
+
55
+ const DOLA_SEED_2_1_TURBO = {
56
+ name: 'dola-seed-2-1-turbo-260628',
57
+ context_window: 256_000,
58
+ max_input_tokens: 256_000,
59
+ max_output_tokens: 256_000,
60
+ supports: {
61
+ input: ['text', 'image', 'video'],
62
+ output: ['text'],
63
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
64
+ tools: [] as const,
65
+ },
66
+ } as const satisfies ModelMeta
67
+
68
+ const SEED_2_0_LITE_260428 = {
69
+ name: 'seed-2-0-lite-260428',
70
+ context_window: 256_000,
71
+ max_input_tokens: 256_000,
72
+ max_output_tokens: 128_000,
73
+ supports: {
74
+ input: ['text', 'image', 'video', 'audio'],
75
+ output: ['text'],
76
+ // Live-probed 2026-07-31: rejects both json_schema and json_object.
77
+ capabilities: ['reasoning', 'tool_calling'],
78
+ tools: [] as const,
79
+ },
80
+ } as const satisfies ModelMeta
81
+
82
+ const SEED_2_0_MINI_260428 = {
83
+ name: 'seed-2-0-mini-260428',
84
+ context_window: 256_000,
85
+ max_input_tokens: 256_000,
86
+ max_output_tokens: 128_000,
87
+ supports: {
88
+ input: ['text', 'image', 'video', 'audio'],
89
+ output: ['text'],
90
+ // Live-probed 2026-07-31: rejects both json_schema and json_object.
91
+ capabilities: ['reasoning', 'tool_calling'],
92
+ tools: [] as const,
93
+ },
94
+ } as const satisfies ModelMeta
95
+
96
+ const SEED_2_0_PRO_260328 = {
97
+ name: 'seed-2-0-pro-260328',
98
+ context_window: 256_000,
99
+ max_input_tokens: 224_000,
100
+ max_output_tokens: 128_000,
101
+ supports: {
102
+ input: ['text', 'image', 'video'],
103
+ output: ['text'],
104
+ // Live-probed 2026-07-31: accepts json_schema, despite the docs table
105
+ // saying otherwise.
106
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
107
+ tools: [] as const,
108
+ },
109
+ } as const satisfies ModelMeta
110
+
111
+ const SEED_2_0_LITE_260228 = {
112
+ name: 'seed-2-0-lite-260228',
113
+ context_window: 256_000,
114
+ max_input_tokens: 224_000,
115
+ max_output_tokens: 128_000,
116
+ supports: {
117
+ input: ['text', 'image', 'video'],
118
+ output: ['text'],
119
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
120
+ tools: [] as const,
121
+ },
122
+ } as const satisfies ModelMeta
123
+
124
+ const SEED_2_0_MINI_260215 = {
125
+ name: 'seed-2-0-mini-260215',
126
+ context_window: 256_000,
127
+ max_input_tokens: 224_000,
128
+ max_output_tokens: 128_000,
129
+ supports: {
130
+ input: ['text', 'image', 'video'],
131
+ output: ['text'],
132
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
133
+ tools: [] as const,
134
+ },
135
+ } as const satisfies ModelMeta
136
+
137
+ const SEED_2_0_CODE_PREVIEW_260328 = {
138
+ name: 'seed-2-0-code-preview-260328',
139
+ context_window: 256_000,
140
+ max_input_tokens: 224_000,
141
+ max_output_tokens: 128_000,
142
+ supports: {
143
+ input: ['text', 'image', 'video'],
144
+ output: ['text'],
145
+ capabilities: ['reasoning', 'tool_calling'],
146
+ tools: [] as const,
147
+ },
148
+ } as const satisfies ModelMeta
149
+
150
+ const SEED_1_8_251228 = {
151
+ name: 'seed-1-8-251228',
152
+ context_window: 256_000,
153
+ max_input_tokens: 224_000,
154
+ max_output_tokens: 64_000,
155
+ supports: {
156
+ input: ['text', 'image', 'video'],
157
+ output: ['text'],
158
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
159
+ tools: [] as const,
160
+ },
161
+ } as const satisfies ModelMeta
162
+
163
+ const SEED_1_6_250915 = {
164
+ name: 'seed-1-6-250915',
165
+ context_window: 256_000,
166
+ max_input_tokens: 224_000,
167
+ max_output_tokens: 32_000,
168
+ supports: {
169
+ input: ['text', 'image', 'video'],
170
+ output: ['text'],
171
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
172
+ tools: [] as const,
173
+ },
174
+ } as const satisfies ModelMeta
175
+
176
+ const SEED_1_6_250615 = {
177
+ name: 'seed-1-6-250615',
178
+ context_window: 256_000,
179
+ max_input_tokens: 224_000,
180
+ max_output_tokens: 32_000,
181
+ supports: {
182
+ input: ['text', 'image', 'video'],
183
+ output: ['text'],
184
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
185
+ tools: [] as const,
186
+ },
187
+ } as const satisfies ModelMeta
188
+
189
+ const SEED_1_6_FLASH_250715 = {
190
+ name: 'seed-1-6-flash-250715',
191
+ context_window: 256_000,
192
+ max_input_tokens: 224_000,
193
+ max_output_tokens: 32_000,
194
+ supports: {
195
+ input: ['text', 'image', 'video'],
196
+ output: ['text'],
197
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
198
+ tools: [] as const,
199
+ },
200
+ } as const satisfies ModelMeta
201
+
202
+ const SEED_1_6_FLASH_250615 = {
203
+ name: 'seed-1-6-flash-250615',
204
+ context_window: 256_000,
205
+ max_input_tokens: 224_000,
206
+ max_output_tokens: 32_000,
207
+ supports: {
208
+ input: ['text', 'image', 'video'],
209
+ output: ['text'],
210
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
211
+ tools: [] as const,
212
+ },
213
+ } as const satisfies ModelMeta
214
+
215
+ const GLM_5_2_260617 = {
216
+ name: 'glm-5-2-260617',
217
+ context_window: 1_024_000,
218
+ max_input_tokens: 1_024_000,
219
+ max_output_tokens: 128_000,
220
+ supports: {
221
+ input: ['text'],
222
+ output: ['text'],
223
+ // Live-probed 2026-07-31: accepts json_schema, despite the docs table
224
+ // saying otherwise.
225
+ capabilities: ['reasoning', 'tool_calling', 'structured_outputs'],
226
+ tools: [] as const,
227
+ },
228
+ } as const satisfies ModelMeta
229
+
230
+ const GLM_4_7_251222 = {
231
+ name: 'glm-4-7-251222',
232
+ context_window: 256_000,
233
+ max_input_tokens: 224_000,
234
+ max_output_tokens: 128_000,
235
+ supports: {
236
+ input: ['text'],
237
+ output: ['text'],
238
+ // Adherence-probed 2026-07-31: ACCEPTS a json_schema with 200 but ignores
239
+ // it and answers in prose, so it is not a structured-output model. A
240
+ // status-code-only probe reads this as support — see the note on
241
+ // BYTEPLUS_STRUCTURED_OUTPUT_CHAT_MODELS.
242
+ capabilities: ['reasoning', 'tool_calling'],
243
+ tools: [] as const,
244
+ },
245
+ } as const satisfies ModelMeta
246
+
247
+ const DEEPSEEK_V4_PRO_260425 = {
248
+ name: 'deepseek-v4-pro-260425',
249
+ context_window: 1_024_000,
250
+ max_input_tokens: 1_024_000,
251
+ max_output_tokens: 384_000,
252
+ supports: {
253
+ input: ['text'],
254
+ output: ['text'],
255
+ capabilities: ['reasoning', 'tool_calling'],
256
+ tools: [] as const,
257
+ },
258
+ } as const satisfies ModelMeta
259
+
260
+ const DEEPSEEK_V4_FLASH_260425 = {
261
+ name: 'deepseek-v4-flash-260425',
262
+ context_window: 1_024_000,
263
+ max_input_tokens: 1_024_000,
264
+ max_output_tokens: 384_000,
265
+ supports: {
266
+ input: ['text'],
267
+ output: ['text'],
268
+ capabilities: ['reasoning', 'tool_calling'],
269
+ tools: [] as const,
270
+ },
271
+ } as const satisfies ModelMeta
272
+
273
+ // The one model on Ark that defaults to `thinking: disabled`.
274
+ const DEEPSEEK_V3_2_251201 = {
275
+ name: 'deepseek-v3-2-251201',
276
+ context_window: 128_000,
277
+ max_input_tokens: 128_000,
278
+ max_output_tokens: 32_000,
279
+ supports: {
280
+ input: ['text'],
281
+ output: ['text'],
282
+ // Live-probed 2026-07-31: rejects both json_schema and json_object.
283
+ capabilities: ['reasoning', 'tool_calling'],
284
+ tools: [] as const,
285
+ },
286
+ } as const satisfies ModelMeta
287
+
288
+ // The only model accepting `thinking: {type: 'auto'}`. Tool calling is
289
+ // undocumented on Ark and unverified, so it is not advertised.
290
+ const GPT_OSS_120B_250805 = {
291
+ name: 'gpt-oss-120b-250805',
292
+ context_window: 128_000,
293
+ max_input_tokens: 96_000,
294
+ max_output_tokens: 64_000,
295
+ supports: {
296
+ input: ['text'],
297
+ output: ['text'],
298
+ capabilities: ['reasoning'],
299
+ tools: [] as const,
300
+ },
301
+ } as const satisfies ModelMeta
302
+
303
+ /**
304
+ * All supported BytePlus chat model identifiers.
305
+ */
306
+ export const BYTEPLUS_CHAT_MODELS = [
307
+ DOLA_SEED_2_1_TURBO.name,
308
+ SEED_2_0_LITE_260428.name,
309
+ SEED_2_0_MINI_260428.name,
310
+ SEED_2_0_PRO_260328.name,
311
+ SEED_2_0_LITE_260228.name,
312
+ SEED_2_0_MINI_260215.name,
313
+ SEED_2_0_CODE_PREVIEW_260328.name,
314
+ SEED_1_8_251228.name,
315
+ SEED_1_6_250915.name,
316
+ SEED_1_6_250615.name,
317
+ SEED_1_6_FLASH_250715.name,
318
+ SEED_1_6_FLASH_250615.name,
319
+ GLM_5_2_260617.name,
320
+ GLM_4_7_251222.name,
321
+ DEEPSEEK_V4_PRO_260425.name,
322
+ DEEPSEEK_V4_FLASH_260425.name,
323
+ DEEPSEEK_V3_2_251201.name,
324
+ GPT_OSS_120B_250805.name,
325
+ ] as const
326
+
327
+ /**
328
+ * Union of all supported BytePlus chat model names.
329
+ */
330
+ export type BytePlusChatModel = (typeof BYTEPLUS_CHAT_MODELS)[number]
331
+
332
+ /**
333
+ * Chat models that emit a `encrypted_content` blob alongside
334
+ * `reasoning_content` when thinking is enabled ("thinking summary" models).
335
+ *
336
+ * The blob is an opaque signature over the reasoning trace: when it is
337
+ * present it must be echoed back verbatim on the assistant message in the
338
+ * next turn. Live probing showed omitting it did *not* fail a simple tool
339
+ * round-trip, so adapters preserve and replay it when present but must never
340
+ * treat its absence as an error.
341
+ */
342
+ export const BYTEPLUS_THINKING_SUMMARY_MODELS = [
343
+ DOLA_SEED_2_1_TURBO.name,
344
+ SEED_2_0_LITE_260428.name,
345
+ SEED_2_0_MINI_260428.name,
346
+ SEED_2_0_PRO_260328.name,
347
+ ] as const
348
+
349
+ /**
350
+ * Union of chat models that emit `encrypted_content`.
351
+ */
352
+ export type BytePlusThinkingSummaryModel =
353
+ (typeof BYTEPLUS_THINKING_SUMMARY_MODELS)[number]
354
+
355
+ const THINKING_SUMMARY_MODEL_SET: ReadonlySet<string> = new Set(
356
+ BYTEPLUS_THINKING_SUMMARY_MODELS,
357
+ )
358
+
359
+ /**
360
+ * True when the model emits `encrypted_content` that should be round-tripped
361
+ * on subsequent turns.
362
+ */
363
+ export function emitsEncryptedContent(model: string): boolean {
364
+ return THINKING_SUMMARY_MODEL_SET.has(model)
365
+ }
366
+
367
+ /**
368
+ * Chat models that accept `response_format: {type: 'json_schema'}`.
369
+ *
370
+ * Live-probed against all 18 chat models on 2026-07-31, not docs-derived — the
371
+ * BytePlus capability tables are wrong here in both directions.
372
+ *
373
+ * Membership needs TWO things, because the API has both failure modes:
374
+ * 1. The request is accepted. Seven models (`seed-2-0-lite-260428`,
375
+ * `seed-2-0-mini-260428`, `seed-2-0-code-preview-260328`, both
376
+ * `deepseek-v4-*`, `deepseek-v3-2-251201`, `gpt-oss-120b-250805`) answer a
377
+ * JSON schema with 400 InvalidParameter — and reject
378
+ * `{type: 'json_object'}` too, so there is no JSON-mode fallback.
379
+ * 2. The schema is actually honoured. `glm-4-7-251222` accepts the request
380
+ * with 200 and then ignores the schema, answering in prose (reproduced
381
+ * twice by the adherence probe). A status-code-only probe wrongly reads
382
+ * that as support, so it is excluded.
383
+ *
384
+ * Models that fail either check need tool-shaped extraction instead.
385
+ *
386
+ * Note that the default chat model `seed-2-0-lite-260428` is one of the
387
+ * rejecting models: structured-output work needs `seed-2-0-lite-260228` or
388
+ * `dola-seed-2-1-turbo-260628`.
389
+ */
390
+ export const BYTEPLUS_STRUCTURED_OUTPUT_CHAT_MODELS = [
391
+ DOLA_SEED_2_1_TURBO.name,
392
+ SEED_2_0_PRO_260328.name,
393
+ SEED_2_0_LITE_260228.name,
394
+ SEED_2_0_MINI_260215.name,
395
+ SEED_1_8_251228.name,
396
+ SEED_1_6_250915.name,
397
+ SEED_1_6_250615.name,
398
+ SEED_1_6_FLASH_250715.name,
399
+ SEED_1_6_FLASH_250615.name,
400
+ GLM_5_2_260617.name,
401
+ ] as const
402
+
403
+ const STRUCTURED_OUTPUT_MODEL_SET: ReadonlySet<string> = new Set(
404
+ BYTEPLUS_STRUCTURED_OUTPUT_CHAT_MODELS,
405
+ )
406
+
407
+ /**
408
+ * True when the model supports native JSON-schema structured output.
409
+ */
410
+ export function supportsStructuredOutput(model: string): boolean {
411
+ return STRUCTURED_OUTPUT_MODEL_SET.has(model)
412
+ }
413
+
414
+ /**
415
+ * Type-only map from chat model name to whether it supports native
416
+ * JSON-schema structured output.
417
+ */
418
+ export type BytePlusChatModelStructuredOutputByName = {
419
+ [K in BytePlusChatModel]: K extends BytePlusStructuredOutputChatModel
420
+ ? true
421
+ : false
422
+ }
423
+
424
+ /**
425
+ * Union of chat models supporting native JSON-schema structured output.
426
+ */
427
+ export type BytePlusStructuredOutputChatModel =
428
+ (typeof BYTEPLUS_STRUCTURED_OUTPUT_CHAT_MODELS)[number]
429
+
430
+ /**
431
+ * Type-only map from chat model name to its supported input modalities.
432
+ * Used for type inference when constructing multimodal messages.
433
+ */
434
+ export type BytePlusModelInputModalitiesByName = {
435
+ [DOLA_SEED_2_1_TURBO.name]: typeof DOLA_SEED_2_1_TURBO.supports.input
436
+ [SEED_2_0_LITE_260428.name]: typeof SEED_2_0_LITE_260428.supports.input
437
+ [SEED_2_0_MINI_260428.name]: typeof SEED_2_0_MINI_260428.supports.input
438
+ [SEED_2_0_PRO_260328.name]: typeof SEED_2_0_PRO_260328.supports.input
439
+ [SEED_2_0_LITE_260228.name]: typeof SEED_2_0_LITE_260228.supports.input
440
+ [SEED_2_0_MINI_260215.name]: typeof SEED_2_0_MINI_260215.supports.input
441
+ [SEED_2_0_CODE_PREVIEW_260328.name]: typeof SEED_2_0_CODE_PREVIEW_260328.supports.input
442
+ [SEED_1_8_251228.name]: typeof SEED_1_8_251228.supports.input
443
+ [SEED_1_6_250915.name]: typeof SEED_1_6_250915.supports.input
444
+ [SEED_1_6_250615.name]: typeof SEED_1_6_250615.supports.input
445
+ [SEED_1_6_FLASH_250715.name]: typeof SEED_1_6_FLASH_250715.supports.input
446
+ [SEED_1_6_FLASH_250615.name]: typeof SEED_1_6_FLASH_250615.supports.input
447
+ [GLM_5_2_260617.name]: typeof GLM_5_2_260617.supports.input
448
+ [GLM_4_7_251222.name]: typeof GLM_4_7_251222.supports.input
449
+ [DEEPSEEK_V4_PRO_260425.name]: typeof DEEPSEEK_V4_PRO_260425.supports.input
450
+ [DEEPSEEK_V4_FLASH_260425.name]: typeof DEEPSEEK_V4_FLASH_260425.supports.input
451
+ [DEEPSEEK_V3_2_251201.name]: typeof DEEPSEEK_V3_2_251201.supports.input
452
+ [GPT_OSS_120B_250805.name]: typeof GPT_OSS_120B_250805.supports.input
453
+ }
454
+
455
+ /**
456
+ * Type-only map from chat model name to its supported provider tools.
457
+ * BytePlus exposes no provider-tool factories, so every model gets an empty
458
+ * tuple — passing another provider's tool is then a compile-time error.
459
+ */
460
+ export type BytePlusChatModelToolCapabilitiesByName = {
461
+ [K in BytePlusChatModel]: ReadonlyArray<BytePlusProviderToolKind>
462
+ }
463
+
464
+ /**
465
+ * Type-only map from chat model name to its provider options type.
466
+ */
467
+ export type BytePlusChatModelProviderOptionsByName = {
468
+ [K in BytePlusChatModel]: BytePlusTextProviderOptions
469
+ }
470
+
471
+ // ============================================================================
472
+ // Video models (Seedance, async task API)
473
+ // ============================================================================
474
+
475
+ /**
476
+ * Output aspect ratios accepted by the Seedance task API. `adaptive` is only
477
+ * meaningful for image-to-video, where the ratio follows the input frame.
478
+ */
479
+ export type BytePlusVideoRatio =
480
+ | '16:9'
481
+ | '9:16'
482
+ | '4:3'
483
+ | '3:4'
484
+ | '1:1'
485
+ | '21:9'
486
+ | 'adaptive'
487
+
488
+ /**
489
+ * Resolution tiers accepted by the Seedance task API.
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`.
495
+ *
496
+ * The API matches this field case-insensitively (`4K`, `4k` and `1080P` are
497
+ * all accepted), so this package standardizes on the lowercase spelling.
498
+ */
499
+ export type BytePlusVideoResolution = '480p' | '720p' | '1080p' | '4k'
500
+
501
+ /**
502
+ * Generic `size` template for Seedance models: either a bare aspect ratio
503
+ * ("16:9") or `ratio_resolution` ("16:9_720p"). The Seedance API takes the
504
+ * two as separate `ratio` / `resolution` fields; the adapter splits this
505
+ * template back apart.
506
+ */
507
+ export type BytePlusVideoSize<
508
+ TResolution extends BytePlusVideoResolution = BytePlusVideoResolution,
509
+ > = BytePlusVideoRatio | `${BytePlusVideoRatio}_${TResolution}`
510
+
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.
516
+ const DREAMINA_SEEDANCE_2_0 = {
517
+ name: 'dreamina-seedance-2-0-260128',
518
+ supports: {
519
+ input: ['text', 'image', 'video', 'audio'],
520
+ output: ['video', 'audio'],
521
+ },
522
+ } as const satisfies ModelMeta
523
+
524
+ const DREAMINA_SEEDANCE_2_0_FAST = {
525
+ name: 'dreamina-seedance-2-0-fast-260128',
526
+ supports: {
527
+ input: ['text', 'image', 'video', 'audio'],
528
+ output: ['video', 'audio'],
529
+ },
530
+ } as const satisfies ModelMeta
531
+
532
+ const DREAMINA_SEEDANCE_2_0_MINI = {
533
+ name: 'dreamina-seedance-2-0-mini-260615',
534
+ supports: {
535
+ input: ['text', 'image', 'video', 'audio'],
536
+ output: ['video', 'audio'],
537
+ },
538
+ } as const satisfies ModelMeta
539
+
540
+ const SEEDANCE_1_5_PRO = {
541
+ name: 'seedance-1-5-pro-251215',
542
+ supports: {
543
+ input: ['text', 'image'],
544
+ output: ['video', 'audio'],
545
+ },
546
+ } as const satisfies ModelMeta
547
+
548
+ const SEEDANCE_1_0_PRO = {
549
+ name: 'seedance-1-0-pro-250528',
550
+ supports: {
551
+ input: ['text', 'image'],
552
+ output: ['video'],
553
+ },
554
+ } as const satisfies ModelMeta
555
+
556
+ const SEEDANCE_1_0_PRO_FAST = {
557
+ name: 'seedance-1-0-pro-fast-251015',
558
+ supports: {
559
+ input: ['text', 'image'],
560
+ output: ['video'],
561
+ },
562
+ } as const satisfies ModelMeta
563
+
564
+ /**
565
+ * All supported Seedance video model identifiers.
566
+ */
567
+ export const BYTEPLUS_VIDEO_MODELS = [
568
+ DREAMINA_SEEDANCE_2_0.name,
569
+ DREAMINA_SEEDANCE_2_0_FAST.name,
570
+ DREAMINA_SEEDANCE_2_0_MINI.name,
571
+ SEEDANCE_1_5_PRO.name,
572
+ SEEDANCE_1_0_PRO.name,
573
+ SEEDANCE_1_0_PRO_FAST.name,
574
+ ] as const
575
+
576
+ /**
577
+ * Union of all supported Seedance video model names.
578
+ */
579
+ export type BytePlusVideoModel = (typeof BYTEPLUS_VIDEO_MODELS)[number]
580
+
581
+ /**
582
+ * 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.
586
+ */
587
+ export type BytePlusVideoModelInputModalitiesByName = {
588
+ [DREAMINA_SEEDANCE_2_0.name]: readonly ['image', 'video', 'audio']
589
+ [DREAMINA_SEEDANCE_2_0_FAST.name]: readonly ['image', 'video', 'audio']
590
+ [DREAMINA_SEEDANCE_2_0_MINI.name]: readonly ['image', 'video', 'audio']
591
+ [SEEDANCE_1_5_PRO.name]: readonly ['image']
592
+ [SEEDANCE_1_0_PRO.name]: readonly ['image']
593
+ [SEEDANCE_1_0_PRO_FAST.name]: readonly ['image']
594
+ }
595
+
596
+ /**
597
+ * Type-only map from video model name to the resolutions it accepts.
598
+ *
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.
601
+ */
602
+ export type BytePlusVideoModelResolutionByName = {
603
+ [DREAMINA_SEEDANCE_2_0.name]: '480p' | '720p' | '1080p' | '4k'
604
+ [DREAMINA_SEEDANCE_2_0_FAST.name]: '480p' | '720p'
605
+ [DREAMINA_SEEDANCE_2_0_MINI.name]: '480p' | '720p'
606
+ [SEEDANCE_1_5_PRO.name]: '480p' | '720p' | '1080p'
607
+ [SEEDANCE_1_0_PRO.name]: '480p' | '720p' | '1080p'
608
+ [SEEDANCE_1_0_PRO_FAST.name]: '480p' | '720p' | '1080p'
609
+ }
610
+
611
+ /**
612
+ * Type-only map from video model name to its accepted `size` strings.
613
+ */
614
+ export type BytePlusVideoModelSizeByName = {
615
+ [K in BytePlusVideoModel]: BytePlusVideoSize<
616
+ BytePlusVideoModelResolutionByName[K]
617
+ >
618
+ }
619
+
620
+ /**
621
+ * A Seedance model id: one this package knows, or any other string.
622
+ *
623
+ * 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
+ *
638
+ * 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
642
+ * release notes (https://docs.byteplus.com/en/docs/ModelArk/1159178) are the
643
+ * other watch surface.
644
+ *
645
+ * To probe an id, POST `/contents/generations/tasks` with only
646
+ * `{"model": "<id>"}`. Three outcomes, all live-verified:
647
+ * - 400 `MissingParameter` (about `content`) — live and usable.
648
+ * - 404 `ModelNotOpen` — real, but not activated on this account.
649
+ * - 404 `InvalidEndpointOrModel.NotFound` — no such model.
650
+ *
651
+ * Unknown ids trade compile-time narrowing for reach: the full size surface is
652
+ * accepted, provider options are ungated, and the adapter's model-specific
653
+ * runtime guards stand down so a new model's legitimate request reaches Ark.
654
+ * Known ids keep their probe-verified narrowing.
655
+ */
656
+ export type BytePlusVideoModelOrString = BytePlusVideoModel | (string & {})
657
+
658
+ /**
659
+ * Resolve the `size` type for a video model: the model's probe-verified
660
+ * template union when known, otherwise the full template surface plus any
661
+ * string (a future model may bring ratios or resolution tiers that do not
662
+ * exist today).
663
+ */
664
+ export type ResolveBytePlusVideoSize<TModel extends string> =
665
+ TModel extends BytePlusVideoModel
666
+ ? BytePlusVideoModelSizeByName[TModel]
667
+ : BytePlusVideoSize | (string & {})
668
+
669
+ /**
670
+ * Resolve the accepted non-text prompt modalities for a video model. Unknown
671
+ * models accept all three rather than none, so a new model's reference media
672
+ * is not a compile error.
673
+ */
674
+ export type ResolveBytePlusVideoInputModalities<TModel extends string> =
675
+ TModel extends BytePlusVideoModel
676
+ ? BytePlusVideoModelInputModalitiesByName[TModel]
677
+ : readonly ['image', 'video', 'audio']
678
+
679
+ const VIDEO_MODEL_SET: ReadonlySet<string> = new Set(BYTEPLUS_VIDEO_MODELS)
680
+
681
+ /**
682
+ * True when the id is one this package has probe-verified metadata for.
683
+ *
684
+ * The adapter uses this to decide whether its model-specific guards apply:
685
+ * see {@link BytePlusVideoModelOrString}.
686
+ */
687
+ export function isKnownBytePlusVideoModel(
688
+ model: string,
689
+ ): model is BytePlusVideoModel {
690
+ return VIDEO_MODEL_SET.has(model)
691
+ }
692
+
693
+ /**
694
+ * Per-model duration type. Seedance accepts any integer second inside the
695
+ * model's range, so this is a continuous range expressed as `number` — a
696
+ * 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`.)
699
+ */
700
+ export type BytePlusVideoModelDurationByName = {
701
+ [K in BytePlusVideoModel]: number
702
+ }
703
+
704
+ /**
705
+ * Runtime duration table backing `availableDurations()` / `snapDuration()`.
706
+ */
707
+ export const BYTEPLUS_VIDEO_DURATIONS: {
708
+ readonly [TModel in BytePlusVideoModel]: DurationOptions<
709
+ BytePlusVideoModelDurationByName[TModel]
710
+ >
711
+ } = {
712
+ 'dreamina-seedance-2-0-260128': {
713
+ kind: 'range',
714
+ min: 4,
715
+ max: 15,
716
+ step: 1,
717
+ unit: 'seconds',
718
+ },
719
+ 'dreamina-seedance-2-0-fast-260128': {
720
+ kind: 'range',
721
+ min: 4,
722
+ max: 15,
723
+ step: 1,
724
+ unit: 'seconds',
725
+ },
726
+ 'dreamina-seedance-2-0-mini-260615': {
727
+ kind: 'range',
728
+ min: 4,
729
+ max: 15,
730
+ step: 1,
731
+ unit: 'seconds',
732
+ },
733
+ 'seedance-1-5-pro-251215': {
734
+ kind: 'range',
735
+ min: 4,
736
+ max: 12,
737
+ step: 1,
738
+ unit: 'seconds',
739
+ },
740
+ 'seedance-1-0-pro-250528': {
741
+ kind: 'range',
742
+ min: 2,
743
+ max: 12,
744
+ step: 1,
745
+ unit: 'seconds',
746
+ },
747
+ 'seedance-1-0-pro-fast-251015': {
748
+ kind: 'range',
749
+ min: 2,
750
+ max: 12,
751
+ step: 1,
752
+ unit: 'seconds',
753
+ },
754
+ }
755
+
756
+ /**
757
+ * Duration hint for a model this package has no table for.
758
+ *
759
+ * 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
761
+ * 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.
764
+ */
765
+ export const BYTEPLUS_VIDEO_FALLBACK_DURATIONS: DurationOptions<number> = {
766
+ kind: 'range',
767
+ min: 2,
768
+ max: 15,
769
+ step: 1,
770
+ unit: 'seconds',
771
+ }
772
+
773
+ /**
774
+ * Look up the duration options for a Seedance video model, falling back to
775
+ * {@link BYTEPLUS_VIDEO_FALLBACK_DURATIONS} for an id this package does not
776
+ * know.
777
+ */
778
+ export function getBytePlusVideoDurationOptions(
779
+ model: BytePlusVideoModelOrString,
780
+ ): DurationOptions<number> {
781
+ return isKnownBytePlusVideoModel(model)
782
+ ? BYTEPLUS_VIDEO_DURATIONS[model]
783
+ : BYTEPLUS_VIDEO_FALLBACK_DURATIONS
784
+ }
785
+
786
+ // ============================================================================
787
+ // Image models (Seedream)
788
+ // ============================================================================
789
+
790
+ /**
791
+ * Shorthand size tokens accepted by `/images/generations`. A request uses
792
+ * either a token or an explicit `WxH` string — never both.
793
+ */
794
+ export type BytePlusImageSizeToken = '1K' | '2K' | '4K'
795
+
796
+ /**
797
+ * Accepted `size` values for Seedream models: a shorthand token or an
798
+ * explicit pixel size such as `2048x2048`.
799
+ */
800
+ export type BytePlusImageSize = BytePlusImageSizeToken | `${number}x${number}`
801
+
802
+ const DOLA_SEEDREAM_5_0_PRO = {
803
+ name: 'dola-seedream-5-0-pro-260628',
804
+ supports: {
805
+ input: ['text', 'image'],
806
+ output: ['image'],
807
+ },
808
+ } as const satisfies ModelMeta
809
+
810
+ const SEEDREAM_5_0 = {
811
+ name: 'seedream-5-0-260128',
812
+ supports: {
813
+ input: ['text', 'image'],
814
+ output: ['image'],
815
+ },
816
+ } as const satisfies ModelMeta
817
+
818
+ const SEEDREAM_5_0_LITE = {
819
+ name: 'seedream-5-0-lite-260128',
820
+ supports: {
821
+ input: ['text', 'image'],
822
+ output: ['image'],
823
+ },
824
+ } as const satisfies ModelMeta
825
+
826
+ const SEEDREAM_4_5 = {
827
+ name: 'seedream-4-5-251128',
828
+ supports: {
829
+ input: ['text', 'image'],
830
+ output: ['image'],
831
+ },
832
+ } as const satisfies ModelMeta
833
+
834
+ const SEEDREAM_4_0 = {
835
+ name: 'seedream-4-0-250828',
836
+ supports: {
837
+ input: ['text', 'image'],
838
+ output: ['image'],
839
+ },
840
+ } as const satisfies ModelMeta
841
+
842
+ /**
843
+ * All supported Seedream image model identifiers.
844
+ */
845
+ export const BYTEPLUS_IMAGE_MODELS = [
846
+ DOLA_SEEDREAM_5_0_PRO.name,
847
+ SEEDREAM_5_0.name,
848
+ SEEDREAM_5_0_LITE.name,
849
+ SEEDREAM_4_5.name,
850
+ SEEDREAM_4_0.name,
851
+ ] as const
852
+
853
+ /**
854
+ * Union of all supported Seedream image model names.
855
+ */
856
+ export type BytePlusImageModel = (typeof BYTEPLUS_IMAGE_MODELS)[number]
857
+
858
+ /**
859
+ * Type-only map from image model name to its accepted `size` strings.
860
+ */
861
+ export type BytePlusImageModelSizeByName = {
862
+ [K in BytePlusImageModel]: BytePlusImageSize
863
+ }
864
+
865
+ /**
866
+ * Maximum number of reference images accepted per editing request.
867
+ * Seedream 5.0 Pro caps at 10 references; the other editing-capable models
868
+ * accept up to 14.
869
+ *
870
+ * Docs-derived, not live-probed. The 14 for `seedream-5-0-260128` is weaker
871
+ * still — the docs never state a cap for that model, so it is inferred from
872
+ * the rest of the family.
873
+ */
874
+ export const BYTEPLUS_IMAGE_MAX_REFERENCE_IMAGES: {
875
+ readonly [K in BytePlusImageModel]: number
876
+ } = {
877
+ 'dola-seedream-5-0-pro-260628': 10,
878
+ 'seedream-5-0-260128': 14,
879
+ 'seedream-5-0-lite-260128': 14,
880
+ 'seedream-4-5-251128': 14,
881
+ 'seedream-4-0-250828': 14,
882
+ }
883
+
884
+ // ============================================================================
885
+ // Seed Speech models (voice host — separate product and API key)
886
+ // ============================================================================
887
+
888
+ const SEED_AUDIO_1_0 = {
889
+ name: 'seed-audio-1.0',
890
+ supports: {
891
+ input: ['text', 'audio'],
892
+ output: ['audio'],
893
+ },
894
+ } as const satisfies ModelMeta
895
+
896
+ // Seed Speech ASR is endpoint-addressed: `POST /api/v3/auc/bigmodel/recognize/
897
+ // flash` selects the model through the `X-Api-Resource-Id` header
898
+ // (`volc.seedasr.auc_turbo`) and takes no `model` field in the body. This
899
+ // synthetic identifier satisfies the SDK's `TranscriptionOptions.model`
900
+ // contract and gives logging and fixture matching a stable value.
901
+ const SEED_ASR = {
902
+ name: 'seed-asr',
903
+ supports: {
904
+ input: ['audio'],
905
+ output: ['text'],
906
+ },
907
+ } as const satisfies ModelMeta
908
+
909
+ /**
910
+ * All supported Seed Speech TTS model identifiers.
911
+ *
912
+ * Note: TTS runs on `voice.ap-southeast-1.bytepluses.com` with an
913
+ * `X-Api-Key` header and a *different* API key from Ark.
914
+ */
915
+ export const BYTEPLUS_TTS_MODELS = [SEED_AUDIO_1_0.name] as const
916
+
917
+ /**
918
+ * All supported Seed Speech transcription model identifiers.
919
+ */
920
+ export const BYTEPLUS_TRANSCRIPTION_MODELS = [SEED_ASR.name] as const
921
+
922
+ /**
923
+ * Union of all supported Seed Speech TTS model names.
924
+ */
925
+ export type BytePlusTTSModel = (typeof BYTEPLUS_TTS_MODELS)[number]
926
+
927
+ /**
928
+ * Union of all supported Seed Speech transcription model names.
929
+ */
930
+ export type BytePlusTranscriptionModel =
931
+ (typeof BYTEPLUS_TRANSCRIPTION_MODELS)[number]
932
+
933
+ // ============================================================================
934
+ // Type resolution helpers
935
+ // ============================================================================
936
+
937
+ /**
938
+ * Resolve provider options for a specific model. Models listed in the chat
939
+ * map get their explicit options; anything else falls back to the base chat
940
+ * options.
941
+ */
942
+ export type ResolveProviderOptions<TModel extends string> =
943
+ TModel extends keyof BytePlusChatModelProviderOptionsByName
944
+ ? BytePlusChatModelProviderOptionsByName[TModel]
945
+ : BytePlusTextProviderOptions
946
+
947
+ /**
948
+ * Resolve input modalities for a specific model. Models missing from the map
949
+ * are treated as text-only.
950
+ */
951
+ export type ResolveInputModalities<TModel extends string> =
952
+ TModel extends keyof BytePlusModelInputModalitiesByName
953
+ ? BytePlusModelInputModalitiesByName[TModel]
954
+ : readonly ['text']