@ai-sdk/gateway 4.0.0-beta.1 → 4.0.0-beta.108

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 (46) hide show
  1. package/CHANGELOG.md +794 -4
  2. package/dist/index.d.ts +314 -42
  3. package/dist/index.js +1369 -397
  4. package/dist/index.js.map +1 -1
  5. package/docs/00-ai-gateway.mdx +447 -61
  6. package/package.json +15 -15
  7. package/src/errors/as-gateway-error.ts +2 -1
  8. package/src/errors/create-gateway-error.ts +17 -3
  9. package/src/errors/gateway-authentication-error.ts +8 -5
  10. package/src/errors/gateway-error.ts +8 -0
  11. package/src/errors/gateway-failed-dependency-error.ts +35 -0
  12. package/src/errors/gateway-forbidden-error.ts +34 -0
  13. package/src/errors/gateway-response-error.ts +1 -1
  14. package/src/errors/index.ts +2 -0
  15. package/src/errors/parse-auth-method.ts +1 -2
  16. package/src/gateway-config.ts +1 -1
  17. package/src/gateway-embedding-model-settings.ts +1 -0
  18. package/src/gateway-embedding-model.ts +62 -15
  19. package/src/gateway-fetch-metadata.ts +51 -38
  20. package/src/gateway-generation-info.ts +149 -0
  21. package/src/gateway-headers.ts +3 -0
  22. package/src/gateway-image-model-settings.ts +14 -1
  23. package/src/gateway-image-model.ts +46 -21
  24. package/src/gateway-language-model-settings.ts +52 -31
  25. package/src/gateway-language-model.ts +72 -42
  26. package/src/gateway-model-entry.ts +15 -3
  27. package/src/gateway-provider-options.ts +50 -78
  28. package/src/gateway-provider.ts +239 -35
  29. package/src/gateway-realtime-auth.ts +126 -0
  30. package/src/gateway-realtime-model-settings.ts +1 -0
  31. package/src/gateway-realtime-model.ts +107 -0
  32. package/src/gateway-reranking-model-settings.ts +7 -0
  33. package/src/gateway-reranking-model.ts +142 -0
  34. package/src/gateway-speech-model-settings.ts +1 -0
  35. package/src/gateway-speech-model.ts +145 -0
  36. package/src/gateway-spend-report.ts +193 -0
  37. package/src/gateway-transcription-model-settings.ts +1 -0
  38. package/src/gateway-transcription-model.ts +155 -0
  39. package/src/gateway-video-model-settings.ts +4 -0
  40. package/src/gateway-video-model.ts +29 -19
  41. package/src/index.ts +30 -5
  42. package/src/tool/parallel-search.ts +10 -11
  43. package/src/tool/perplexity-search.ts +10 -11
  44. package/dist/index.d.mts +0 -602
  45. package/dist/index.mjs +0 -1539
  46. package/dist/index.mjs.map +0 -1
@@ -1,11 +1,9 @@
1
1
  import type {
2
- LanguageModelV3,
3
- LanguageModelV3CallOptions,
4
- SharedV3Warning,
5
- LanguageModelV3FilePart,
6
- LanguageModelV3StreamPart,
7
- LanguageModelV3GenerateResult,
8
- LanguageModelV3StreamResult,
2
+ LanguageModelV4,
3
+ LanguageModelV4CallOptions,
4
+ LanguageModelV4StreamPart,
5
+ LanguageModelV4GenerateResult,
6
+ LanguageModelV4StreamResult,
9
7
  } from '@ai-sdk/provider';
