@ai-sdk/google 4.0.0-beta.47 → 4.0.0-beta.49

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.
@@ -625,10 +625,10 @@ the model has access to a compliance-focused web index designed for highly-regul
625
625
  </Note>
626
626
 
627
627
  ```ts
628
- import { createVertex } from '@ai-sdk/google-vertex';
628
+ import { createGoogleVertex } from '@ai-sdk/google-vertex';
629
629
  import { generateText } from 'ai';
630
630
 
631
- const vertex = createVertex({
631
+ const vertex = createGoogleVertex({
632
632
  project: 'my-project',
633
633
  location: 'us-central1',
634
634
  });
@@ -848,11 +848,11 @@ This enables the model to provide answers based on your specific data sources an
848
848
  </Note>
849
849
 
850
850
  ```ts highlight="8,17-20"
851
- import { createVertex } from '@ai-sdk/google-vertex';
851
+ import { createGoogleVertex } from '@ai-sdk/google-vertex';
852
852
  import { GoogleProviderMetadata } from '@ai-sdk/google';
853
853
  import { generateText } from 'ai';
854
854
 
855
- const vertex = createVertex({
855
+ const vertex = createGoogleVertex({
856
856
  project: 'my-project',
857
857
  location: 'us-central1',
858
858
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "4.0.0-beta.47",
3
+ "version": "4.0.0-beta.49",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,15 +35,15 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.0-beta.13",
39
- "@ai-sdk/provider-utils": "5.0.0-beta.28"
38
+ "@ai-sdk/provider": "4.0.0-beta.14",
39
+ "@ai-sdk/provider-utils": "5.0.0-beta.30"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "20.17.24",
43
43
  "tsup": "^8",
44
44
  "typescript": "5.8.3",
45
45
  "zod": "3.25.76",
46
- "@ai-sdk/test-server": "2.0.0-beta.2",
46
+ "@ai-sdk/test-server": "2.0.0-beta.3",
47
47
  "@vercel/ai-tsconfig": "0.0.0"
48
48
  },
49
49
  "peerDependencies": {
@@ -1,4 +1,4 @@
1
- import { LanguageModelV4Usage } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4Usage } from '@ai-sdk/provider';
2
2
 
3
3
  export type GoogleTokenDetail = {
4
4
  modality: string;
@@ -1,4 +1,4 @@
1
- import { JSONSchema7Definition } from '@ai-sdk/provider';
1
+ import type { JSONSchema7Definition } from '@ai-sdk/provider';
2
2
 
3
3
  /**
4
4
  * Converts JSON Schema 7 to OpenAPI Schema 3.0
@@ -1,13 +1,14 @@
1
1
  import {
2
- LanguageModelV4Prompt,
3
2
  UnsupportedFunctionalityError,
3
+ type LanguageModelV4Prompt,
4
4
  } from '@ai-sdk/provider';
5
5
  import {
6
6
  convertToBase64,
7
- isProviderReference,
7
+ isFullMediaType,
8
+ resolveFullMediaType,
8
9
  resolveProviderReference,
9
10
  } from '@ai-sdk/provider-utils';
10
- import {
11
+ import type {
11
12
  GoogleContent,
12
13
  GoogleContentPart,
13
14
  GoogleFunctionResponsePart,
@@ -170,7 +171,13 @@ export function convertToGoogleMessages(
170
171
  prompt: LanguageModelV4Prompt,
171
172
  options?: {
172
173
  isGemmaModel?: boolean;
173
- providerOptionsName?: string;
174
+ /**
175
+ * Names to look up under `providerOptions` when reading per-part metadata
176
+ * (e.g. thought signatures). Tried in order; first match wins. For the
177
+ * Vertex provider this is `['googleVertex', 'vertex']` (new key first,
178
+ * legacy key as fallback) and for the Google provider it is `['google']`.
179
+ */
180
+ providerOptionsNames?: readonly string[];
174
181
  supportsFunctionResponseParts?: boolean;
175
182
  },
176
183
  ): GooglePrompt {
@@ -178,10 +185,30 @@ export function convertToGoogleMessages(
178
185
  const contents: Array<GoogleContent> = [];
179
186
  let systemMessagesAllowed = true;
180
187
  const isGemmaModel = options?.isGemmaModel ?? false;
181
- const providerOptionsName = options?.providerOptionsName ?? 'google';
188
+ const providerOptionsNames = options?.providerOptionsNames ?? ['google'];
189
+ const isVertexLike = !providerOptionsNames.includes('google');
182
190
  const supportsFunctionResponseParts =
183
191
  options?.supportsFunctionResponseParts ?? true;
184
192
 
193
+ const readProviderOpts = (part: {
194
+ providerOptions?: Record<string, unknown> | undefined;
195
+ }): Record<string, unknown> | undefined => {
196
+ for (const name of providerOptionsNames) {
197
+ const v = part.providerOptions?.[name];
198
+ if (v != null) return v as Record<string, unknown>;
199
+ }
200
+ // Cross-namespace fallback (gateway interop): Vertex providers may receive
201
+ // metadata under `google`, and the Google provider may receive metadata
202
+ // under `googleVertex`/`vertex`.
203
+ if (isVertexLike) {
204
+ return part.providerOptions?.google as
205
+ | Record<string, unknown>
206
+ | undefined;
207
+ }
208
+ return (part.providerOptions?.googleVertex ??
209
+ part.providerOptions?.vertex) as Record<string, unknown> | undefined;
210
+ };
211
+
185
212
  for (const { role, content } of prompt) {
186
213
  switch (role) {
187
214
  case 'system': {
@@ -209,39 +236,56 @@ export function convertToGoogleMessages(
209
236
  }
210
237
 
211
238
  case 'file': {
212
- const mediaType =
213
- part.mediaType === 'image/*' ? 'image/jpeg' : part.mediaType;
214
-
215
- if (part.data instanceof URL) {
216
- parts.push({
217
- fileData: {
218
- mimeType: mediaType,
219
- fileUri: part.data.toString(),
220
- },
221
- });
222
- } else if (isProviderReference(part.data)) {
223
- if (providerOptionsName === 'vertex') {
224
- throw new UnsupportedFunctionalityError({
225
- functionality: 'file parts with provider references',
239
+ switch (part.data.type) {
240
+ case 'url': {
241
+ parts.push({
242
+ fileData: {
243
+ mimeType: resolveFullMediaType({ part }),
244
+ fileUri: part.data.url.toString(),
245
+ },
226
246
  });
247
+ break;
227
248
  }
249
+ case 'reference': {
250
+ if (isVertexLike) {
251
+ throw new UnsupportedFunctionalityError({
252
+ functionality: 'file parts with provider references',
253
+ });
254
+ }
228
255
 
229
- parts.push({
230
- fileData: {
231
- mimeType: mediaType,
232
- fileUri: resolveProviderReference({
233
- reference: part.data,
234
- provider: 'google',
235
- }),
236
- },
237
- });
238
- } else {
239
- parts.push({
240
- inlineData: {
241
- mimeType: mediaType,
242
- data: convertToBase64(part.data),
243
- },
244
- });
256
+ parts.push({
257
+ fileData: {
258
+ mimeType: resolveFullMediaType({ part }),
259
+ fileUri: resolveProviderReference({
260
+ reference: part.data.reference,
261
+ provider: 'google',
262
+ }),
263
+ },
264
+ });
265
+ break;
266
+ }
267
+ case 'text': {
268
+ parts.push({
269
+ inlineData: {
270
+ mimeType: isFullMediaType(part.mediaType)
271
+ ? part.mediaType
272
+ : 'text/plain',
273
+ data: convertToBase64(
274
+ new TextEncoder().encode(part.data.text),
275
+ ),
276
+ },
277
+ });
278
+ break;
279
+ }
280
+ case 'data': {
281
+ parts.push({
282
+ inlineData: {
283
+ mimeType: resolveFullMediaType({ part }),
284
+ data: convertToBase64(part.data.data),
285
+ },
286
+ });
287
+ break;
288
+ }
245
289
  }
246
290
 
247
291
  break;
@@ -260,11 +304,7 @@ export function convertToGoogleMessages(
260
304
  role: 'model',
261
305
  parts: content
262
306
  .map(part => {
263
- const providerOpts =
264
- part.providerOptions?.[providerOptionsName] ??
265
- (providerOptionsName !== 'google'
266
- ? part.providerOptions?.google
267
- : part.providerOptions?.vertex);
307
+ const providerOpts = readProviderOpts(part);
268
308
  const thoughtSignature =
269
309
  providerOpts?.thoughtSignature != null
270
310
  ? String(providerOpts.thoughtSignature)
@@ -291,63 +331,86 @@ export function convertToGoogleMessages(
291
331
  }
292
332
 
293
333
  case 'reasoning-file': {
294
- if (part.data instanceof URL) {
295
- throw new UnsupportedFunctionalityError({
296
- functionality:
297
- 'File data URLs in assistant messages are not supported',
298
- });
334
+ switch (part.data.type) {
335
+ case 'url': {
336
+ throw new UnsupportedFunctionalityError({
337
+ functionality:
338
+ 'File data URLs in assistant messages are not supported',
339
+ });
340
+ }
341
+ case 'data': {
342
+ return {
343
+ inlineData: {
344
+ mimeType: part.mediaType,
345
+ data: convertToBase64(part.data.data),
346
+ },
347
+ thought: true,
348
+ thoughtSignature,
349
+ };
350
+ }
299
351
  }
300
-
301
- return {
302
- inlineData: {
303
- mimeType: part.mediaType,
304
- data: convertToBase64(part.data),
305
- },
306
- thought: true,
307
- thoughtSignature,
308
- };
352
+ break;
309
353
  }
310
354
 
311
355
  case 'file': {
312
- if (part.data instanceof URL) {
313
- throw new UnsupportedFunctionalityError({
314
- functionality:
315
- 'File data URLs in assistant messages are not supported',
316
- });
317
- }
318
-
319
- if (isProviderReference(part.data)) {
320
- if (providerOptionsName === 'vertex') {
356
+ switch (part.data.type) {
357
+ case 'url': {
321
358
  throw new UnsupportedFunctionalityError({
322
- functionality: 'file parts with provider references',
359
+ functionality:
360
+ 'File data URLs in assistant messages are not supported',
323
361
  });
324
362
  }
325
-
326
- return {
327
- fileData: {
328
- mimeType: part.mediaType,
329
- fileUri: resolveProviderReference({
330
- reference: part.data,
331
- provider: 'google',
332
- }),
333
- },
334
- ...(providerOpts?.thought === true
335
- ? { thought: true }
336
- : {}),
337
- thoughtSignature,
338
- };
363
+ case 'reference': {
364
+ if (isVertexLike) {
365
+ throw new UnsupportedFunctionalityError({
366
+ functionality: 'file parts with provider references',
367
+ });
368
+ }
369
+
370
+ return {
371
+ fileData: {
372
+ mimeType: part.mediaType,
373
+ fileUri: resolveProviderReference({
374
+ reference: part.data.reference,
375
+ provider: 'google',
376
+ }),
377
+ },
378
+ ...(providerOpts?.thought === true
379
+ ? { thought: true }
380
+ : {}),
381
+ thoughtSignature,
382
+ };
383
+ }
384
+ case 'text': {
385
+ return {
386
+ inlineData: {
387
+ mimeType: isFullMediaType(part.mediaType)
388
+ ? part.mediaType
389
+ : 'text/plain',
390
+ data: convertToBase64(
391
+ new TextEncoder().encode(part.data.text),
392
+ ),
393
+ },
394
+ ...(providerOpts?.thought === true
395
+ ? { thought: true }
396
+ : {}),
397
+ thoughtSignature,
398
+ };
399
+ }
400
+ case 'data': {
401
+ return {
402
+ inlineData: {
403
+ mimeType: part.mediaType,
404
+ data: convertToBase64(part.data.data),
405
+ },
406
+ ...(providerOpts?.thought === true
407
+ ? { thought: true }
408
+ : {}),
409
+ thoughtSignature,
410
+ };
411
+ }
339
412
  }
340
-
341
- return {
342
- inlineData: {
343
- mimeType: part.mediaType,
344
- data: convertToBase64(part.data),
345
- },
346
- ...(providerOpts?.thought === true
347
- ? { thought: true }
348
- : {}),
349
- thoughtSignature,
350
- };
413
+ break;
351
414
  }
352
415
 
353
416
  case 'tool-call': {
@@ -425,11 +488,7 @@ export function convertToGoogleMessages(
425
488
  continue;
426
489
  }
427
490
 
428
- const partProviderOpts =
429
- part.providerOptions?.[providerOptionsName] ??
430
- (providerOptionsName !== 'google'
431
- ? part.providerOptions?.google
432
- : part.providerOptions?.vertex);
491
+ const partProviderOpts = readProviderOpts(part);
433
492
  const serverToolCallId =
434
493
  partProviderOpts?.serverToolCallId != null
435
494
  ? String(partProviderOpts.serverToolCallId)
@@ -1,11 +1,10 @@
1
1
  import {
2
- EmbeddingModelV4,
3
2
  TooManyEmbeddingValuesForCallError,
3
+ type EmbeddingModelV4,
4
4
  } from '@ai-sdk/provider';
5
5
  import {
6
6
  combineHeaders,
7
7
  createJsonResponseHandler,
8
- FetchFunction,
9
8
  lazySchema,
10
9
  parseProviderOptions,
11
10
  postJsonToApi,
@@ -14,14 +13,14 @@ import {
14
13
  WORKFLOW_SERIALIZE,
15
14
  WORKFLOW_DESERIALIZE,
16
15
  zodSchema,
16
+ type FetchFunction,
17
17
  } from '@ai-sdk/provider-utils';
18
18
  import { z } from 'zod/v4';
19
19
  import { googleFailedResponseHandler } from './google-error';
20
20
  import {
21
- GoogleEmbeddingModelId,
22
21
  googleEmbeddingModelOptions,
23
- } from './google-embedding-options';
24
-
22
+ type GoogleEmbeddingModelId,
23
+ } from './google-embedding-model-options';
25
24
  type GoogleEmbeddingConfig = {
26
25
  provider: string;
27
26
  baseURL: string;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createJsonErrorResponseHandler,
3
- type InferSchema,
4
3
  lazySchema,
5
4
  zodSchema,
5
+ type InferSchema,
6
6
  } from '@ai-sdk/provider-utils';
7
7
  import { z } from 'zod/v4';
8
8
 
@@ -7,13 +7,14 @@ import {
7
7
  } from '@ai-sdk/provider';
8
8
  import {
9
9
  combineHeaders,
10
+ convertInlineFileDataToUint8Array,
10
11
  createJsonResponseHandler,
11
12
  delay,
12
- type FetchFunction,
13
13
  lazySchema,
14
14
  parseProviderOptions,
15
15
  zodSchema,
16
16
  getFromApi,
17
+ type FetchFunction,
17
18
  } from '@ai-sdk/provider-utils';
18
19
  import { z } from 'zod/v4';
19
20
  import { googleFailedResponseHandler } from './google-error';
@@ -59,11 +60,7 @@ export class GoogleFiles implements FilesV4 {
59
60
  warnings.push({ type: 'unsupported', feature: 'filename' });
60
61
  }
61
62
 
62
- const data = options.data;
63
- const fileBytes =
64
- data instanceof Uint8Array
65
- ? data
66
- : Uint8Array.from(atob(data), c => c.charCodeAt(0));
63
+ const fileBytes = convertInlineFileDataToUint8Array(options.data);
67
64
 
68
65
  const mediaType = options.mediaType;
69
66
  const displayName = googleOptions?.displayName;
@@ -0,0 +1,23 @@
1
+ import {
2
+ lazySchema,
3
+ zodSchema,
4
+ type InferSchema,
5
+ } from '@ai-sdk/provider-utils';
6
+ import { z } from 'zod/v4';
7
+
8
+ // Note: For the initial GA launch of Imagen 3, safety filters are not configurable.
9
+ // https://ai.google.dev/gemini-api/docs/imagen#imagen-model
10
+ export const googleImageModelOptionsSchema = lazySchema(() =>
11
+ zodSchema(
12
+ z.object({
13
+ personGeneration: z
14
+ .enum(['dont_allow', 'allow_adult', 'allow_all'])
15
+ .nullish(),
16
+ aspectRatio: z.enum(['1:1', '3:4', '4:3', '9:16', '16:9']).nullish(),
17
+ }),
18
+ ),
19
+ );
20
+
21
+ export type GoogleImageModelOptions = InferSchema<
22
+ typeof googleImageModelOptionsSchema
23
+ >;
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  ImageModelV4,
3
3
  LanguageModelV4Prompt,
4
4
  SharedV4Warning,
@@ -7,27 +7,27 @@ import {
7
7
  combineHeaders,
8
8
  convertToBase64,
9
9
  createJsonResponseHandler,
10
- FetchFunction,
11
10
  generateId as defaultGenerateId,
12
- type InferSchema,
13
11
  lazySchema,
14
12
  parseProviderOptions,
15
13
  postJsonToApi,
16
- Resolvable,
17
14
  resolve,
18
15
  serializeModelOptions,
19
16
  WORKFLOW_SERIALIZE,
20
17
  WORKFLOW_DESERIALIZE,
21
18
  zodSchema,
19
+ type FetchFunction,
20
+ type Resolvable,
22
21
  } from '@ai-sdk/provider-utils';
23
22
  import { z } from 'zod/v4';
24
23
  import { googleFailedResponseHandler } from './google-error';
25
- import {
24
+ import { googleImageModelOptionsSchema } from './google-image-model-options';
25
+ import type {
26
26
  GoogleImageModelId,
27
27
  GoogleImageSettings,
28
28
  } from './google-image-settings';
29
29
  import { GoogleLanguageModel } from './google-language-model';
30
- import type { GoogleLanguageModelOptions } from './google-options';
30
+ import type { GoogleLanguageModelOptions } from './google-language-model-options';
31
31
 
32
32
  interface GoogleImageModelConfig {
33
33
  provider: string;
@@ -240,33 +240,39 @@ export class GoogleImageModel implements ImageModelV4 {
240
240
  });
241
241
  }
242
242
 
243
- // Build user message content for language model
244
243
  const userContent: Array<
245
244
  | { type: 'text'; text: string }
246
- | { type: 'file'; data: string | Uint8Array | URL; mediaType: string }
245
+ | {
246
+ type: 'file';
247
+ data:
248
+ | { type: 'data'; data: string | Uint8Array }
249
+ | { type: 'url'; url: URL };
250
+ mediaType: string;
251
+ }
247
252
  > = [];
248
253
 
249
- // Add text prompt
250
254
  if (prompt != null) {
251
255
  userContent.push({ type: 'text', text: prompt });
252
256
  }
253
257
 
254
- // Add input images for editing
255
258
  if (files != null && files.length > 0) {
256
259
  for (const file of files) {
257
260
  if (file.type === 'url') {
258
261
  userContent.push({
259
262
  type: 'file',
260
- data: new URL(file.url),
263
+ data: { type: 'url', url: new URL(file.url) },
261
264
  mediaType: 'image/*',
262
265
  });
263
266
  } else {
264
267
  userContent.push({
265
268
  type: 'file',
266
- data:
267
- typeof file.data === 'string'
268
- ? file.data
269
- : new Uint8Array(file.data),
269
+ data: {
270
+ type: 'data',
271
+ data:
272
+ typeof file.data === 'string'
273
+ ? file.data
274
+ : new Uint8Array(file.data),
275
+ },
270
276
  mediaType: file.mediaType,
271
277
  });
272
278
  }
@@ -312,11 +318,14 @@ export class GoogleImageModel implements ImageModelV4 {
312
318
 
313
319
  const currentDate = this.config._internal?.currentDate?.() ?? new Date();
314
320
 
315
- // Extract images from language model response
316
321
  const images: string[] = [];
317
322
  for (const part of result.content) {
318
- if (part.type === 'file' && part.mediaType.startsWith('image/')) {
319
- images.push(convertToBase64(part.data));
323
+ if (
324
+ part.type === 'file' &&
325
+ part.mediaType.startsWith('image/') &&
326
+ part.data.type === 'data'
327
+ ) {
328
+ images.push(convertToBase64(part.data.data));
320
329
  }
321
330
  }
322
331
 
@@ -360,20 +369,3 @@ const googleImageResponseSchema = lazySchema(() =>
360
369
  }),
361
370
  ),
362
371
  );
363
-
364
- // Note: For the initial GA launch of Imagen 3, safety filters are not configurable.
365
- // https://ai.google.dev/gemini-api/docs/imagen#imagen-model
366
- const googleImageModelOptionsSchema = lazySchema(() =>
367
- zodSchema(
368
- z.object({
369
- personGeneration: z
370
- .enum(['dont_allow', 'allow_adult', 'allow_all'])
371
- .nullish(),
372
- aspectRatio: z.enum(['1:1', '3:4', '4:3', '9:16', '16:9']).nullish(),
373
- }),
374
- ),
375
- );
376
-
377
- export type GoogleImageModelOptions = InferSchema<
378
- typeof googleImageModelOptionsSchema
379
- >;
@@ -1,4 +1,8 @@
1
- import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
1
+ import {
2
+ lazySchema,
3
+ zodSchema,
4
+ type InferSchema,
5
+ } from '@ai-sdk/provider-utils';
2
6
  import { z } from 'zod/v4';
3
7
 
4
8
  export type GoogleModelId =