@ai-sdk/gateway 4.0.43 → 4.0.44
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/CHANGELOG.md +15 -0
- package/dist/index.js +211 -50
- package/dist/index.js.map +1 -1
- package/docs/00-ai-gateway.mdx +23 -0
- package/package.json +1 -1
- package/src/gateway-video-model.ts +245 -41
package/docs/00-ai-gateway.mdx
CHANGED
|
@@ -444,6 +444,29 @@ if (generationId) {
|
|
|
444
444
|
}
|
|
445
445
|
```
|
|
446
446
|
|
|
447
|
+
You can also capture the generation ID for every completed model call with
|
|
448
|
+
`onLanguageModelCallEnd`. The callback runs before client-side tools execute,
|
|
449
|
+
so the metadata remains available even if the operation is later aborted while
|
|
450
|
+
a tool is running:
|
|
451
|
+
|
|
452
|
+
```ts
|
|
453
|
+
import { gateway, generateText } from 'ai';
|
|
454
|
+
|
|
455
|
+
await generateText({
|
|
456
|
+
model: gateway('anthropic/claude-sonnet-4'),
|
|
457
|
+
prompt: 'Explain quantum entanglement briefly',
|
|
458
|
+
onLanguageModelCallEnd({ providerMetadata }) {
|
|
459
|
+
const generationId = providerMetadata?.gateway?.generationId as
|
|
460
|
+
| string
|
|
461
|
+
| undefined;
|
|
462
|
+
|
|
463
|
+
if (generationId) {
|
|
464
|
+
console.log(`Completed Gateway generation: ${generationId}`);
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
447
470
|
The `getGenerationInfo()` method accepts:
|
|
448
471
|
|
|
449
472
|
- **id** _string_ - The generation ID to look up (format: `gen_<ulid>`, required)
|
package/package.json
CHANGED
|
@@ -3,7 +3,10 @@ import {
|
|
|
3
3
|
type Experimental_VideoModelV4 as VideoModelV4,
|
|
4
4
|
type Experimental_VideoModelV4CallOptions as VideoModelV4CallOptions,
|
|
5
5
|
type Experimental_VideoModelV4File as VideoModelV4File,
|
|
6
|
+
type Experimental_VideoModelV4OperationStartResult as VideoModelV4OperationStartResult,
|
|
7
|
+
type Experimental_VideoModelV4OperationStatusResult as VideoModelV4OperationStatusResult,
|
|
6
8
|
type Experimental_VideoModelV4VideoData as VideoModelV4VideoData,
|
|
9
|
+
type JSONValue,
|
|
7
10
|
type SharedV4ProviderMetadata,
|
|
8
11
|
type SharedV4Warning,
|
|
9
12
|
} from '@ai-sdk/provider';
|
|
@@ -11,6 +14,7 @@ import {
|
|
|
11
14
|
combineHeaders,
|
|
12
15
|
convertUint8ArrayToBase64,
|
|
13
16
|
createJsonErrorResponseHandler,
|
|
17
|
+
createJsonResponseHandler,
|
|
14
18
|
parseJsonEventStream,
|
|
15
19
|
postJsonToApi,
|
|
16
20
|
resolve,
|
|
@@ -38,22 +42,7 @@ export class GatewayVideoModel implements VideoModelV4 {
|
|
|
38
42
|
return this.config.provider;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
async doGenerate({
|
|
42
|
-
prompt,
|
|
43
|
-
n,
|
|
44
|
-
aspectRatio,
|
|
45
|
-
resolution,
|
|
46
|
-
duration,
|
|
47
|
-
fps,
|
|
48
|
-
seed,
|
|
49
|
-
generateAudio,
|
|
50
|
-
image,
|
|
51
|
-
frameImages,
|
|
52
|
-
inputReferences,
|
|
53
|
-
providerOptions,
|
|
54
|
-
headers,
|
|
55
|
-
abortSignal,
|
|
56
|
-
}: VideoModelV4CallOptions): Promise<{
|
|
45
|
+
async doGenerate(options: VideoModelV4CallOptions): Promise<{
|
|
57
46
|
videos: Array<VideoModelV4VideoData>;
|
|
58
47
|
warnings: Array<SharedV4Warning>;
|
|
59
48
|
providerMetadata?: SharedV4ProviderMetadata;
|
|
@@ -63,6 +52,7 @@ export class GatewayVideoModel implements VideoModelV4 {
|
|
|
63
52
|
headers: Record<string, string> | undefined;
|
|
64
53
|
};
|
|
65
54
|
}> {
|
|
55
|
+
const { headers, abortSignal } = options;
|
|
66
56
|
const resolvedHeaders = this.config.headers
|
|
67
57
|
? await resolve(this.config.headers)
|
|
68
58
|
: undefined;
|
|
@@ -76,29 +66,7 @@ export class GatewayVideoModel implements VideoModelV4 {
|
|
|
76
66
|
await resolve(this.config.o11yHeaders),
|
|
77
67
|
{ accept: 'text/event-stream' },
|
|
78
68
|
),
|
|
79
|
-
body:
|
|
80
|
-
prompt,
|
|
81
|
-
n,
|
|
82
|
-
...(aspectRatio && { aspectRatio }),
|
|
83
|
-
...(resolution && { resolution }),
|
|
84
|
-
...(duration && { duration }),
|
|
85
|
-
...(fps && { fps }),
|
|
86
|
-
...(seed && { seed }),
|
|
87
|
-
...(generateAudio !== undefined && { generateAudio }),
|
|
88
|
-
...(providerOptions && { providerOptions }),
|
|
89
|
-
...(image && { image: maybeEncodeVideoFile(image) }),
|
|
90
|
-
...(frameImages && {
|
|
91
|
-
frameImages: frameImages.map(frame => ({
|
|
92
|
-
...frame,
|
|
93
|
-
image: maybeEncodeVideoFile(frame.image),
|
|
94
|
-
})),
|
|
95
|
-
}),
|
|
96
|
-
...(inputReferences && {
|
|
97
|
-
inputReferences: inputReferences.map(reference =>
|
|
98
|
-
maybeEncodeVideoFile(reference),
|
|
99
|
-
),
|
|
100
|
-
}),
|
|
101
|
-
},
|
|
69
|
+
body: this.buildRequestBody(options),
|
|
102
70
|
successfulResponseHandler: async ({
|
|
103
71
|
response,
|
|
104
72
|
url,
|
|
@@ -186,8 +154,8 @@ export class GatewayVideoModel implements VideoModelV4 {
|
|
|
186
154
|
return {
|
|
187
155
|
videos: responseBody.videos,
|
|
188
156
|
warnings: responseBody.warnings ?? [],
|
|
189
|
-
providerMetadata:
|
|
190
|
-
|
|
157
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
158
|
+
undefined) as SharedV4ProviderMetadata,
|
|
191
159
|
response: {
|
|
192
160
|
timestamp: new Date(),
|
|
193
161
|
modelId: this.modelId,
|
|
@@ -202,10 +170,209 @@ export class GatewayVideoModel implements VideoModelV4 {
|
|
|
202
170
|
}
|
|
203
171
|
}
|
|
204
172
|
|
|
173
|
+
// `handleWebhookOption` is intentionally NOT implemented. The Gateway's
|
|
174
|
+
// async video jobs are polling-first: it does not expose a provider->SDK
|
|
175
|
+
// webhook completion channel. If this method were present, `generateVideo`
|
|
176
|
+
// would forward a webhook URL and await a notification that never arrives.
|
|
177
|
+
// `doStart` still forwards the spec's `webhookUrl` — as the Gateway's
|
|
178
|
+
// `callbackUrl` wire field (its completion-webhook contract; unknown body
|
|
179
|
+
// keys are stripped server-side). Enabling webhooks later requires adding
|
|
180
|
+
// `handleWebhookOption` here plus handling the Gateway's HMAC-signed
|
|
181
|
+
// delivery format; the wire field is already the right one.
|
|
182
|
+
|
|
183
|
+
async doStart(
|
|
184
|
+
options: VideoModelV4CallOptions & {
|
|
185
|
+
webhookUrl?: string;
|
|
186
|
+
},
|
|
187
|
+
): Promise<VideoModelV4OperationStartResult> {
|
|
188
|
+
const { headers, abortSignal, webhookUrl } = options;
|
|
189
|
+
const resolvedHeaders = this.config.headers
|
|
190
|
+
? await resolve(this.config.headers)
|
|
191
|
+
: undefined;
|
|
192
|
+
try {
|
|
193
|
+
const { responseHeaders, value: responseBody } = await postJsonToApi({
|
|
194
|
+
url: this.getStartUrl(),
|
|
195
|
+
headers: combineHeaders(
|
|
196
|
+
resolvedHeaders,
|
|
197
|
+
headers ?? {},
|
|
198
|
+
this.getModelConfigHeaders(),
|
|
199
|
+
await resolve(this.config.o11yHeaders),
|
|
200
|
+
),
|
|
201
|
+
body: {
|
|
202
|
+
...this.buildRequestBody(options),
|
|
203
|
+
// The spec option is `webhookUrl`; the Gateway's wire contract for a
|
|
204
|
+
// completion webhook is `callbackUrl`.
|
|
205
|
+
...(webhookUrl && { callbackUrl: webhookUrl }),
|
|
206
|
+
},
|
|
207
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
208
|
+
gatewayVideoStartResponseSchema,
|
|
209
|
+
),
|
|
210
|
+
failedResponseHandler: createJsonErrorResponseHandler({
|
|
211
|
+
errorSchema: z.any(),
|
|
212
|
+
errorToMessage: data => data,
|
|
213
|
+
}),
|
|
214
|
+
...(abortSignal && { abortSignal }),
|
|
215
|
+
fetch: this.config.fetch,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
operation: responseBody.operation as JSONValue,
|
|
220
|
+
warnings: responseBody.warnings ?? [],
|
|
221
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
222
|
+
undefined) as SharedV4ProviderMetadata,
|
|
223
|
+
response: {
|
|
224
|
+
timestamp: new Date(),
|
|
225
|
+
modelId: this.modelId,
|
|
226
|
+
headers: responseHeaders,
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
throw await asGatewayError(
|
|
231
|
+
error,
|
|
232
|
+
await parseAuthMethod(resolvedHeaders ?? {}),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async doStatus({
|
|
238
|
+
operation,
|
|
239
|
+
abortSignal,
|
|
240
|
+
headers,
|
|
241
|
+
}: {
|
|
242
|
+
operation: JSONValue;
|
|
243
|
+
abortSignal?: AbortSignal;
|
|
244
|
+
headers?: Record<string, string | undefined>;
|
|
245
|
+
}): Promise<VideoModelV4OperationStatusResult> {
|
|
246
|
+
const resolvedHeaders = this.config.headers
|
|
247
|
+
? await resolve(this.config.headers)
|
|
248
|
+
: undefined;
|
|
249
|
+
try {
|
|
250
|
+
const { responseHeaders, value: responseBody } = await postJsonToApi({
|
|
251
|
+
url: this.getStatusUrl(),
|
|
252
|
+
headers: combineHeaders(
|
|
253
|
+
resolvedHeaders,
|
|
254
|
+
headers ?? {},
|
|
255
|
+
this.getModelConfigHeaders(),
|
|
256
|
+
await resolve(this.config.o11yHeaders),
|
|
257
|
+
),
|
|
258
|
+
body: { operation },
|
|
259
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
260
|
+
gatewayVideoStatusResponseSchema,
|
|
261
|
+
),
|
|
262
|
+
failedResponseHandler: createJsonErrorResponseHandler({
|
|
263
|
+
errorSchema: z.any(),
|
|
264
|
+
errorToMessage: data => data,
|
|
265
|
+
}),
|
|
266
|
+
...(abortSignal && { abortSignal }),
|
|
267
|
+
fetch: this.config.fetch,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const response = {
|
|
271
|
+
timestamp: new Date(),
|
|
272
|
+
modelId: this.modelId,
|
|
273
|
+
headers: responseHeaders,
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
if (responseBody.status === 'completed') {
|
|
277
|
+
return {
|
|
278
|
+
status: 'completed',
|
|
279
|
+
videos: responseBody.videos,
|
|
280
|
+
warnings: responseBody.warnings ?? [],
|
|
281
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
282
|
+
undefined) as SharedV4ProviderMetadata,
|
|
283
|
+
response,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (responseBody.status === 'error') {
|
|
288
|
+
return {
|
|
289
|
+
status: 'error',
|
|
290
|
+
error: responseBody.error,
|
|
291
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
292
|
+
undefined) as SharedV4ProviderMetadata,
|
|
293
|
+
response,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// The Gateway reports cooperative cancellation as its own terminal
|
|
298
|
+
// status; the v4 operation union has no cancelled state, so surface it
|
|
299
|
+
// as a terminal error rather than polling forever.
|
|
300
|
+
if (responseBody.status === 'cancelled') {
|
|
301
|
+
return {
|
|
302
|
+
status: 'error',
|
|
303
|
+
error: 'Video generation was cancelled.',
|
|
304
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
305
|
+
undefined) as SharedV4ProviderMetadata,
|
|
306
|
+
response,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
status: 'pending',
|
|
312
|
+
warnings: responseBody.warnings ?? [],
|
|
313
|
+
providerMetadata: (responseBody.providerMetadata ??
|
|
314
|
+
undefined) as SharedV4ProviderMetadata,
|
|
315
|
+
response,
|
|
316
|
+
};
|
|
317
|
+
} catch (error) {
|
|
318
|
+
throw await asGatewayError(
|
|
319
|
+
error,
|
|
320
|
+
await parseAuthMethod(resolvedHeaders ?? {}),
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private buildRequestBody({
|
|
326
|
+
prompt,
|
|
327
|
+
n,
|
|
328
|
+
aspectRatio,
|
|
329
|
+
resolution,
|
|
330
|
+
duration,
|
|
331
|
+
fps,
|
|
332
|
+
seed,
|
|
333
|
+
generateAudio,
|
|
334
|
+
image,
|
|
335
|
+
frameImages,
|
|
336
|
+
inputReferences,
|
|
337
|
+
providerOptions,
|
|
338
|
+
}: VideoModelV4CallOptions) {
|
|
339
|
+
return {
|
|
340
|
+
prompt,
|
|
341
|
+
n,
|
|
342
|
+
...(aspectRatio && { aspectRatio }),
|
|
343
|
+
...(resolution && { resolution }),
|
|
344
|
+
...(duration && { duration }),
|
|
345
|
+
...(fps && { fps }),
|
|
346
|
+
...(seed && { seed }),
|
|
347
|
+
...(generateAudio !== undefined && { generateAudio }),
|
|
348
|
+
...(providerOptions && { providerOptions }),
|
|
349
|
+
...(image && { image: maybeEncodeVideoFile(image) }),
|
|
350
|
+
...(frameImages && {
|
|
351
|
+
frameImages: frameImages.map(frame => ({
|
|
352
|
+
...frame,
|
|
353
|
+
image: maybeEncodeVideoFile(frame.image),
|
|
354
|
+
})),
|
|
355
|
+
}),
|
|
356
|
+
...(inputReferences && {
|
|
357
|
+
inputReferences: inputReferences.map(reference =>
|
|
358
|
+
maybeEncodeVideoFile(reference),
|
|
359
|
+
),
|
|
360
|
+
}),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
205
364
|
private getUrl() {
|
|
206
365
|
return `${this.config.baseURL}/video-model`;
|
|
207
366
|
}
|
|
208
367
|
|
|
368
|
+
private getStartUrl() {
|
|
369
|
+
return `${this.config.baseURL}/video-model/start`;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private getStatusUrl() {
|
|
373
|
+
return `${this.config.baseURL}/video-model/status`;
|
|
374
|
+
}
|
|
375
|
+
|
|
209
376
|
private getModelConfigHeaders() {
|
|
210
377
|
return {
|
|
211
378
|
'ai-video-model-specification-version': '4',
|
|
@@ -282,3 +449,40 @@ const gatewayVideoEventSchema = z.discriminatedUnion('type', [
|
|
|
282
449
|
param: z.unknown().nullable(),
|
|
283
450
|
}),
|
|
284
451
|
]);
|
|
452
|
+
|
|
453
|
+
const gatewayVideoStartResponseSchema = z.object({
|
|
454
|
+
operation: z.unknown(),
|
|
455
|
+
warnings: z.array(gatewayVideoWarningSchema).nullish(),
|
|
456
|
+
providerMetadata: z.record(z.string(), providerMetadataEntrySchema).nullish(),
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const gatewayVideoStatusResponseSchema = z.discriminatedUnion('status', [
|
|
460
|
+
z.object({
|
|
461
|
+
status: z.literal('pending'),
|
|
462
|
+
warnings: z.array(gatewayVideoWarningSchema).nullish(),
|
|
463
|
+
providerMetadata: z
|
|
464
|
+
.record(z.string(), providerMetadataEntrySchema)
|
|
465
|
+
.nullish(),
|
|
466
|
+
}),
|
|
467
|
+
z.object({
|
|
468
|
+
status: z.literal('completed'),
|
|
469
|
+
videos: z.array(gatewayVideoDataSchema),
|
|
470
|
+
warnings: z.array(gatewayVideoWarningSchema).nullish(),
|
|
471
|
+
providerMetadata: z
|
|
472
|
+
.record(z.string(), providerMetadataEntrySchema)
|
|
473
|
+
.nullish(),
|
|
474
|
+
}),
|
|
475
|
+
z.object({
|
|
476
|
+
status: z.literal('error'),
|
|
477
|
+
error: z.string(),
|
|
478
|
+
providerMetadata: z
|
|
479
|
+
.record(z.string(), providerMetadataEntrySchema)
|
|
480
|
+
.nullish(),
|
|
481
|
+
}),
|
|
482
|
+
z.object({
|
|
483
|
+
status: z.literal('cancelled'),
|
|
484
|
+
providerMetadata: z
|
|
485
|
+
.record(z.string(), providerMetadataEntrySchema)
|
|
486
|
+
.nullish(),
|
|
487
|
+
}),
|
|
488
|
+
]);
|