10
8
  import {
11
9
  combineHeaders,
@@ -14,6 +12,9 @@ import {
14
12
  createJsonResponseHandler,
15
13
  postJsonToApi,
16
14
  resolve,
15
+ serializeModelOptions,
16
+ WORKFLOW_SERIALIZE,
17
+ WORKFLOW_DESERIALIZE,
17
18
  type ParseResult,
18
19
  type Resolvable,
19
20
  } from '@ai-sdk/provider-utils';
@@ -28,10 +29,24 @@ type GatewayChatConfig = GatewayConfig & {
28
29
  o11yHeaders: Resolvable<Record<string, string>>;
29
30
  };
30
31
 
31
- export class GatewayLanguageModel implements LanguageModelV3 {
32
- readonly specificationVersion = 'v3';
32
+ export class GatewayLanguageModel implements LanguageModelV4 {
33
+ readonly specificationVersion = 'v4';
33
34
  readonly supportedUrls = { '*/*': [/.*/] };
34
35
 
36
+ static [WORKFLOW_SERIALIZE](model: GatewayLanguageModel) {
37
+ return serializeModelOptions({
38
+ modelId: model.modelId,
39
+ config: model.config,
40
+ });
41
+ }
42
+
43
+ static [WORKFLOW_DESERIALIZE](options: {
44
+ modelId: GatewayModelId;
45
+ config: GatewayChatConfig;
46
+ }) {
47
+ return new GatewayLanguageModel(options.modelId, options.config);
48
+ }
49
+
35
50
  constructor(
36
51
  readonly modelId: GatewayModelId,
37
52
  private readonly config: GatewayChatConfig,
@@ -41,7 +56,7 @@ export class GatewayLanguageModel implements LanguageModelV3 {
41
56
  return this.config.provider;
42
57
  }
43
58
 
44
- private async getArgs(options: LanguageModelV3CallOptions) {
59
+ private async getArgs(options: LanguageModelV4CallOptions) {
45
60
  const { abortSignal: _abortSignal, ...optionsWithoutSignal } = options;
46
61
 
47
62
  return {
@@ -51,12 +66,14 @@ export class GatewayLanguageModel implements LanguageModelV3 {
51
66
  }
52
67
 
53
68
  async doGenerate(
54
- options: LanguageModelV3CallOptions,
55
- ): Promise<LanguageModelV3GenerateResult> {
69
+ options: LanguageModelV4CallOptions,
70
+ ): Promise<LanguageModelV4GenerateResult> {
56
71
  const { args, warnings } = await this.getArgs(options);
57
72
  const { abortSignal } = options;
58
73
 
59
- const resolvedHeaders = await resolve(this.config.headers());
74
+ const resolvedHeaders = this.config.headers
75
+ ? await resolve(this.config.headers)
76
+ : undefined;
60
77
 
61
78
  try {
62
79
  const {
@@ -88,17 +105,22 @@ export class GatewayLanguageModel implements LanguageModelV3 {
88
105
  warnings,
89
106
  };
90
107
  } catch (error) {
91
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
108
+ throw await asGatewayError(
109
+ error,
110
+ await parseAuthMethod(resolvedHeaders ?? {}),
111
+ );
92
112
  }
93
113
  }
94
114
 
95
115
  async doStream(
96
- options: LanguageModelV3CallOptions,
97
- ): Promise<LanguageModelV3StreamResult> {
116
+ options: LanguageModelV4CallOptions,
117
+ ): Promise<LanguageModelV4StreamResult> {
98
118
  const { args, warnings } = await this.getArgs(options);
99
119
  const { abortSignal } = options;
100
120
 
101
- const resolvedHeaders = await resolve(this.config.headers());
121
+ const resolvedHeaders = this.config.headers
122
+ ? await resolve(this.config.headers)
123
+ : undefined;
102
124
 
103
125
  try {
104
126
  const { value: response, responseHeaders } = await postJsonToApi({
@@ -122,8 +144,8 @@ export class GatewayLanguageModel implements LanguageModelV3 {
122
144
  return {
123
145
  stream: response.pipeThrough(
124
146
  new TransformStream<
125
- ParseResult<LanguageModelV3StreamPart>,
126
- LanguageModelV3StreamPart
147
+ ParseResult<LanguageModelV4StreamPart>,
148
+ LanguageModelV4StreamPart
127
149
  >({
128
150
  start(controller) {
129
151
  if (warnings.length > 0) {
@@ -161,36 +183,34 @@ export class GatewayLanguageModel implements LanguageModelV3 {
161
183
  response: { headers: responseHeaders },
162
184
  };
163
185
  } catch (error) {
164
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
186
+ throw await asGatewayError(
187
+ error,
188
+ await parseAuthMethod(resolvedHeaders ?? {}),
189
+ );
165
190
  }
166
191
  }
167
192
 
168
- private isFilePart(part: unknown) {
169
- return (
170
- part && typeof part === 'object' && 'type' in part && part.type === 'file'
171
- );
172
- }
173
-
174
193
  /**
175
- * Encodes file parts in the prompt to base64. Mutates the passed options
176
- * instance directly to avoid copying the file data.
194
+ * Encodes inline `Uint8Array` file data to a base64 string in place.
177
195
  * @param options - The options to encode.
178
- * @returns The options with the file parts encoded.
196
+ * @returns The options with the file data encoded.
179
197
  */
180
- private maybeEncodeFileParts(options: LanguageModelV3CallOptions) {
198
+ private maybeEncodeFileParts(options: LanguageModelV4CallOptions) {
181
199
  for (const message of options.prompt) {
200
+ if (!Array.isArray(message.content)) {
201
+ continue;
202
+ }
182
203
  for (const part of message.content) {
183
- if (this.isFilePart(part)) {
184
- const filePart = part as LanguageModelV3FilePart;
185
- // If the file part is a URL it will get cleanly converted to a string.
186
- // If it's a binary file attachment we convert it to a data url.
187
- // In either case, server-side we should only ever see URLs as strings.
188
- if (filePart.data instanceof Uint8Array) {
189
- const buffer = Uint8Array.from(filePart.data);
190
- const base64Data = Buffer.from(buffer).toString('base64');
191
- filePart.data = new URL(
192
- `data:${filePart.mediaType || 'application/octet-stream'};base64,${base64Data}`,
193
- );
204
+ if (part.type === 'file' || part.type === 'reasoning-file') {
205
+ part.data = maybeBase64EncodeFileData(part.data);
206
+ } else if (
207
+ part.type === 'tool-result' &&
208
+ part.output.type === 'content'
209
+ ) {
210
+ for (const contentPart of part.output.value) {
211
+ if (contentPart.type === 'file') {
212
+ contentPart.data = maybeBase64EncodeFileData(contentPart.data);
213
+ }
194
214
  }
195
215
  }
196
216
  }
@@ -204,9 +224,19 @@ export class GatewayLanguageModel implements LanguageModelV3 {
204
224
 
205
225
  private getModelConfigHeaders(modelId: string, streaming: boolean) {
206
226
  return {
207
- 'ai-language-model-specification-version': '3',
227
+ 'ai-language-model-specification-version': '4',
208
228
  'ai-language-model-id': modelId,
209
229
  'ai-language-model-streaming': String(streaming),
210
230
  };
211
231
  }
212
232
  }
233
+
234
+ function maybeBase64EncodeFileData<T extends { type: string }>(data: T): T {
235
+ if (data.type === 'data') {
236
+ const bytes = (data as { data?: unknown }).data;
237
+ if (bytes instanceof Uint8Array) {
238
+ return { ...data, data: Buffer.from(bytes).toString('base64') } as T;
239
+ }
240
+ }
241
+ return data;
242
+ }
@@ -1,4 +1,16 @@
1
- import type { LanguageModelV3 } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4 } from '@ai-sdk/provider';
2
+
3
+ export const KNOWN_MODEL_TYPES = [
4
+ 'embedding',
5
+ 'image',
6
+ 'language',
7
+ 'reranking',
8
+ 'speech',
9
+ 'transcription',
10
+ 'video',
11
+ ] as const;
12
+
13
+ export type KnownModelType = (typeof KNOWN_MODEL_TYPES)[number];
2
14
 
3
15
  export interface GatewayLanguageModelEntry {
4
16
  /**
@@ -49,10 +61,10 @@ export interface GatewayLanguageModelEntry {
49
61
  /**
50
62
  * Optional field to differentiate between model types.
51
63
  */
52
- modelType?: 'language' | 'embedding' | 'image' | 'video' | null;
64
+ modelType?: KnownModelType | null;
53
65
  }
54
66
 
55
67
  export type GatewayLanguageModelSpecification = Pick<
56
- LanguageModelV3,
68
+ LanguageModelV4,
57
69
  'specificationVersion' | 'provider' | 'modelId'
58
70
  >;
@@ -1,80 +1,52 @@
1
- import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
2
- import { z } from 'zod/v4';
3
-
4
1
  // https://vercel.com/docs/ai-gateway/provider-options
5
- const gatewayLanguageModelOptions = lazySchema(() =>
6
- zodSchema(
7
- z.object({
8
- /**
9
- * Array of provider slugs that are the only ones allowed to be used.
10
- *
11
- * Example: `['azure', 'openai']` will only allow Azure and OpenAI to be used.
12
- */
13
- only: z.array(z.string()).optional(),
14
- /**
15
- * Array of provider slugs that specifies the sequence in which providers should be attempted.
16
- *
17
- * Example: `['bedrock', 'anthropic']` will try Amazon Bedrock first, then Anthropic as fallback.
18
- */
19
- order: z.array(z.string()).optional(),
20
- /**
21
- * The unique identifier for the end user on behalf of whom the request was made.
22
- *
23
- * Used for spend tracking and attribution purposes.
24
- */
25
- user: z.string().optional(),
26
- /**
27
- * User-specified tags for use in reporting and filtering usage.
28
- *
29
- * For example, spend tracking reporting by feature or prompt version.
30
- *
31
- * Example: `['chat', 'v2']`
32
- */
33
- tags: z.array(z.string()).optional(),
34
- /**
35
- * Array of model slugs specifying fallback models to use in order.
36
- *
37
- * Example: `['openai/gpt-5-nano', 'zai/glm-4.6']` will try `openai/gpt-5-nano` first, then `zai/glm-4.6` as fallback.
38
- */
39
- models: z.array(z.string()).optional(),
40
- /**
41
- * Request-scoped BYOK credentials to use instead of cached credentials.
42
- *
43
- * When provided, cached BYOK credentials are ignored entirely.
44
- *
45
- * Each provider can have multiple credentials (tried in order).
46
- *
47
- * Examples:
48
- * - Simple: `{ 'anthropic': [{ apiKey: 'sk-ant-...' }] }`
49
- * - Multiple: `{ 'vertex': [{ projectId: 'proj-1', privateKey: '...' }, { projectId: 'proj-2', privateKey: '...' }] }`
50
- * - Multi-provider: `{ 'anthropic': [{ apiKey: '...' }], 'bedrock': [{ accessKeyId: '...', secretAccessKey: '...' }] }`
51
- */
52
- byok: z
53
- .record(z.string(), z.array(z.record(z.string(), z.unknown())))
54
- .optional(),
55
- /**
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.
60
- */
61
- zeroDataRetention: z.boolean().optional(),
62
- /**
63
- * Per-provider timeouts for BYOK credentials in milliseconds.
64
- * Controls how long to wait for a provider to start responding
65
- * before falling back to the next available provider.
66
- *
67
- * Example: `{ byok: { openai: 5000, anthropic: 2000 } }`
68
- */
69
- providerTimeouts: z
70
- .object({
71
- byok: z.record(z.string(), z.number().int().min(1000)).optional(),
72
- })
73
- .optional(),
74
- }),
75
- ),
76
- );
2
+ export type GatewayProviderOptions = {
3
+ /**
4
+ * Service-owned options may be added by the Gateway without requiring an SDK
5
+ * release. The Gateway service validates and applies the runtime schema.
6
+ */
7
+ [key: string]: unknown;
8
+
9
+ /** Request-scoped BYOK credentials to use instead of cached credentials. */
10
+ byok?: Record<string, Array<Record<string, unknown>>>;
11
+
12
+ /** Enables automatic caching behavior when supported by the Gateway. */
13
+ caching?: 'auto';
14
+
15
+ /** Filter to providers that do not train on prompt data. */
16
+ disallowPromptTraining?: boolean;
17
+
18
+ /** Filter to providers that are HIPAA compliant with Vercel AI Gateway. */
19
+ hipaaCompliant?: boolean;
20
+
21
+ /** Array of model slugs specifying fallback models to use in order. */
22
+ models?: string[];
23
+
24
+ /** Array of provider slugs that are the only ones allowed to be used. */
25
+ only?: string[];
26
+
27
+ /** Array of provider slugs specifying the provider attempt order. */
28
+ order?: string[];
29
+
30
+ /** Per-provider timeouts for BYOK credentials in milliseconds. */
31
+ providerTimeouts?: {
32
+ byok?: Record<string, number>;
33
+ };
34
+
35
+ /** Entity identifier against which quota is tracked. */
36
+ quotaEntityId?: string;
37
+
38
+ /** Unified service tier intent. */
39
+ serviceTier?: 'flex' | 'priority';
40
+
41
+ /** Sort providers by a performance or cost metric before routing. */
42
+ sort?: 'cost' | 'tps' | 'ttft';
43
+
44
+ /** User-specified tags for reporting and filtering usage. */
45
+ tags?: string[];
46
+
47
+ /** End-user identifier for spend tracking and attribution. */
48
+ user?: string;
77
49
 
78
- export type GatewayLanguageModelOptions = InferSchema<
79
- typeof gatewayLanguageModelOptions
80
- >;
50
+ /** Filter to providers with zero data retention agreements. */
51
+ zeroDataRetention?: boolean;
52
+ };