@tanstack/ai 0.31.0 → 0.33.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.
- package/dist/esm/activities/chat/index.js +24 -3
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +7 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +25 -1
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +26 -2
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +7 -0
- package/dist/esm/activities/generateAudio/index.js +26 -1
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/adapter.d.ts +8 -4
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +26 -3
- package/dist/esm/activities/generateImage/index.js +38 -2
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +7 -0
- package/dist/esm/activities/generateSpeech/index.js +26 -1
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +7 -0
- package/dist/esm/activities/generateTranscription/index.js +26 -1
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/adapter.d.ts +65 -6
- package/dist/esm/activities/generateVideo/adapter.js +14 -0
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +40 -5
- package/dist/esm/activities/generateVideo/index.js +52 -2
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/snap.d.ts +14 -0
- package/dist/esm/activities/generateVideo/snap.js +54 -0
- package/dist/esm/activities/generateVideo/snap.js.map +1 -0
- package/dist/esm/activities/index.d.ts +3 -2
- package/dist/esm/activities/index.js +2 -0
- package/dist/esm/activities/index.js.map +1 -1
- package/dist/esm/activities/middleware/index.d.ts +2 -0
- package/dist/esm/activities/middleware/run.d.ts +20 -0
- package/dist/esm/activities/middleware/run.js +42 -0
- package/dist/esm/activities/middleware/run.js.map +1 -0
- package/dist/esm/activities/middleware/types.d.ts +118 -0
- package/dist/esm/client.d.ts +1 -1
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/middlewares/otel.d.ts +8 -2
- package/dist/esm/middlewares/otel.js +145 -95
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.d.ts +24 -0
- package/dist/esm/middlewares/usage-attributes.js +43 -0
- package/dist/esm/middlewares/usage-attributes.js.map +1 -0
- package/dist/esm/types.d.ts +103 -14
- package/dist/esm/utilities/errors.d.ts +13 -0
- package/dist/esm/utilities/errors.js +22 -0
- package/dist/esm/utilities/errors.js.map +1 -0
- package/dist/esm/utilities/media-prompt.d.ts +35 -0
- package/dist/esm/utilities/media-prompt.js +43 -0
- package/dist/esm/utilities/media-prompt.js.map +1 -0
- package/dist/esm/utilities/numbers.d.ts +8 -0
- package/dist/esm/utilities/numbers.js +12 -0
- package/dist/esm/utilities/numbers.js.map +1 -0
- package/package.json +2 -2
- package/skills/ai-core/media-generation/SKILL.md +173 -3
- package/src/activities/chat/index.ts +32 -4
- package/src/activities/chat/middleware/types.ts +7 -0
- package/src/activities/chat/tools/lazy-tool-manager.ts +46 -4
- package/src/activities/generateAudio/index.ts +42 -1
- package/src/activities/generateImage/adapter.ts +16 -3
- package/src/activities/generateImage/index.ts +90 -5
- package/src/activities/generateSpeech/index.ts +42 -1
- package/src/activities/generateTranscription/index.ts +42 -1
- package/src/activities/generateVideo/adapter.ts +80 -4
- package/src/activities/generateVideo/index.ts +141 -6
- package/src/activities/generateVideo/snap.ts +100 -0
- package/src/activities/index.ts +4 -0
- package/src/activities/middleware/index.ts +20 -0
- package/src/activities/middleware/run.ts +88 -0
- package/src/activities/middleware/types.ts +173 -0
- package/src/client.ts +4 -0
- package/src/index.ts +23 -0
- package/src/middlewares/otel.ts +195 -120
- package/src/middlewares/usage-attributes.ts +65 -0
- package/src/types.ts +126 -13
- package/src/utilities/errors.ts +29 -0
- package/src/utilities/media-prompt.ts +86 -0
- package/src/utilities/numbers.ts +15 -0
|
@@ -8,10 +8,24 @@
|
|
|
8
8
|
import { aiEventClient } from '@tanstack/ai-event-client'
|
|
9
9
|
import { streamGenerationResult } from '../stream-generation-result.js'
|
|
10
10
|
import { resolveDebugOption } from '../../logger/resolve'
|
|
11
|
+
import {
|
|
12
|
+
createGenerationContext,
|
|
13
|
+
runGenerationError,
|
|
14
|
+
runGenerationFinish,
|
|
15
|
+
runGenerationStart,
|
|
16
|
+
runGenerationUsage,
|
|
17
|
+
} from '../middleware'
|
|
18
|
+
import { resolveMediaPrompt } from '../../utilities/media-prompt'
|
|
11
19
|
import type { InternalLogger } from '../../logger/internal-logger'
|
|
12
20
|
import type { DebugOption } from '../../logger/types'
|
|
21
|
+
import type { GenerationMiddleware } from '../middleware'
|
|
13
22
|
import type { ImageAdapter } from './adapter'
|
|
14
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
ImageGenerationResult,
|
|
25
|
+
MediaPrompt,
|
|
26
|
+
MediaPromptFor,
|
|
27
|
+
StreamChunk,
|
|
28
|
+
} from '../../types'
|
|
15
29
|
|
|
16
30
|
// ===========================
|
|
17
31
|
// Activity Kind
|
|
@@ -55,6 +69,23 @@ export type ImageSizeForModel<TAdapter, TModel extends string> =
|
|
|
55
69
|
: string
|
|
56
70
|
: string
|
|
57
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Extract the prompt type a model accepts from an ImageAdapter via ~types.
|
|
74
|
+
* Adapters declare a per-model input-modality map; models in the map get a
|
|
75
|
+
* `prompt` narrowed to text + their supported part types (text-only models
|
|
76
|
+
* accept `string | Array<TextPart>`), so unsupported media parts fail at
|
|
77
|
+
* compile time. Adapters without a map fall back to the full MediaPrompt.
|
|
78
|
+
*/
|
|
79
|
+
export type ImagePromptForModel<TAdapter, TModel extends string> =
|
|
80
|
+
TAdapter extends ImageAdapter<any, any, any, any, infer ModsByName>
|
|
81
|
+
? string extends keyof ModsByName
|
|
82
|
+
? // No explicit map - accept the full union
|
|
83
|
+
MediaPrompt
|
|
84
|
+
: TModel extends keyof ModsByName
|
|
85
|
+
? MediaPromptFor<ModsByName[TModel][number]>
|
|
86
|
+
: MediaPrompt
|
|
87
|
+
: MediaPrompt
|
|
88
|
+
|
|
58
89
|
// ===========================
|
|
59
90
|
// Activity Options Type
|
|
60
91
|
// ===========================
|
|
@@ -72,8 +103,16 @@ export type ImageActivityOptions<
|
|
|
72
103
|
> = {
|
|
73
104
|
/** The image adapter to use (must be created with a model) */
|
|
74
105
|
adapter: TAdapter & { kind: typeof kind }
|
|
75
|
-
/**
|
|
76
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Description of the desired image(s). Either a plain string, or — for
|
|
108
|
+
* models that support image-conditioned generation — an ordered array of
|
|
109
|
+
* content parts interleaving text with image inputs (image-to-image,
|
|
110
|
+
* reference-guided, edit, multi-reference). Media parts may carry
|
|
111
|
+
* `metadata.role` (`'reference' | 'mask' | 'control' | 'character'`) to
|
|
112
|
+
* disambiguate intent. The accepted part types are narrowed per model via
|
|
113
|
+
* the adapter's input-modality map.
|
|
114
|
+
*/
|
|
115
|
+
prompt: ImagePromptForModel<TAdapter, TAdapter['model']>
|
|
77
116
|
/** Number of images to generate (default: 1) */
|
|
78
117
|
numberOfImages?: number
|
|
79
118
|
/** Image size in WIDTHxHEIGHT format (e.g., "1024x1024") */
|
|
@@ -92,6 +131,12 @@ export type ImageActivityOptions<
|
|
|
92
131
|
* control and/or a custom `Logger`.
|
|
93
132
|
*/
|
|
94
133
|
debug?: DebugOption
|
|
134
|
+
/**
|
|
135
|
+
* Observe-only middleware notified on start, usage, success, and error. Pass
|
|
136
|
+
* `otelMiddleware()` to emit OpenTelemetry spans, or implement the
|
|
137
|
+
* `GenerationMiddleware` contract for a custom backend.
|
|
138
|
+
*/
|
|
139
|
+
middleware?: Array<GenerationMiddleware>
|
|
95
140
|
} & ({} extends ImageProviderOptionsForModel<TAdapter, TAdapter['model']>
|
|
96
141
|
? {
|
|
97
142
|
/** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel<
|
|
@@ -197,19 +242,49 @@ async function runGenerateImage<
|
|
|
197
242
|
>(
|
|
198
243
|
options: ImageActivityOptions<TAdapter, boolean>,
|
|
199
244
|
): Promise<ImageGenerationResult> {
|
|
200
|
-
const {
|
|
245
|
+
const {
|
|
246
|
+
adapter,
|
|
247
|
+
stream: _stream,
|
|
248
|
+
debug: _debug,
|
|
249
|
+
middleware,
|
|
250
|
+
...rest
|
|
251
|
+
} = options
|
|
201
252
|
const model = adapter.model
|
|
202
253
|
const requestId = createId('image')
|
|
203
254
|
const startTime = Date.now()
|
|
204
255
|
const logger: InternalLogger = resolveDebugOption(options.debug)
|
|
205
256
|
|
|
257
|
+
const mwCtx = createGenerationContext({
|
|
258
|
+
requestId,
|
|
259
|
+
activity: 'image',
|
|
260
|
+
provider: adapter.name,
|
|
261
|
+
model,
|
|
262
|
+
modelOptions: rest.modelOptions,
|
|
263
|
+
createId,
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
await runGenerationStart(middleware, mwCtx)
|
|
267
|
+
|
|
268
|
+
// Devtools events carry the flattened prompt text plus media-part counts —
|
|
269
|
+
// the wire payload stays `prompt: string` regardless of the prompt shape.
|
|
270
|
+
const resolved = resolveMediaPrompt(rest.prompt)
|
|
271
|
+
|
|
206
272
|
aiEventClient.emit('image:request:started', {
|
|
207
273
|
requestId,
|
|
208
274
|
provider: adapter.name,
|
|
209
275
|
model,
|
|
210
|
-
prompt:
|
|
276
|
+
prompt: resolved.text,
|
|
211
277
|
numberOfImages: rest.numberOfImages,
|
|
212
278
|
size: rest.size,
|
|
279
|
+
...(resolved.images.length > 0 && {
|
|
280
|
+
imageInputCount: resolved.images.length,
|
|
281
|
+
}),
|
|
282
|
+
...(resolved.videos.length > 0 && {
|
|
283
|
+
videoInputCount: resolved.videos.length,
|
|
284
|
+
}),
|
|
285
|
+
...(resolved.audios.length > 0 && {
|
|
286
|
+
audioInputCount: resolved.audios.length,
|
|
287
|
+
}),
|
|
213
288
|
modelOptions: rest.modelOptions,
|
|
214
289
|
timestamp: startTime,
|
|
215
290
|
})
|
|
@@ -255,8 +330,18 @@ async function runGenerateImage<
|
|
|
255
330
|
count: result.images.length,
|
|
256
331
|
})
|
|
257
332
|
|
|
333
|
+
if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)
|
|
334
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
335
|
+
duration,
|
|
336
|
+
usage: result.usage,
|
|
337
|
+
})
|
|
338
|
+
|
|
258
339
|
return result
|
|
259
340
|
} catch (error) {
|
|
341
|
+
await runGenerationError(middleware, mwCtx, {
|
|
342
|
+
error,
|
|
343
|
+
duration: Date.now() - startTime,
|
|
344
|
+
})
|
|
260
345
|
logger.errors('generateImage activity failed', {
|
|
261
346
|
error,
|
|
262
347
|
source: 'generateImage',
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
import { aiEventClient } from '@tanstack/ai-event-client'
|
|
9
9
|
import { streamGenerationResult } from '../stream-generation-result.js'
|
|
10
10
|
import { resolveDebugOption } from '../../logger/resolve'
|
|
11
|
+
import {
|
|
12
|
+
createGenerationContext,
|
|
13
|
+
runGenerationError,
|
|
14
|
+
runGenerationFinish,
|
|
15
|
+
runGenerationStart,
|
|
16
|
+
runGenerationUsage,
|
|
17
|
+
} from '../middleware'
|
|
11
18
|
import type { InternalLogger } from '../../logger/internal-logger'
|
|
12
19
|
import type { DebugOption } from '../../logger/types'
|
|
20
|
+
import type { GenerationMiddleware } from '../middleware'
|
|
13
21
|
import type { TTSAdapter } from './adapter'
|
|
14
22
|
import type { StreamChunk, TTSResult } from '../../types'
|
|
15
23
|
|
|
@@ -73,6 +81,12 @@ export interface TTSActivityOptions<
|
|
|
73
81
|
* control and/or a custom `Logger`.
|
|
74
82
|
*/
|
|
75
83
|
debug?: DebugOption
|
|
84
|
+
/**
|
|
85
|
+
* Observe-only middleware notified on start, usage, success, and error. Pass
|
|
86
|
+
* `otelMiddleware()` to emit OpenTelemetry spans, or implement the
|
|
87
|
+
* `GenerationMiddleware` contract for a custom backend.
|
|
88
|
+
*/
|
|
89
|
+
middleware?: Array<GenerationMiddleware>
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
// ===========================
|
|
@@ -143,7 +157,13 @@ export function generateSpeech<
|
|
|
143
157
|
async function runGenerateSpeech<
|
|
144
158
|
TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,
|
|
145
159
|
>(options: TTSActivityOptions<TAdapter, boolean>): Promise<TTSResult> {
|
|
146
|
-
const {
|
|
160
|
+
const {
|
|
161
|
+
adapter,
|
|
162
|
+
stream: _stream,
|
|
163
|
+
debug: _debug,
|
|
164
|
+
middleware,
|
|
165
|
+
...rest
|
|
166
|
+
} = options
|
|
147
167
|
const model = adapter.model
|
|
148
168
|
const requestId = createId('speech')
|
|
149
169
|
const startTime = Date.now()
|
|
@@ -153,6 +173,17 @@ async function runGenerateSpeech<
|
|
|
153
173
|
(adapter as { name?: string }).name ??
|
|
154
174
|
'unknown'
|
|
155
175
|
|
|
176
|
+
const mwCtx = createGenerationContext({
|
|
177
|
+
requestId,
|
|
178
|
+
activity: 'tts',
|
|
179
|
+
provider: adapter.name,
|
|
180
|
+
model,
|
|
181
|
+
modelOptions: rest.modelOptions,
|
|
182
|
+
createId,
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
await runGenerationStart(middleware, mwCtx)
|
|
186
|
+
|
|
156
187
|
aiEventClient.emit('speech:request:started', {
|
|
157
188
|
requestId,
|
|
158
189
|
provider: adapter.name,
|
|
@@ -202,6 +233,12 @@ async function runGenerateSpeech<
|
|
|
202
233
|
contentType: result.contentType,
|
|
203
234
|
})
|
|
204
235
|
|
|
236
|
+
if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)
|
|
237
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
238
|
+
duration,
|
|
239
|
+
usage: result.usage,
|
|
240
|
+
})
|
|
241
|
+
|
|
205
242
|
return result
|
|
206
243
|
} catch (error) {
|
|
207
244
|
const duration = Date.now() - startTime
|
|
@@ -215,6 +252,10 @@ async function runGenerateSpeech<
|
|
|
215
252
|
modelOptions: rest.modelOptions as Record<string, unknown> | undefined,
|
|
216
253
|
timestamp: Date.now(),
|
|
217
254
|
})
|
|
255
|
+
await runGenerationError(middleware, mwCtx, {
|
|
256
|
+
error,
|
|
257
|
+
duration,
|
|
258
|
+
})
|
|
218
259
|
logger.errors('generateSpeech activity failed', {
|
|
219
260
|
error,
|
|
220
261
|
source: 'generateSpeech',
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
import { aiEventClient } from '@tanstack/ai-event-client'
|
|
9
9
|
import { streamGenerationResult } from '../stream-generation-result.js'
|
|
10
10
|
import { resolveDebugOption } from '../../logger/resolve'
|
|
11
|
+
import {
|
|
12
|
+
createGenerationContext,
|
|
13
|
+
runGenerationError,
|
|
14
|
+
runGenerationFinish,
|
|
15
|
+
runGenerationStart,
|
|
16
|
+
runGenerationUsage,
|
|
17
|
+
} from '../middleware'
|
|
11
18
|
import type { InternalLogger } from '../../logger/internal-logger'
|
|
12
19
|
import type { DebugOption } from '../../logger/types'
|
|
20
|
+
import type { GenerationMiddleware } from '../middleware'
|
|
13
21
|
import type { TranscriptionAdapter } from './adapter'
|
|
14
22
|
import type { StreamChunk, TranscriptionResult } from '../../types'
|
|
15
23
|
|
|
@@ -76,6 +84,12 @@ export interface TranscriptionActivityOptions<
|
|
|
76
84
|
* control and/or a custom `Logger`.
|
|
77
85
|
*/
|
|
78
86
|
debug?: DebugOption
|
|
87
|
+
/**
|
|
88
|
+
* Observe-only middleware notified on start, usage, success, and error. Pass
|
|
89
|
+
* `otelMiddleware()` to emit OpenTelemetry spans, or implement the
|
|
90
|
+
* `GenerationMiddleware` contract for a custom backend.
|
|
91
|
+
*/
|
|
92
|
+
middleware?: Array<GenerationMiddleware>
|
|
79
93
|
}
|
|
80
94
|
|
|
81
95
|
// ===========================
|
|
@@ -174,7 +188,13 @@ async function runGenerateTranscription<
|
|
|
174
188
|
>(
|
|
175
189
|
options: TranscriptionActivityOptions<TAdapter, boolean>,
|
|
176
190
|
): Promise<TranscriptionResult> {
|
|
177
|
-
const {
|
|
191
|
+
const {
|
|
192
|
+
adapter,
|
|
193
|
+
stream: _stream,
|
|
194
|
+
debug: _debug,
|
|
195
|
+
middleware,
|
|
196
|
+
...rest
|
|
197
|
+
} = options
|
|
178
198
|
const model = adapter.model
|
|
179
199
|
const requestId = createId('transcription')
|
|
180
200
|
const startTime = Date.now()
|
|
@@ -184,6 +204,17 @@ async function runGenerateTranscription<
|
|
|
184
204
|
(adapter as { name?: string }).name ??
|
|
185
205
|
'unknown'
|
|
186
206
|
|
|
207
|
+
const mwCtx = createGenerationContext({
|
|
208
|
+
requestId,
|
|
209
|
+
activity: 'transcription',
|
|
210
|
+
provider: adapter.name,
|
|
211
|
+
model,
|
|
212
|
+
modelOptions: rest.modelOptions,
|
|
213
|
+
createId,
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
await runGenerationStart(middleware, mwCtx)
|
|
217
|
+
|
|
187
218
|
aiEventClient.emit('transcription:request:started', {
|
|
188
219
|
requestId,
|
|
189
220
|
provider: adapter.name,
|
|
@@ -220,6 +251,12 @@ async function runGenerateTranscription<
|
|
|
220
251
|
{ hasText: !!result.text },
|
|
221
252
|
)
|
|
222
253
|
|
|
254
|
+
if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)
|
|
255
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
256
|
+
duration,
|
|
257
|
+
usage: result.usage,
|
|
258
|
+
})
|
|
259
|
+
|
|
223
260
|
return result
|
|
224
261
|
} catch (error) {
|
|
225
262
|
const duration = Date.now() - startTime
|
|
@@ -233,6 +270,10 @@ async function runGenerateTranscription<
|
|
|
233
270
|
modelOptions: rest.modelOptions as Record<string, unknown> | undefined,
|
|
234
271
|
timestamp: Date.now(),
|
|
235
272
|
})
|
|
273
|
+
await runGenerationError(middleware, mwCtx, {
|
|
274
|
+
error,
|
|
275
|
+
duration,
|
|
276
|
+
})
|
|
236
277
|
logger.errors('generateTranscription activity failed', {
|
|
237
278
|
error,
|
|
238
279
|
source: 'generateTranscription',
|
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
ModelInputModalitiesByName,
|
|
2
3
|
VideoGenerationOptions,
|
|
3
4
|
VideoJobResult,
|
|
4
5
|
VideoStatusResult,
|
|
5
6
|
VideoUrlResult,
|
|
6
7
|
} from '../../types'
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Structured description of the durations a video model accepts.
|
|
11
|
+
*
|
|
12
|
+
* Tagged union so the same shape can express discrete enums (OpenAI Sora,
|
|
13
|
+
* Veo), continuous ranges, mixed shapes, and models with no duration field.
|
|
14
|
+
* Consumed by `VideoAdapter.availableDurations()`.
|
|
15
|
+
*
|
|
16
|
+
* @experimental Video generation is an experimental feature and may change.
|
|
17
|
+
*/
|
|
18
|
+
export type DurationOptions<T extends string | number | undefined> =
|
|
19
|
+
| { kind: 'discrete'; values: ReadonlyArray<NonNullable<T>> }
|
|
20
|
+
| { kind: 'range'; min: number; max: number; step?: number; unit: 'seconds' }
|
|
21
|
+
| {
|
|
22
|
+
kind: 'mixed'
|
|
23
|
+
values: ReadonlyArray<NonNullable<T>>
|
|
24
|
+
range?: { min: number; max: number; step?: number }
|
|
25
|
+
}
|
|
26
|
+
| { kind: 'none' }
|
|
27
|
+
|
|
8
28
|
/**
|
|
9
29
|
* Configuration for video adapter instances
|
|
10
30
|
*
|
|
@@ -31,6 +51,11 @@ export interface VideoAdapterConfig {
|
|
|
31
51
|
* - TProviderOptions: Provider-specific options (already resolved)
|
|
32
52
|
* - TModelProviderOptionsByName: Map from model name to its specific provider options
|
|
33
53
|
* - TModelSizeByName: Map from model name to its supported sizes
|
|
54
|
+
* - TModelInputModalitiesByName: Map from model name to the non-text prompt
|
|
55
|
+
* modalities it accepts (constrains the `prompt` part types at compile time)
|
|
56
|
+
* - TModelDurationByName: Map from model name to its supported duration
|
|
57
|
+
* union. Defaults to `Record<string, number>` so adapters that haven't
|
|
58
|
+
* declared a map keep today's `duration?: number` typing.
|
|
34
59
|
*/
|
|
35
60
|
export interface VideoAdapter<
|
|
36
61
|
TModel extends string = string,
|
|
@@ -40,6 +65,10 @@ export interface VideoAdapter<
|
|
|
40
65
|
string,
|
|
41
66
|
string
|
|
42
67
|
>,
|
|
68
|
+
TModelInputModalitiesByName extends ModelInputModalitiesByName =
|
|
69
|
+
ModelInputModalitiesByName,
|
|
70
|
+
TModelDurationByName extends Record<string, string | number | undefined> =
|
|
71
|
+
Record<string, number>,
|
|
43
72
|
> {
|
|
44
73
|
/** Discriminator for adapter kind - used to determine API shape */
|
|
45
74
|
readonly kind: 'video'
|
|
@@ -55,6 +84,8 @@ export interface VideoAdapter<
|
|
|
55
84
|
providerOptions: TProviderOptions
|
|
56
85
|
modelProviderOptionsByName: TModelProviderOptionsByName
|
|
57
86
|
modelSizeByName: TModelSizeByName
|
|
87
|
+
modelInputModalitiesByName: TModelInputModalitiesByName
|
|
88
|
+
modelDurationByName: TModelDurationByName
|
|
58
89
|
}
|
|
59
90
|
|
|
60
91
|
/**
|
|
@@ -62,7 +93,11 @@ export interface VideoAdapter<
|
|
|
62
93
|
* Returns a job ID that can be used to poll for status and retrieve the video.
|
|
63
94
|
*/
|
|
64
95
|
createVideoJob: (
|
|
65
|
-
options: VideoGenerationOptions<
|
|
96
|
+
options: VideoGenerationOptions<
|
|
97
|
+
TProviderOptions,
|
|
98
|
+
TModelSizeByName[TModel],
|
|
99
|
+
TModelDurationByName[TModel]
|
|
100
|
+
>,
|
|
66
101
|
) => Promise<VideoJobResult>
|
|
67
102
|
|
|
68
103
|
/**
|
|
@@ -75,13 +110,26 @@ export interface VideoAdapter<
|
|
|
75
110
|
* Should only be called after status is 'completed'.
|
|
76
111
|
*/
|
|
77
112
|
getVideoUrl: (jobId: string) => Promise<VideoUrlResult>
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Describe the durations this adapter's model accepts. Returns a tagged
|
|
116
|
+
* union so consumers can render UI / coerce input without provider-specific
|
|
117
|
+
* knowledge.
|
|
118
|
+
*/
|
|
119
|
+
availableDurations: () => DurationOptions<TModelDurationByName[TModel]>
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Coerce a raw seconds value to the closest valid duration for this model.
|
|
123
|
+
* Returns `undefined` for models with no duration field.
|
|
124
|
+
*/
|
|
125
|
+
snapDuration: (seconds: number) => TModelDurationByName[TModel] | undefined
|
|
78
126
|
}
|
|
79
127
|
|
|
80
128
|
/**
|
|
81
129
|
* A VideoAdapter with any/unknown type parameters.
|
|
82
130
|
* Useful as a constraint in generic functions and interfaces.
|
|
83
131
|
*/
|
|
84
|
-
export type AnyVideoAdapter = VideoAdapter<any, any, any, any>
|
|
132
|
+
export type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>
|
|
85
133
|
|
|
86
134
|
/**
|
|
87
135
|
* Abstract base class for video generation adapters.
|
|
@@ -99,11 +147,17 @@ export abstract class BaseVideoAdapter<
|
|
|
99
147
|
string,
|
|
100
148
|
string
|
|
101
149
|
>,
|
|
150
|
+
TModelInputModalitiesByName extends ModelInputModalitiesByName =
|
|
151
|
+
ModelInputModalitiesByName,
|
|
152
|
+
TModelDurationByName extends Record<string, string | number | undefined> =
|
|
153
|
+
Record<string, number>,
|
|
102
154
|
> implements VideoAdapter<
|
|
103
155
|
TModel,
|
|
104
156
|
TProviderOptions,
|
|
105
157
|
TModelProviderOptionsByName,
|
|
106
|
-
TModelSizeByName
|
|
158
|
+
TModelSizeByName,
|
|
159
|
+
TModelInputModalitiesByName,
|
|
160
|
+
TModelDurationByName
|
|
107
161
|
> {
|
|
108
162
|
readonly kind = 'video' as const
|
|
109
163
|
abstract readonly name: string
|
|
@@ -114,6 +168,8 @@ export abstract class BaseVideoAdapter<
|
|
|
114
168
|
providerOptions: TProviderOptions
|
|
115
169
|
modelProviderOptionsByName: TModelProviderOptionsByName
|
|
116
170
|
modelSizeByName: TModelSizeByName
|
|
171
|
+
modelInputModalitiesByName: TModelInputModalitiesByName
|
|
172
|
+
modelDurationByName: TModelDurationByName
|
|
117
173
|
}
|
|
118
174
|
|
|
119
175
|
protected config: VideoAdapterConfig
|
|
@@ -124,13 +180,33 @@ export abstract class BaseVideoAdapter<
|
|
|
124
180
|
}
|
|
125
181
|
|
|
126
182
|
abstract createVideoJob(
|
|
127
|
-
options: VideoGenerationOptions<
|
|
183
|
+
options: VideoGenerationOptions<
|
|
184
|
+
TProviderOptions,
|
|
185
|
+
TModelSizeByName[TModel],
|
|
186
|
+
TModelDurationByName[TModel]
|
|
187
|
+
>,
|
|
128
188
|
): Promise<VideoJobResult>
|
|
129
189
|
|
|
130
190
|
abstract getVideoStatus(jobId: string): Promise<VideoStatusResult>
|
|
131
191
|
|
|
132
192
|
abstract getVideoUrl(jobId: string): Promise<VideoUrlResult>
|
|
133
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Default implementation returns `{ kind: 'none' }`. Adapters that have
|
|
196
|
+
* declared their per-model duration map should override this.
|
|
197
|
+
*/
|
|
198
|
+
availableDurations(): DurationOptions<TModelDurationByName[TModel]> {
|
|
199
|
+
return { kind: 'none' }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Default implementation returns `undefined`. Adapters that have declared
|
|
204
|
+
* their per-model duration map should override.
|
|
205
|
+
*/
|
|
206
|
+
snapDuration(_seconds: number): TModelDurationByName[TModel] | undefined {
|
|
207
|
+
return undefined
|
|
208
|
+
}
|
|
209
|
+
|
|
134
210
|
protected generateId(): string {
|
|
135
211
|
return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
136
212
|
}
|