@ai-sdk/gateway 4.0.0-beta.5 → 4.0.0-beta.50

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.
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV3 } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4 } from '@ai-sdk/provider';
2
2
 
3
3
  export interface GatewayLanguageModelEntry {
4
4
  /**
@@ -53,6 +53,6 @@ export interface GatewayLanguageModelEntry {
53
53
  }
54
54
 
55
55
  export type GatewayLanguageModelSpecification = Pick<
56
- LanguageModelV3,
56
+ LanguageModelV4,
57
57
  'specificationVersion' | 'provider' | 'modelId'
58
58
  >;
@@ -2,7 +2,7 @@ import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
2
2
  import { z } from 'zod/v4';
3
3
 
4
4
  // https://vercel.com/docs/ai-gateway/provider-options
5
- const gatewayLanguageModelOptions = lazySchema(() =>
5
+ const gatewayProviderOptions = lazySchema(() =>
6
6
  zodSchema(
7
7
  z.object({
8
8
  /**
@@ -17,6 +17,14 @@ const gatewayLanguageModelOptions = lazySchema(() =>
17
17
  * Example: `['bedrock', 'anthropic']` will try Amazon Bedrock first, then Anthropic as fallback.
18
18
  */
19
19
  order: z.array(z.string()).optional(),
20
+ /**
21
+ * Sort providers by a performance or cost metric before routing.
22
+ *
23
+ * - `'cost'`: lowest cost first
24
+ * - `'ttft'`: lowest time-to-first-token first
25
+ * - `'tps'`: highest tokens-per-second first
26
+ */
27
+ sort: z.enum(['cost', 'ttft', 'tps']).optional(),
20
28
  /**
21
29
  * The unique identifier for the end user on behalf of whom the request was made.
22
30
  *
@@ -53,12 +61,33 @@ const gatewayLanguageModelOptions = lazySchema(() =>
53
61
  .record(z.string(), z.array(z.record(z.string(), z.unknown())))
54
62
  .optional(),
55
63
  /**
56
- * Whether to filter by only providers that state they have zero data
57
- * retention with Vercel AI Gateway. When enabled, only providers that
58
- * have agreements with Vercel AI Gateway for zero data retention will be
59
- * used.
64
+ * Whether to filter by only providers that have zero data retention
65
+ * agreements with Vercel for AI Gateway. When using BYOK credentials,
66
+ * this filter is not applied. If BYOK credentials fail and the request
67
+ * falls back to system credentials, only providers with zero data
68
+ * retention agreements will be used.
60
69
  */
61
70
  zeroDataRetention: z.boolean().optional(),
71
+ /**
72
+ * Whether to filter by only providers that do not train on prompt data.
73
+ * When using BYOK credentials, this filter is not applied. If BYOK
74
+ * credentials fail and the request falls back to system credentials,
75
+ * only providers that have agreements with Vercel for AI Gateway to not
76
+ * use prompts for model training will be used.
77
+ */
78
+ disallowPromptTraining: z.boolean().optional(),
79
+ /**
80
+ * Whether to filter by only providers that are HIPAA compliant with
81
+ * Vercel AI Gateway. When enabled, only providers that have agreements
82
+ * with Vercel AI Gateway for HIPAA compliance will be used.
83
+ */
84
+ hipaaCompliant: z.boolean().optional(),
85
+ /**
86
+ * The unique identifier for the entity against which quota is tracked.
87
+ *
88
+ * Used for quota management and enforcement purposes.
89
+ */
90
+ quotaEntityId: z.string().optional(),
62
91
  /**
63
92
  * Per-provider timeouts for BYOK credentials in milliseconds.
64
93
  * Controls how long to wait for a provider to start responding
@@ -75,6 +104,4 @@ const gatewayLanguageModelOptions = lazySchema(() =>
75
104
  ),
76
105
  );
77
106
 
78
- export type GatewayLanguageModelOptions = InferSchema<
79
- typeof gatewayLanguageModelOptions
80
- >;
107
+ export type GatewayProviderOptions = InferSchema<typeof gatewayProviderOptions>;
@@ -13,38 +13,51 @@ import {
13
13
  type GatewayFetchMetadataResponse,
14
14
  type GatewayCreditsResponse,
15
15
  } from './gateway-fetch-metadata';
16
+ import {
17
+ GatewaySpendReport,
18
+ type GatewaySpendReportParams,
19
+ type GatewaySpendReportResponse,
20
+ } from './gateway-spend-report';
21
+ import {
22
+ GatewayGenerationInfoFetcher,
23
+ type GatewayGenerationInfoParams,
24
+ type GatewayGenerationInfo,
25
+ } from './gateway-generation-info';
16
26
  import { GatewayLanguageModel } from './gateway-language-model';
17
27
  import { GatewayEmbeddingModel } from './gateway-embedding-model';
18
28
  import { GatewayImageModel } from './gateway-image-model';
19
29
  import { GatewayVideoModel } from './gateway-video-model';
30
+ import { GatewayRerankingModel } from './gateway-reranking-model';
20
31
  import type { GatewayEmbeddingModelId } from './gateway-embedding-model-settings';
21
32
  import type { GatewayImageModelId } from './gateway-image-model-settings';
33
+ import type { GatewayRerankingModelId } from './gateway-reranking-model-settings';
22
34
  import type { GatewayVideoModelId } from './gateway-video-model-settings';
23
35
  import { gatewayTools } from './gateway-tools';
24
36
  import { getVercelOidcToken, getVercelRequestId } from './vercel-environment';
25
37
  import type { GatewayModelId } from './gateway-language-model-settings';
26
38
  import type {
27
- LanguageModelV3,
28
- EmbeddingModelV3,
29
- ImageModelV3,
30
- Experimental_VideoModelV3,
31
- ProviderV3,
39
+ LanguageModelV4,
40
+ EmbeddingModelV4,
41
+ ImageModelV4,
42
+ RerankingModelV4,
43
+ Experimental_VideoModelV4,
44
+ ProviderV4,
32
45
  } from '@ai-sdk/provider';
33
46
  import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
34
47
  import { VERSION } from './version';
35
48
 
36
- export interface GatewayProvider extends ProviderV3 {
37
- (modelId: GatewayModelId): LanguageModelV3;
49
+ export interface GatewayProvider extends ProviderV4 {
50
+ (modelId: GatewayModelId): LanguageModelV4;
38
51
 
39
52
  /**
40
53
  * Creates a model for text generation.
41
54
  */
42
- chat(modelId: GatewayModelId): LanguageModelV3;
55
+ chat(modelId: GatewayModelId): LanguageModelV4;
43
56
 
44
57
  /**
45
58
  * Creates a model for text generation.
46
59
  */
47
- languageModel(modelId: GatewayModelId): LanguageModelV3;
60
+ languageModel(modelId: GatewayModelId): LanguageModelV4;
48
61
 
49
62
  /**
50
63
  * Returns available providers and models for use with the remote provider.
@@ -56,40 +69,66 @@ export interface GatewayProvider extends ProviderV3 {
56
69
  */
57
70
  getCredits(): Promise<GatewayCreditsResponse>;
58
71
 
72
+ /**
73
+ * Returns a spend report with cost, token, and request count data,
74
+ * aggregated by the specified dimension.
75
+ */
76
+ getSpendReport(
77
+ params: GatewaySpendReportParams,
78
+ ): Promise<GatewaySpendReportResponse>;
79
+
80
+ /**
81
+ * Returns detailed information about a specific generation by its ID,
82
+ * including cost, token usage, latency, and provider details.
83
+ */
84
+ getGenerationInfo(
85
+ params: GatewayGenerationInfoParams,
86
+ ): Promise<GatewayGenerationInfo>;
87
+
59
88
  /**
60
89
  * Creates a model for generating text embeddings.
61
90
  */
62
- embedding(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
91
+ embedding(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
63
92
 
64
93
  /**
65
94
  * Creates a model for generating text embeddings.
66
95
  */
67
- embeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
96
+ embeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
68
97
 
69
98
  /**
70
99
  * @deprecated Use `embeddingModel` instead.
71
100
  */
72
- textEmbeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
101
+ textEmbeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV4;
73
102
 
74
103
  /**
75
104
  * Creates a model for generating images.
76
105
  */
77
- image(modelId: GatewayImageModelId): ImageModelV3;
106
+ image(modelId: GatewayImageModelId): ImageModelV4;
78
107
 
79
108
  /**
80
109
  * Creates a model for generating images.
81
110
  */
82
- imageModel(modelId: GatewayImageModelId): ImageModelV3;
111
+ imageModel(modelId: GatewayImageModelId): ImageModelV4;
83
112
 
84
113
  /**
85
114
  * Creates a model for generating videos.
86
115
  */
87
- video(modelId: GatewayVideoModelId): Experimental_VideoModelV3;
116
+ video(modelId: GatewayVideoModelId): Experimental_VideoModelV4;
88
117
 
89
118
  /**
90
119
  * Creates a model for generating videos.
91
120
  */
92
- videoModel(modelId: GatewayVideoModelId): Experimental_VideoModelV3;
121
+ videoModel(modelId: GatewayVideoModelId): Experimental_VideoModelV4;
122
+
123
+ /**
124
+ * Creates a model for reranking documents.
125
+ */
126
+ reranking(modelId: GatewayRerankingModelId): RerankingModelV4;
127
+
128
+ /**
129
+ * Creates a model for reranking documents.
130
+ */
131
+ rerankingModel(modelId: GatewayRerankingModelId): RerankingModelV4;
93
132
 
94
133
  /**
95
134
  * Gateway-specific tools executed server-side.
@@ -253,6 +292,36 @@ export function createGatewayProvider(
253
292
  });
254
293
  };
255
294
 
295
+ const getSpendReport = async (params: GatewaySpendReportParams) => {
296
+ return new GatewaySpendReport({
297
+ baseURL,
298
+ headers: getHeaders,
299
+ fetch: options.fetch,
300
+ })
301
+ .getSpendReport(params)
302
+ .catch(async (error: unknown) => {
303
+ throw await asGatewayError(
304
+ error,
305
+ await parseAuthMethod(await getHeaders()),
306
+ );
307
+ });
308
+ };
309
+
310
+ const getGenerationInfo = async (params: GatewayGenerationInfoParams) => {
311
+ return new GatewayGenerationInfoFetcher({
312
+ baseURL,
313
+ headers: getHeaders,
314
+ fetch: options.fetch,
315
+ })
316
+ .getGenerationInfo(params)
317
+ .catch(async (error: unknown) => {
318
+ throw await asGatewayError(
319
+ error,
320
+ await parseAuthMethod(await getHeaders()),
321
+ );
322
+ });
323
+ };
324
+
256
325
  const provider = function (modelId: GatewayModelId) {
257
326
  if (new.target) {
258
327
  throw new Error(
@@ -263,9 +332,11 @@ export function createGatewayProvider(
263
332
  return createLanguageModel(modelId);
264
333
  };
265
334
 
266
- provider.specificationVersion = 'v3' as const;
335
+ provider.specificationVersion = 'v4' as const;
267
336
  provider.getAvailableModels = getAvailableModels;
268
337
  provider.getCredits = getCredits;
338
+ provider.getSpendReport = getSpendReport;
339
+ provider.getGenerationInfo = getGenerationInfo;
269
340
  provider.imageModel = (modelId: GatewayImageModelId) => {
270
341
  return new GatewayImageModel(modelId, {
271
342
  provider: 'gateway',
@@ -296,6 +367,17 @@ export function createGatewayProvider(
296
367
  o11yHeaders: createO11yHeaders(),
297
368
  });
298
369
  };
370
+ const createRerankingModel = (modelId: GatewayRerankingModelId) => {
371
+ return new GatewayRerankingModel(modelId, {
372
+ provider: 'gateway',
373
+ baseURL,
374
+ headers: getHeaders,
375
+ fetch: options.fetch,
376
+ o11yHeaders: createO11yHeaders(),
377
+ });
378
+ };
379
+ provider.rerankingModel = createRerankingModel;
380
+ provider.reranking = createRerankingModel;
299
381
  provider.chat = provider.languageModel;
300
382
  provider.embedding = provider.embeddingModel;
301
383
  provider.image = provider.imageModel;
@@ -0,0 +1 @@
1
+ export type GatewayRerankingModelId = 'cohere/rerank-v3.5' | (string & {});
@@ -0,0 +1,119 @@
1
+ import type {
2
+ RerankingModelV4,
3
+ SharedV4ProviderMetadata,
4
+ } from '@ai-sdk/provider';
5
+ import {
6
+ combineHeaders,
7
+ createJsonErrorResponseHandler,
8
+ createJsonResponseHandler,
9
+ lazySchema,
10
+ postJsonToApi,
11
+ resolve,
12
+ zodSchema,
13
+ type Resolvable,
14
+ } from '@ai-sdk/provider-utils';
15
+ import { z } from 'zod/v4';
16
+ import { asGatewayError } from './errors';
17
+ import { parseAuthMethod } from './errors/parse-auth-method';
18
+ import type { GatewayConfig } from './gateway-config';
19
+
20
+ export class GatewayRerankingModel implements RerankingModelV4 {
21
+ readonly specificationVersion = 'v4';
22
+
23
+ constructor(
24
+ readonly modelId: string,
25
+ private readonly config: GatewayConfig & {
26
+ provider: string;
27
+ o11yHeaders: Resolvable<Record<string, string>>;
28
+ },
29
+ ) {}
30
+
31
+ get provider(): string {
32
+ return this.config.provider;
33
+ }
34
+
35
+ async doRerank({
36
+ documents,
37
+ query,
38
+ topN,
39
+ headers,
40
+ abortSignal,
41
+ providerOptions,
42
+ }: Parameters<RerankingModelV4['doRerank']>[0]): Promise<
43
+ Awaited<ReturnType<RerankingModelV4['doRerank']>>
44
+ > {
45
+ const resolvedHeaders = this.config.headers
46
+ ? await resolve(this.config.headers)
47
+ : undefined;
48
+ try {
49
+ const {
50
+ responseHeaders,
51
+ value: responseBody,
52
+ rawValue,
53
+ } = await postJsonToApi({
54
+ url: this.getUrl(),
55
+ headers: combineHeaders(
56
+ resolvedHeaders,
57
+ headers ?? {},
58
+ this.getModelConfigHeaders(),
59
+ await resolve(this.config.o11yHeaders),
60
+ ),
61
+ body: {
62
+ documents,
63
+ query,
64
+ ...(topN != null ? { topN } : {}),
65
+ ...(providerOptions ? { providerOptions } : {}),
66
+ },
67
+ successfulResponseHandler: createJsonResponseHandler(
68
+ gatewayRerankingResponseSchema,
69
+ ),
70
+ failedResponseHandler: createJsonErrorResponseHandler({
71
+ errorSchema: z.any(),
72
+ errorToMessage: data => data,
73
+ }),
74
+ ...(abortSignal && { abortSignal }),
75
+ fetch: this.config.fetch,
76
+ });
77
+
78
+ return {
79
+ ranking: responseBody.ranking,
80
+ providerMetadata:
81
+ responseBody.providerMetadata as unknown as SharedV4ProviderMetadata,
82
+ response: { headers: responseHeaders, body: rawValue },
83
+ warnings: [],
84
+ };
85
+ } catch (error) {
86
+ throw await asGatewayError(
87
+ error,
88
+ await parseAuthMethod(resolvedHeaders ?? {}),
89
+ );
90
+ }
91
+ }
92
+
93
+ private getUrl() {
94
+ return `${this.config.baseURL}/reranking-model`;
95
+ }
96
+
97
+ private getModelConfigHeaders() {
98
+ return {
99
+ 'ai-reranking-model-specification-version': '4',
100
+ 'ai-model-id': this.modelId,
101
+ };
102
+ }
103
+ }
104
+
105
+ const gatewayRerankingResponseSchema = lazySchema(() =>
106
+ zodSchema(
107
+ z.object({
108
+ ranking: z.array(
109
+ z.object({
110
+ index: z.number(),
111
+ relevanceScore: z.number(),
112
+ }),
113
+ ),
114
+ providerMetadata: z
115
+ .record(z.string(), z.record(z.string(), z.unknown()))
116
+ .optional(),
117
+ }),
118
+ ),
119
+ );
@@ -0,0 +1,193 @@
1
+ import {
2
+ createJsonErrorResponseHandler,
3
+ createJsonResponseHandler,
4
+ getFromApi,
5
+ lazySchema,
6
+ resolve,
7
+ zodSchema,
8
+ } from '@ai-sdk/provider-utils';
9
+ import { z } from 'zod/v4';
10
+ import { asGatewayError } from './errors';
11
+ import type { GatewayConfig } from './gateway-config';
12
+
13
+ export interface GatewaySpendReportParams {
14
+ /** Start date in YYYY-MM-DD format (inclusive) */
15
+ startDate: string;
16
+ /** End date in YYYY-MM-DD format (inclusive) */
17
+ endDate: string;
18
+ /** Primary aggregation dimension. Defaults to 'day'. */
19
+ groupBy?: 'day' | 'user' | 'model' | 'tag' | 'provider' | 'credential_type';
20
+ /** Time granularity when groupBy is 'day'. */
21
+ datePart?: 'day' | 'hour';
22
+ /** Filter to a specific user's spend. */
23
+ userId?: string;
24
+ /** Filter to a specific model (e.g. 'anthropic/claude-sonnet-4.5'). */
25
+ model?: string;
26
+ /** Filter to a specific provider (e.g. 'anthropic'). */
27
+ provider?: string;
28
+ /** Filter to BYOK or system credentials. */
29
+ credentialType?: 'byok' | 'system';
30
+ /** Filter to requests with these tags. */
31
+ tags?: string[];
32
+ }
33
+
34
+ export interface GatewaySpendReportRow {
35
+ /** Date string (present when groupBy is 'day') */
36
+ day?: string;
37
+ /** Hour timestamp (present when groupBy is 'day' and datePart is 'hour') */
38
+ hour?: string;
39
+ /** User identifier (present when groupBy is 'user') */
40
+ user?: string;
41
+ /** Model identifier (present when groupBy is 'model') */
42
+ model?: string;
43
+ /** Tag value (present when groupBy is 'tag') */
44
+ tag?: string;
45
+ /** Provider name (present when groupBy is 'provider') */
46
+ provider?: string;
47
+ /** Credential type (present when groupBy is 'credential_type') */
48
+ credentialType?: 'byok' | 'system';
49
+
50
+ /** Total cost in USD */
51
+ totalCost: number;
52
+ /** Market cost in USD */
53
+ marketCost?: number;
54
+ /** Number of input tokens */
55
+ inputTokens?: number;
56
+ /** Number of output tokens */
57
+ outputTokens?: number;
58
+ /** Number of cached input tokens */
59
+ cachedInputTokens?: number;
60
+ /** Number of cache creation input tokens */
61
+ cacheCreationInputTokens?: number;
62
+ /** Number of reasoning tokens */
63
+ reasoningTokens?: number;
64
+ /** Number of requests */
65
+ requestCount?: number;
66
+ }
67
+
68
+ export interface GatewaySpendReportResponse {
69
+ results: GatewaySpendReportRow[];
70
+ }
71
+
72
+ export class GatewaySpendReport {
73
+ constructor(private readonly config: GatewayConfig) {}
74
+
75
+ async getSpendReport(
76
+ params: GatewaySpendReportParams,
77
+ ): Promise<GatewaySpendReportResponse> {
78
+ try {
79
+ const baseUrl = new URL(this.config.baseURL);
80
+
81
+ const searchParams = new URLSearchParams();
82
+ searchParams.set('start_date', params.startDate);
83
+ searchParams.set('end_date', params.endDate);
84
+
85
+ if (params.groupBy) {
86
+ searchParams.set('group_by', params.groupBy);
87
+ }
88
+ if (params.datePart) {
89
+ searchParams.set('date_part', params.datePart);
90
+ }
91
+ if (params.userId) {
92
+ searchParams.set('user_id', params.userId);
93
+ }
94
+ if (params.model) {
95
+ searchParams.set('model', params.model);
96
+ }
97
+ if (params.provider) {
98
+ searchParams.set('provider', params.provider);
99
+ }
100
+ if (params.credentialType) {
101
+ searchParams.set('credential_type', params.credentialType);
102
+ }
103
+ if (params.tags && params.tags.length > 0) {
104
+ searchParams.set('tags', params.tags.join(','));
105
+ }
106
+
107
+ const { value } = await getFromApi({
108
+ url: `${baseUrl.origin}/v1/report?${searchParams.toString()}`,
109
+ headers: this.config.headers
110
+ ? await resolve(this.config.headers)
111
+ : undefined,
112
+ successfulResponseHandler: createJsonResponseHandler(
113
+ gatewaySpendReportResponseSchema,
114
+ ),
115
+ failedResponseHandler: createJsonErrorResponseHandler({
116
+ errorSchema: z.any(),
117
+ errorToMessage: data => data,
118
+ }),
119
+ fetch: this.config.fetch,
120
+ });
121
+
122
+ return value;
123
+ } catch (error) {
124
+ throw await asGatewayError(error);
125
+ }
126
+ }
127
+ }
128
+
129
+ const gatewaySpendReportResponseSchema = lazySchema(() =>
130
+ zodSchema(
131
+ z.object({
132
+ results: z.array(
133
+ z
134
+ .object({
135
+ day: z.string().optional(),
136
+ hour: z.string().optional(),
137
+ user: z.string().optional(),
138
+ model: z.string().optional(),
139
+ tag: z.string().optional(),
140
+ provider: z.string().optional(),
141
+ credential_type: z.enum(['byok', 'system']).optional(),
142
+ total_cost: z.number(),
143
+ market_cost: z.number().optional(),
144
+ input_tokens: z.number().optional(),
145
+ output_tokens: z.number().optional(),
146
+ cached_input_tokens: z.number().optional(),
147
+ cache_creation_input_tokens: z.number().optional(),
148
+ reasoning_tokens: z.number().optional(),
149
+ request_count: z.number().optional(),
150
+ })
151
+ .transform(
152
+ ({
153
+ credential_type,
154
+ total_cost,
155
+ market_cost,
156
+ input_tokens,
157
+ output_tokens,
158
+ cached_input_tokens,
159
+ cache_creation_input_tokens,
160
+ reasoning_tokens,
161
+ request_count,
162
+ ...rest
163
+ }) => ({
164
+ ...rest,
165
+ ...(credential_type !== undefined
166
+ ? { credentialType: credential_type }
167
+ : {}),
168
+ totalCost: total_cost,
169
+ ...(market_cost !== undefined ? { marketCost: market_cost } : {}),
170
+ ...(input_tokens !== undefined
171
+ ? { inputTokens: input_tokens }
172
+ : {}),
173
+ ...(output_tokens !== undefined
174
+ ? { outputTokens: output_tokens }
175
+ : {}),
176
+ ...(cached_input_tokens !== undefined
177
+ ? { cachedInputTokens: cached_input_tokens }
178
+ : {}),
179
+ ...(cache_creation_input_tokens !== undefined
180
+ ? { cacheCreationInputTokens: cache_creation_input_tokens }
181
+ : {}),
182
+ ...(reasoning_tokens !== undefined
183
+ ? { reasoningTokens: reasoning_tokens }
184
+ : {}),
185
+ ...(request_count !== undefined
186
+ ? { requestCount: request_count }
187
+ : {}),
188
+ }),
189
+ ),
190
+ ),
191
+ }),
192
+ ),
193
+ );
@@ -1,10 +1,10 @@
1
1
  import type {
2
- Experimental_VideoModelV3,
3
- Experimental_VideoModelV3CallOptions,
4
- Experimental_VideoModelV3File,
5
- Experimental_VideoModelV3VideoData,
6
- SharedV3ProviderMetadata,
7
- SharedV3Warning,
2
+ Experimental_VideoModelV4,
3
+ Experimental_VideoModelV4CallOptions,
4
+ Experimental_VideoModelV4File,
5
+ Experimental_VideoModelV4VideoData,
6
+ SharedV4ProviderMetadata,
7
+ SharedV4Warning,
8
8
  } from '@ai-sdk/provider';
9
9
  import { APICallError } from '@ai-sdk/provider';
10
10
  import {
@@ -21,8 +21,8 @@ import type { GatewayConfig } from './gateway-config';
21
21
  import { asGatewayError } from './errors';
22
22
  import { parseAuthMethod } from './errors/parse-auth-method';
23
23
 
24
- export class GatewayVideoModel implements Experimental_VideoModelV3 {
25
- readonly specificationVersion = 'v3' as const;
24
+ export class GatewayVideoModel implements Experimental_VideoModelV4 {
25
+ readonly specificationVersion = 'v4' as const;
26
26
  // Set a very large number to prevent client-side splitting of requests
27
27
  readonly maxVideosPerCall = Number.MAX_SAFE_INTEGER;
28
28
 
@@ -50,17 +50,19 @@ export class GatewayVideoModel implements Experimental_VideoModelV3 {
50
50
  providerOptions,
51
51
  headers,
52
52
  abortSignal,
53
- }: Experimental_VideoModelV3CallOptions): Promise<{
54
- videos: Array<Experimental_VideoModelV3VideoData>;
55
- warnings: Array<SharedV3Warning>;
56
- providerMetadata?: SharedV3ProviderMetadata;
53
+ }: Experimental_VideoModelV4CallOptions): Promise<{
54
+ videos: Array<Experimental_VideoModelV4VideoData>;
55
+ warnings: Array<SharedV4Warning>;
56
+ providerMetadata?: SharedV4ProviderMetadata;
57
57
  response: {
58
58
  timestamp: Date;
59
59
  modelId: string;
60
60
  headers: Record<string, string> | undefined;
61
61
  };
62
62
  }> {
63
- const resolvedHeaders = await resolve(this.config.headers());
63
+ const resolvedHeaders = this.config.headers
64
+ ? await resolve(this.config.headers)
65
+ : undefined;
64
66
  try {
65
67
  const { responseHeaders, value: responseBody } = await postJsonToApi({
66
68
  url: this.getUrl(),
@@ -170,7 +172,7 @@ export class GatewayVideoModel implements Experimental_VideoModelV3 {
170
172
  videos: responseBody.videos,
171
173
  warnings: responseBody.warnings ?? [],
172
174
  providerMetadata:
173
- responseBody.providerMetadata as SharedV3ProviderMetadata,
175
+ responseBody.providerMetadata as SharedV4ProviderMetadata,
174
176
  response: {
175
177
  timestamp: new Date(),
176
178
  modelId: this.modelId,
@@ -178,7 +180,10 @@ export class GatewayVideoModel implements Experimental_VideoModelV3 {
178
180
  },
179
181
  };
180
182
  } catch (error) {
181
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
183
+ throw await asGatewayError(
184
+ error,
185
+ await parseAuthMethod(resolvedHeaders ?? {}),
186
+ );
182
187
  }
183
188
  }
184
189
 
@@ -188,13 +193,13 @@ export class GatewayVideoModel implements Experimental_VideoModelV3 {
188
193
 
189
194
  private getModelConfigHeaders() {
190
195
  return {
191
- 'ai-video-model-specification-version': '3',
196
+ 'ai-video-model-specification-version': '4',
192
197
  'ai-model-id': this.modelId,
193
198
  };
194
199
  }
195
200
  }
196
201
 
197
- function maybeEncodeVideoFile(file: Experimental_VideoModelV3File) {
202
+ function maybeEncodeVideoFile(file: Experimental_VideoModelV4File) {
198
203
  if (file.type === 'file' && file.data instanceof Uint8Array) {
199
204
  return {
200
205
  ...file,