@ai-sdk/google 4.0.62 → 4.0.64

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.
@@ -68,11 +68,11 @@ You can use the following optional settings to customize the Google provider ins
68
68
  ## Language Models
69
69
 
70
70
  You can create models that call the [Google Generative AI API](https://ai.google.dev/api/rest) using the provider instance.
71
- The first argument is the model id, e.g. `gemini-3.7-flash`.
71
+ The first argument is the model id, e.g. `gemini-3.8-flash`.
72
72
  The models support tool calls and some have multi-modal capabilities.
73
73
 
74
74
  ```ts
75
- const model = google('gemini-3.7-flash');
75
+ const model = google('gemini-3.8-flash');
76
76
  ```
77
77
 
78
78
  You can use Google language models to generate text with the `generateText` function:
@@ -82,7 +82,7 @@ import { google } from '@ai-sdk/google';
82
82
  import { generateText } from 'ai';
83
83
 
84
84
  const { text } = await generateText({
85
- model: google('gemini-3.7-flash'),
85
+ model: google('gemini-3.8-flash'),
86
86
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
87
87
  });
88
88
  ```
@@ -107,7 +107,7 @@ You can pass them as an options argument:
107
107
  ```ts
108
108
  import { google, type GoogleLanguageModelOptions } from '@ai-sdk/google';
109
109
 
110
- const model = google('gemini-3.7-flash');
110
+ const model = google('gemini-3.8-flash');
111
111
 
112
112
  await generateText({
113
113
  model,
@@ -262,7 +262,7 @@ For Gemini 3 and later models, use the `thinkingLevel` parameter to control the
262
262
  import { google, GoogleLanguageModelOptions } from '@ai-sdk/google';
263
263
  import { generateText } from 'ai';
264
264
 
265
- const model = google('gemini-3.7-flash');
265
+ const model = google('gemini-3.8-flash');
266
266
 
267
267
  const { text, reasoning } = await generateText({
268
268
  model: model,
@@ -319,7 +319,7 @@ import { google } from '@ai-sdk/google';
319
319
  import { generateText } from 'ai';
320
320
 
321
321
  const result = await generateText({
322
- model: google('gemini-3.7-flash'),
322
+ model: google('gemini-3.8-flash'),
323
323
  messages: [
324
324
  {
325
325
  role: 'user',
@@ -346,7 +346,7 @@ import { google } from '@ai-sdk/google';
346
346
  import { generateText } from 'ai';
347
347
 
348
348
  const result = await generateText({
349
- model: google('gemini-3.7-flash'),
349
+ model: google('gemini-3.8-flash'),
350
350
  messages: [
351
351
  {
352
352
  role: 'user',
@@ -401,13 +401,13 @@ const baseContext =
401
401
  'You are a cooking assistant with expertise in Italian cuisine. Here are 1000 lasagna recipes for reference...';
402
402
 
403
403
  const { text: veggieLasagna } = await generateText({
404
- model: google('gemini-3.7-flash'),
404
+ model: google('gemini-3.8-flash'),
405
405
  prompt: `${baseContext}\n\nWrite a vegetarian lasagna recipe for 4 people.`,
406
406
  });
407
407
 
408
408
  // Second request with same prefix - eligible for cache hit
409
409
  const { text: meatLasagna, providerMetadata } = await generateText({
410
- model: google('gemini-3.7-flash'),
410
+ model: google('gemini-3.8-flash'),
411
411
  prompt: `${baseContext}\n\nWrite a meat lasagna recipe for 12 people.`,
412
412
  });
413
413
 
@@ -446,7 +446,7 @@ const ai = new GoogleGenAI({
446
446
  apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
447
447
  });
448
448
 
449
- const model = 'gemini-3.7-flash';
449
+ const model = 'gemini-3.8-flash';
450
450
 
451
451
  // Create a cache with the content you want to reuse
452
452
  const cache = await ai.caches.create({
@@ -495,7 +495,7 @@ import { googleTools } from '@ai-sdk/google/internal';
495
495
  import { generateText } from 'ai';
496
496
 
497
497
  const { text, toolCalls, toolResults } = await generateText({
498
- model: google('gemini-3.7-flash'),
498
+ model: google('gemini-3.8-flash'),
499
499
  tools: { code_execution: google.tools.codeExecution({}) },
500
500
  prompt: 'Use python to calculate the 20th fibonacci number.',
501
501
  });
@@ -514,7 +514,7 @@ import { GoogleProviderMetadata } from '@ai-sdk/google';
514
514
  import { generateText } from 'ai';
515
515
 
516
516
  const { text, sources, providerMetadata } = await generateText({
517
- model: google('gemini-3.7-flash'),
517
+ model: google('gemini-3.8-flash'),
518
518
  tools: {
519
519
  google_search: google.tools.googleSearch({}),
520
520
  },
@@ -622,7 +622,7 @@ const vertex = createGoogleVertex({
622
622
  });
623
623
 
624
624
  const { text, sources, providerMetadata } = await generateText({
625
- model: vertex('gemini-3.7-flash'),
625
+ model: vertex('gemini-3.8-flash'),
626
626
  tools: {
627
627
  enterprise_web_search: vertex.tools.enterpriseWebSearch({}),
628
628
  },
@@ -645,7 +645,7 @@ import { google } from '@ai-sdk/google';
645
645
  import { generateText } from 'ai';
646
646
 
647
647
  const { text, sources } = await generateText({
648
- model: google('gemini-3.7-flash'),
648
+ model: google('gemini-3.8-flash'),
649
649
  tools: {
650
650
  file_search: google.tools.fileSearch({
651
651
  fileSearchStoreNames: [
@@ -672,7 +672,7 @@ import { google } from '@ai-sdk/google';
672
672
  import { generateText } from 'ai';
673
673
 
674
674
  const { text, sources, providerMetadata } = await generateText({
675
- model: google('gemini-3.7-flash'),
675
+ model: google('gemini-3.8-flash'),
676
676
  prompt: `Based on the document: https://ai.google.dev/gemini-api/docs/url-context.
677
677
  Answer this question: How many links we can consume in one request?`,
678
678
  tools: {
@@ -750,7 +750,7 @@ import { google } from '@ai-sdk/google';
750
750
  import { generateText } from 'ai';
751
751
 
752
752
  const { text, sources, providerMetadata } = await generateText({
753
- model: google('gemini-3.7-flash'),
753
+ model: google('gemini-3.8-flash'),
754
754
  prompt: `Based on this context: https://ai-sdk.dev/providers/ai-sdk-providers/google, tell me how to use Gemini with AI SDK.
755
755
  Also, provide the latest news about AI SDK V5.`,
756
756
  tools: {
@@ -775,7 +775,7 @@ import { GoogleProviderMetadata } from '@ai-sdk/google';
775
775
  import { generateText } from 'ai';
776
776
 
777
777
  const { text, sources, providerMetadata } = await generateText({
778
- model: google('gemini-3.7-flash'),
778
+ model: google('gemini-3.8-flash'),
779
779
  tools: {
780
780
  google_maps: google.tools.googleMaps({}),
781
781
  },
@@ -839,7 +839,7 @@ const vertex = createGoogleVertex({
839
839
  });
840
840
 
841
841
  const { text, sources, providerMetadata } = await generateText({
842
- model: vertex('gemini-3.7-flash'),
842
+ model: vertex('gemini-3.8-flash'),
843
843
  tools: {
844
844
  vertex_rag_store: vertex.tools.vertexRagStore({
845
845
  ragCorpus:
@@ -1006,7 +1006,7 @@ You can disable structured outputs for object generation as a workaround:
1006
1006
 
1007
1007
  ```ts highlight="3,8"
1008
1008
  const { output } = await generateText({
1009
- model: google('gemini-3.7-flash'),
1009
+ model: google('gemini-3.8-flash'),
1010
1010
  providerOptions: {
1011
1011
  google: {
1012
1012
  structuredOutputs: false,
@@ -1041,6 +1041,7 @@ The following Zod features are known to not work with Google:
1041
1041
 
1042
1042
  | Model | Image Input | Object Generation | Tool Usage | Tool Streaming | Google Search | URL Context |
1043
1043
  | ------------------------------------- | ----------- | ----------------- | ---------- | -------------- | ------------- | ----------- |
1044
+ | `gemini-3.8-flash` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
1044
1045
  | `gemini-3.7-flash` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
1045
1046
  | `gemini-3.6-flash` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
1046
1047
  | `gemini-3.5-flash` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
@@ -1270,13 +1271,13 @@ import { google } from '@ai-sdk/google';
1270
1271
  import { generateText } from 'ai';
1271
1272
 
1272
1273
  const { text } = await generateText({
1273
- model: google.interactions('gemini-3.7-flash'),
1274
+ model: google.interactions('gemini-3.8-flash'),
1274
1275
  prompt: 'Hello, how are you?',
1275
1276
  });
1276
1277
  ```
1277
1278
 
1278
1279
  `google.interactions(...)` accepts a model ID string (e.g.
1279
- `'gemini-3.7-flash'`, `'gemini-3.1-pro-preview'`), `{ agent: <name> }` to use
1280
+ `'gemini-3.8-flash'`, `'gemini-3.1-pro-preview'`), `{ agent: <name> }` to use
1280
1281
  a Gemini [agent preset](#agent-presets), or `{ managedAgent: <name> }` to
1281
1282
  invoke a [managed agent](#managed-agents) you created on Google's side.
1282
1283
  The returned model can be passed to `generateText` and `streamText` like
@@ -1303,7 +1304,7 @@ import {
1303
1304
  import { generateText } from 'ai';
1304
1305
 
1305
1306
  await generateText({
1306
- model: google.interactions('gemini-3.7-flash'),
1307
+ model: google.interactions('gemini-3.8-flash'),
1307
1308
  prompt: 'What color is the sky in one word?',
1308
1309
  providerOptions: {
1309
1310
  google: {
@@ -1452,7 +1453,20 @@ exposes:
1452
1453
  - **signature** _string_
1453
1454
 
1454
1455
  Per-block signature hash, set by the SDK on output reasoning and
1455
- tool-call parts. Round-tripped automatically on the next turn.
1456
+ tool-call or agentic video processing parts. Round-tripped automatically on
1457
+ the next turn.
1458
+
1459
+ Agentic video custom parts additionally expose:
1460
+
1461
+ - **processingId** _string_
1462
+
1463
+ ID of an agentic video `processing_call`. Present on
1464
+ `google.processing_call` custom parts.
1465
+
1466
+ - **processingCallId** _string_
1467
+
1468
+ ID of the matching agentic video processing call. Present on
1469
+ `google.processing_result` custom parts.
1456
1470
 
1457
1471
  ### Stateful chaining
1458
1472
 
@@ -1468,7 +1482,7 @@ import {
1468
1482
  import { generateText } from 'ai';
1469
1483
 
1470
1484
  const turn1 = await generateText({
1471
- model: google.interactions('gemini-3.7-flash'),
1485
+ model: google.interactions('gemini-3.8-flash'),
1472
1486
  prompt: 'What are the three largest cities in Spain?',
1473
1487
  });
1474
1488
 
@@ -1477,7 +1491,7 @@ const interactionId = turn1.providerMetadata?.google?.interactionId as
1477
1491
  | undefined;
1478
1492
 
1479
1493
  const turn2 = await generateText({
1480
- model: google.interactions('gemini-3.7-flash'),
1494
+ model: google.interactions('gemini-3.8-flash'),
1481
1495
  prompt: 'What is the most famous landmark in the second one?',
1482
1496
  providerOptions: {
1483
1497
  google: {
@@ -1502,7 +1516,7 @@ const messages: Array<ModelMessage> = [
1502
1516
  ];
1503
1517
 
1504
1518
  const turn1 = await generateText({
1505
- model: google.interactions('gemini-3.7-flash'),
1519
+ model: google.interactions('gemini-3.8-flash'),
1506
1520
  messages,
1507
1521
  providerOptions: {
1508
1522
  google: { store: false } satisfies GoogleLanguageModelInteractionsOptions,
@@ -1516,7 +1530,7 @@ messages.push({
1516
1530
  });
1517
1531
 
1518
1532
  const turn2 = await generateText({
1519
- model: google.interactions('gemini-3.7-flash'),
1533
+ model: google.interactions('gemini-3.8-flash'),
1520
1534
  messages,
1521
1535
  providerOptions: {
1522
1536
  google: { store: false } satisfies GoogleLanguageModelInteractionsOptions,
@@ -1524,6 +1538,97 @@ const turn2 = await generateText({
1524
1538
  });
1525
1539
  ```
1526
1540
 
1541
+ ### Agentic video understanding
1542
+
1543
+ Gemini 3.7 Flash, 3.6 Flash, and 3.5 Flash Lite support agentic video
1544
+ understanding through the Interactions API. Instead of sampling the entire
1545
+ video at a fixed frame rate, the model dynamically navigates the timeline and
1546
+ loads the transcripts, frames, or audio needed for the prompt.
1547
+
1548
+ Set `processing: 'agentic'` in the Google provider options of an individual
1549
+ video file part. You can validate the per-file options with
1550
+ `GoogleInteractionsVideoOptions`:
1551
+
1552
+ ```ts
1553
+ import { google, type GoogleInteractionsVideoOptions } from '@ai-sdk/google';
1554
+ import { generateText } from 'ai';
1555
+
1556
+ const result = await generateText({
1557
+ model: google.interactions('gemini-3.7-flash'),
1558
+ messages: [
1559
+ {
1560
+ role: 'user',
1561
+ content: [
1562
+ {
1563
+ type: 'file',
1564
+ data: 'https://www.youtube.com/watch?v=9hE5-98ZeCg',
1565
+ mediaType: 'video',
1566
+ providerOptions: {
1567
+ google: {
1568
+ processing: 'agentic',
1569
+ } satisfies GoogleInteractionsVideoOptions,
1570
+ },
1571
+ },
1572
+ {
1573
+ type: 'text',
1574
+ text: 'Identify the three most important moments and include timestamps.',
1575
+ },
1576
+ ],
1577
+ },
1578
+ ],
1579
+ providerOptions: {
1580
+ google: {
1581
+ thinkingSummaries: 'auto',
1582
+ },
1583
+ },
1584
+ });
1585
+
1586
+ const processingSteps = result.content.filter(
1587
+ part =>
1588
+ part.type === 'custom' &&
1589
+ (part.kind === 'google.processing_call' ||
1590
+ part.kind === 'google.processing_result'),
1591
+ );
1592
+ ```
1593
+
1594
+ Agentic navigation is exposed as `custom` content parts:
1595
+
1596
+ - `google.processing_call` marks a request by the model to inspect part of the
1597
+ video. Its `providerMetadata.google.processingId` contains the processing ID.
1598
+ - `google.processing_result` marks completion of that request. Its
1599
+ `providerMetadata.google.processingCallId` links it to the processing call.
1600
+
1601
+ These parts are informational and do not require a tool response. They are
1602
+ available from both `generateText` and `streamText`.
1603
+
1604
+ For static processing, use `'static'` or provide clipping and frame-rate
1605
+ options:
1606
+
1607
+ ```ts
1608
+ const video = {
1609
+ type: 'file' as const,
1610
+ data: videoBytes,
1611
+ mediaType: 'video/mp4',
1612
+ providerOptions: {
1613
+ google: {
1614
+ processing: {
1615
+ type: 'static',
1616
+ startOffset: 1200,
1617
+ endOffset: 1500,
1618
+ fps: 0.5,
1619
+ },
1620
+ } satisfies GoogleInteractionsVideoOptions,
1621
+ },
1622
+ };
1623
+ ```
1624
+
1625
+ With stateful conversations, pass the returned `interactionId` as
1626
+ `previousInteractionId`; Gemini retains the video context server-side. With
1627
+ `store: false`, append `result.responseMessages` and re-send the full history.
1628
+ The processing custom parts and their signatures are then round-tripped as
1629
+ native `processing_call` and `processing_result` steps so the video context is
1630
+ preserved.
1631
+
1527
1632
  ### Built-in Tools
1528
1633
 
1529
1634
  The Interactions API ships a built-in tool catalog. The provider-defined
@@ -1549,7 +1654,7 @@ import { google } from '@ai-sdk/google';
1549
1654
  import { generateText } from 'ai';
1550
1655
 
1551
1656
  const { text, sources } = await generateText({
1552
- model: google.interactions('gemini-3.7-flash'),
1657
+ model: google.interactions('gemini-3.8-flash'),
1553
1658
  tools: {
1554
1659
  google_search: google.tools.googleSearch({}),
1555
1660
  },
@@ -1573,7 +1678,7 @@ const weatherTool = tool({
1573
1678
  });
1574
1679
 
1575
1680
  const { text, toolCalls } = await generateText({
1576
- model: google.interactions('gemini-3.7-flash'),
1681
+ model: google.interactions('gemini-3.8-flash'),
1577
1682
  tools: { getWeather: weatherTool },
1578
1683
  stopWhen: isStepCount(5),
1579
1684
  prompt: 'What is the weather in San Francisco right now?',
@@ -1872,7 +1977,7 @@ import { google } from '@ai-sdk/google';
1872
1977
  import { streamText } from 'ai';
1873
1978
 
1874
1979
  const result = streamText({
1875
- model: google.interactions('gemini-3.7-flash'),
1980
+ model: google.interactions('gemini-3.8-flash'),
1876
1981
  prompt: 'Hello, how are you?',
1877
1982
  });
1878
1983
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "4.0.62",
3
+ "version": "4.0.64",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -91,6 +91,8 @@ function convertJSONSchemaDefinition(
91
91
  format,
92
92
  const: constValue,
93
93
  minLength,
94
+ minItems,
95
+ maxItems,
94
96
  enum: enumValues,
95
97
  } = jsonSchema;
96
98
 
@@ -196,6 +198,14 @@ function convertJSONSchemaDefinition(
196
198
  result.minLength = minLength;
197
199
  }
198
200
 
201
+ if (minItems !== undefined) {
202
+ result.minItems = minItems;
203
+ }
204
+
205
+ if (maxItems !== undefined) {
206
+ result.maxItems = maxItems;
207
+ }
208
+
199
209
  return result;
200
210
  }
201
211
 
@@ -105,6 +105,7 @@ const googleFileUploadResponseSchema = lazySchema(() =>
105
105
  z.object({
106
106
  file: z.object({
107
107
  name: z.string(),
108
+ expirationTime: z.string().nullish(),
108
109
  }),
109
110
  }),
110
111
  ),
@@ -243,10 +244,9 @@ export class GoogleBatchLanguageModel
243
244
  const createUrl = `${this.batchConfig.baseURL}/${getModelPath(
244
245
  this.modelId,
245
246
  )}:batchGenerateContent`;
246
- let operation: GoogleBatchOperation;
247
247
 
248
248
  if (fileParts == null) {
249
- const { value } = await postJsonToApi({
249
+ const { value: operation } = await postJsonToApi({
250
250
  url: createUrl,
251
251
  headers,
252
252
  body: inlineBatchBody,
@@ -257,86 +257,98 @@ export class GoogleBatchLanguageModel
257
257
  abortSignal: options.abortSignal,
258
258
  fetch: this.batchConfig.fetch,
259
259
  });
260
- operation = value;
261
- } else {
262
- const inputFile = new Blob(fileParts, { type: 'application/jsonl' });
263
- // Blob snapshots the strings, so release the potentially large input array.
264
- fileParts.length = 0;
265
- if (inputFile.size > googleBatchInputFileMaxBytes) {
266
- throw new InvalidArgumentError({
267
- argument: 'requests',
268
- message: 'Google batch input files must not exceed 2 GB.',
269
- });
270
- }
271
260
 
272
- const { value: uploadUrl } = await postJsonToApi({
273
- url: `${this.getBaseOrigin()}/upload/v1beta/files`,
274
- headers: combineHeaders(headers, {
275
- 'X-Goog-Upload-Protocol': 'resumable',
276
- 'X-Goog-Upload-Command': 'start',
277
- 'X-Goog-Upload-Header-Content-Length': String(inputFile.size),
278
- 'X-Goog-Upload-Header-Content-Type': 'application/jsonl',
279
- }),
280
- body: {
281
- file: {
282
- display_name: `${displayName}-input`,
283
- },
284
- },
285
- failedResponseHandler: googleFailedResponseHandler,
286
- successfulResponseHandler: googleUploadUrlResponseHandler,
287
- abortSignal: options.abortSignal,
288
- fetch: this.batchConfig.fetch,
261
+ return {
262
+ batchId: operation.name,
263
+ ...convertGoogleBatchStatus(operation),
264
+ warnings,
265
+ };
266
+ }
267
+
268
+ const inputFile = new Blob(fileParts, { type: 'application/jsonl' });
269
+ // Blob snapshots the strings, so release the potentially large input array.
270
+ fileParts.length = 0;
271
+ if (inputFile.size > googleBatchInputFileMaxBytes) {
272
+ throw new InvalidArgumentError({
273
+ argument: 'requests',
274
+ message: 'Google batch input files must not exceed 2 GB.',
289
275
  });
276
+ }
290
277
 
291
- const { value: uploadedFile } = await postToApi({
292
- url: uploadUrl,
293
- headers: {
294
- 'X-Goog-Upload-Offset': '0',
295
- 'X-Goog-Upload-Command': 'upload, finalize',
296
- 'Content-Type': 'application/jsonl',
278
+ const { value: uploadUrl } = await postJsonToApi({
279
+ url: `${this.getBaseOrigin()}/upload/v1beta/files`,
280
+ headers: combineHeaders(headers, {
281
+ 'X-Goog-Upload-Protocol': 'resumable',
282
+ 'X-Goog-Upload-Command': 'start',
283
+ 'X-Goog-Upload-Header-Content-Length': String(inputFile.size),
284
+ 'X-Goog-Upload-Header-Content-Type': 'application/jsonl',
285
+ }),
286
+ body: {
287
+ file: {
288
+ display_name: `${displayName}-input`,
297
289
  },
298
- body: {
299
- content: inputFile,
300
- values: {
301
- byteLength: inputFile.size,
302
- mediaType: 'application/jsonl',
303
- },
290
+ },
291
+ failedResponseHandler: googleFailedResponseHandler,
292
+ successfulResponseHandler: googleUploadUrlResponseHandler,
293
+ abortSignal: options.abortSignal,
294
+ fetch: this.batchConfig.fetch,
295
+ });
296
+
297
+ const { value: uploadedFile } = await postToApi({
298
+ url: uploadUrl,
299
+ headers: {
300
+ 'X-Goog-Upload-Offset': '0',
301
+ 'X-Goog-Upload-Command': 'upload, finalize',
302
+ 'Content-Type': 'application/jsonl',
303
+ },
304
+ body: {
305
+ content: inputFile,
306
+ values: {
307
+ byteLength: inputFile.size,
308
+ mediaType: 'application/jsonl',
304
309
  },
305
- failedResponseHandler: googleFailedResponseHandler,
306
- successfulResponseHandler: createJsonResponseHandler(
307
- googleFileUploadResponseSchema,
308
- ),
309
- abortSignal: options.abortSignal,
310
- fetch: this.batchConfig.fetch,
311
- });
310
+ },
311
+ failedResponseHandler: googleFailedResponseHandler,
312
+ successfulResponseHandler: createJsonResponseHandler(
313
+ googleFileUploadResponseSchema,
314
+ ),
315
+ abortSignal: options.abortSignal,
316
+ fetch: this.batchConfig.fetch,
317
+ });
312
318
 
313
- const { value } = await postJsonToApi({
314
- url: createUrl,
315
- headers,
316
- body: {
317
- batch: {
318
- displayName,
319
- ...(options.webhookUrl != null && {
320
- webhookConfig: { uris: [options.webhookUrl] },
321
- }),
322
- inputConfig: {
323
- fileName: uploadedFile.file.name,
324
- },
319
+ const { value: operation } = await postJsonToApi({
320
+ url: createUrl,
321
+ headers,
322
+ body: {
323
+ batch: {
324
+ displayName,
325
+ ...(options.webhookUrl != null && {
326
+ webhookConfig: { uris: [options.webhookUrl] },
327
+ }),
328
+ inputConfig: {
329
+ fileName: uploadedFile.file.name,
325
330
  },
326
331
  },
327
- failedResponseHandler: googleFailedResponseHandler,
328
- successfulResponseHandler: createJsonResponseHandler(
329
- googleBatchOperationSchema,
330
- ),
331
- abortSignal: options.abortSignal,
332
- fetch: this.batchConfig.fetch,
333
- });
334
- operation = value;
335
- }
332
+ },
333
+ failedResponseHandler: googleFailedResponseHandler,
334
+ successfulResponseHandler: createJsonResponseHandler(
335
+ googleBatchOperationSchema,
336
+ ),
337
+ abortSignal: options.abortSignal,
338
+ fetch: this.batchConfig.fetch,
339
+ });
336
340
 
337
341
  return {
338
342
  batchId: operation.name,
339
343
  ...convertGoogleBatchStatus(operation),
344
+ providerMetadata: {
345
+ google: {
346
+ inputFileId: uploadedFile.file.name,
347
+ ...(uploadedFile.file.expirationTime != null
348
+ ? { inputFileExpiresAt: uploadedFile.file.expirationTime }
349
+ : {}),
350
+ },
351
+ },
340
352
  warnings,
341
353
  };
342
354
  }
@@ -34,6 +34,7 @@ export type GoogleModelId =
34
34
  | 'gemini-3.5-flash-lite'
35
35
  | 'gemini-3.6-flash'
36
36
  | 'gemini-3.7-flash'
37
+ | 'gemini-3.8-flash'
37
38
  // latest version
38
39
  // https://ai.google.dev/gemini-api/docs/models#latest
39
40
  | 'gemini-pro-latest'