@ai-sdk/google 4.0.63 → 4.0.65

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.
@@ -1081,27 +1081,37 @@ import { google } from '@ai-sdk/google';
1081
1081
  import {
1082
1082
  experimental_getBatchResults as getBatchResults,
1083
1083
  experimental_getBatchStatus as getBatchStatus,
1084
- experimental_startTextBatch as startTextBatch,
1084
+ experimental_startBatch as startBatch,
1085
1085
  } from 'ai';
1086
1086
  import { setTimeout } from 'node:timers/promises';
1087
1087
 
1088
- const model = google('gemini-3.6-flash');
1088
+ const model = 'gemini-3.6-flash';
1089
1089
 
1090
- const batch = await startTextBatch({
1091
- model,
1090
+ const batch = await startBatch({
1091
+ provider: google,
1092
1092
  requests: [
1093
- { id: 'capital-france', prompt: 'What is the capital of France?' },
1094
- { id: 'capital-germany', prompt: 'What is the capital of Germany?' },
1093
+ {
1094
+ id: 'capital-france',
1095
+ type: 'text',
1096
+ model,
1097
+ prompt: 'What is the capital of France?',
1098
+ },
1099
+ {
1100
+ id: 'capital-germany',
1101
+ type: 'text',
1102
+ model,
1103
+ prompt: 'What is the capital of Germany?',
1104
+ },
1095
1105
  ],
1096
1106
  });
1097
1107
 
1098
1108
  let status = batch.status;
1099
1109
  while (status === 'pending') {
1100
1110
  await setTimeout(60_000);
1101
- ({ status } = await getBatchStatus({ model, batch }));
1111
+ ({ status } = await getBatchStatus({ provider: google, batch }));
1102
1112
  }
1103
1113
 
1104
- for await (const item of getBatchResults({ model, batch })) {
1114
+ for await (const item of getBatchResults({ provider: google, batch })) {
1105
1115
  if (item.status === 'succeeded') {
1106
1116
  console.log(item.id, item.text);
1107
1117
  } else {
@@ -1110,21 +1120,35 @@ for await (const item of getBatchResults({ model, batch })) {
1110
1120
  }
1111
1121
  ```
1112
1122
 
1113
- `startTextBatch` returns a serializable batch reference. Persist this reference
1123
+ `startBatch` returns a serializable batch reference. Persist this reference
1114
1124
  to check the batch status or retrieve its results from another process. Results
1115
1125
  can arrive in a different order from the input requests, so match each result by
1116
1126
  its `id`.
1117
1127
 
1128
+ Each request specifies its `type` and `model`. Google requires every text
1129
+ request in a batch to use the same model and throws before submission when the
1130
+ models differ.
1131
+
1118
1132
  #### Webhooks
1119
1133
 
1120
1134
  You can pass a `webhookUrl` to receive a notification when the batch reaches a terminal state:
1121
1135
 
1122
1136
  ```ts
1123
- const batch = await startTextBatch({
1124
- model,
1137
+ const batch = await startBatch({
1138
+ provider: google,
1125
1139
  requests: [
1126
- { id: 'capital-france', prompt: 'What is the capital of France?' },
1127
- { id: 'capital-germany', prompt: 'What is the capital of Germany?' },
1140
+ {
1141
+ id: 'capital-france',
1142
+ type: 'text',
1143
+ model,
1144
+ prompt: 'What is the capital of France?',
1145
+ },
1146
+ {
1147
+ id: 'capital-germany',
1148
+ type: 'text',
1149
+ model,
1150
+ prompt: 'What is the capital of Germany?',
1151
+ },
1128
1152
  ],
1129
1153
  webhookUrl: 'https://example.com/api/google-batch-webhook',
1130
1154
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "4.0.63",
3
+ "version": "4.0.65",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.10",
39
- "@ai-sdk/provider-utils": "5.0.36"
38
+ "@ai-sdk/provider": "4.0.11",
39
+ "@ai-sdk/provider-utils": "5.0.37"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.1",
@@ -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
 
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  InvalidArgumentError,
3
3
  InvalidResponseDataError,
4
- type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
4
+ type Experimental_BatchV4 as BatchV4,
5
5
  type Experimental_BatchV4Error as BatchV4Error,
6
6
  type Experimental_BatchV4ItemResult as BatchV4ItemResult,
7
7
  type Experimental_BatchV4OperationOptions as BatchV4OperationOptions,
8
- type Experimental_BatchV4StartOptions as BatchV4StartOptions,
9
8
  type Experimental_BatchV4StartResult as BatchV4StartResult,
10
9
  type Experimental_BatchV4Status as BatchV4Status,
10
+ type Experimental_TextBatchV4Request as TextBatchV4Request,
11
+ type Experimental_BatchV4StartOptions as BatchV4StartOptions,
11
12
  type LanguageModelV4GenerateResult,
12
13
  } from '@ai-sdk/provider';
13
14
  import {
@@ -23,8 +24,6 @@ import {
23
24
  postToApi,
24
25
  resolve,
25
26
  safeValidateTypes,
26
- WORKFLOW_DESERIALIZE,
27
- WORKFLOW_SERIALIZE,
28
27
  zodSchema,
29
28
  type InferSchema,
30
29
  type ResponseHandler,
@@ -45,9 +44,7 @@ const supportedGoogleBatchContentTypes = new Set<
45
44
  LanguageModelV4GenerateResult['content'][number]['type']
46
45
  >(['text', 'reasoning', 'source', 'tool-call', 'tool-result']);
47
46
 
48
- type GoogleBatchRequest = Parameters<
49
- BatchLanguageModelV4['experimental_doStartBatch']
50
- >[0]['requests'][number];
47
+ type GoogleBatchRequest = TextBatchV4Request<GoogleModelId>;
51
48
 
52
49
  const googleRpcStatusSchema = z.object({
53
50
  code: z.union([z.number(), z.string()]).nullish(),
@@ -136,33 +133,28 @@ const googleBatchResponsePreviewSchema = lazySchema(() =>
136
133
  ),
137
134
  );
138
135
 
139
- export class GoogleBatchLanguageModel
140
- extends GoogleLanguageModel
141
- implements BatchLanguageModelV4
142
- {
136
+ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
137
+ readonly specificationVersion = 'v4' as const;
138
+ readonly provider: string;
139
+ readonly supportedUrls: Record<string, RegExp[]>;
143
140
  private readonly batchConfig: GoogleLanguageModelConfig;
144
141
  private readonly batchGenerateId: () => string;
145
142
 
146
- static [WORKFLOW_SERIALIZE](model: GoogleLanguageModel) {
147
- return GoogleLanguageModel[WORKFLOW_SERIALIZE](model);
148
- }
149
-
150
- static [WORKFLOW_DESERIALIZE](options: {
151
- modelId: string;
143
+ constructor(options: {
144
+ provider: string;
152
145
  config: GoogleLanguageModelConfig;
146
+ supportedUrls: Record<string, RegExp[]>;
153
147
  }) {
154
- return new GoogleBatchLanguageModel(options.modelId, options.config);
155
- }
156
-
157
- constructor(modelId: GoogleModelId, config: GoogleLanguageModelConfig) {
158
- super(modelId, config);
159
- this.batchConfig = config;
160
- this.batchGenerateId = config.generateId ?? generateId;
148
+ this.provider = options.provider;
149
+ this.batchConfig = options.config;
150
+ this.supportedUrls = options.supportedUrls;
151
+ this.batchGenerateId = options.config.generateId ?? generateId;
161
152
  }
162
153
 
163
- async experimental_doStartBatch(
164
- options: BatchV4StartOptions<GoogleBatchRequest>,
154
+ async doStartBatch(
155
+ options: BatchV4StartOptions<{ text: GoogleModelId }>,
165
156
  ): Promise<BatchV4StartResult> {
157
+ const modelId = getGoogleBatchModelId(options.requests);
166
158
  const warnings: BatchV4StartResult['warnings'] = [];
167
159
  const displayName = `ai-sdk-batch-${this.batchGenerateId()}`;
168
160
  const inlinedRequests: Array<{
@@ -187,7 +179,11 @@ export class GoogleBatchLanguageModel
187
179
  let fileParts: string[] | undefined;
188
180
 
189
181
  for (const request of options.requests) {
190
- const preparedRequest = await this.getArgs(request.options);
182
+ const preparedRequest = await GoogleLanguageModel.prepareRequest({
183
+ modelId: request.modelId,
184
+ config: this.batchConfig,
185
+ options: request.options,
186
+ });
191
187
  const inlinedRequest = {
192
188
  request: preparedRequest.args,
193
189
  metadata: { key: request.id },
@@ -242,7 +238,7 @@ export class GoogleBatchLanguageModel
242
238
 
243
239
  const headers = await this.getHeaders(options.headers);
244
240
  const createUrl = `${this.batchConfig.baseURL}/${getModelPath(
245
- this.modelId,
241
+ modelId,
246
242
  )}:batchGenerateContent`;
247
243
 
248
244
  if (fileParts == null) {
@@ -353,15 +349,15 @@ export class GoogleBatchLanguageModel
353
349
  };
354
350
  }
355
351
 
356
- async experimental_doGetBatchStatus(
352
+ async doGetBatchStatus(
357
353
  options: BatchV4OperationOptions,
358
354
  ): Promise<BatchV4Status> {
359
355
  return convertGoogleBatchStatus(await this.retrieveBatch(options));
360
356
  }
361
357
 
362
- async experimental_doGetBatchResults(
358
+ async doGetBatchResults(
363
359
  options: BatchV4OperationOptions,
364
- ): Promise<ReadableStream<BatchV4ItemResult<LanguageModelV4GenerateResult>>> {
360
+ ): Promise<ReadableStream<BatchV4ItemResult>> {
365
361
  const operation = await this.retrieveBatch(options);
366
362
  const batchStatus = convertGoogleBatchStatus(operation);
367
363
 
@@ -450,7 +446,7 @@ export class GoogleBatchLanguageModel
450
446
  results:
451
447
  | Iterable<GoogleBatchResultLine>
452
448
  | AsyncIterable<GoogleBatchResultLine>,
453
- ): AsyncGenerator<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
449
+ ): AsyncGenerator<BatchV4ItemResult> {
454
450
  for await (const line of results) {
455
451
  if (line.error != null) {
456
452
  const error = convertGoogleRpcError(
@@ -462,12 +458,13 @@ export class GoogleBatchLanguageModel
462
458
  ? 'cancelled'
463
459
  : 'failed';
464
460
 
465
- yield { id: line.key, status, error };
461
+ yield { type: 'text', id: line.key, status, error };
466
462
  continue;
467
463
  }
468
464
 
469
465
  if (line.response == null) {
470
466
  yield {
467
+ type: 'text',
471
468
  id: line.key,
472
469
  status: 'failed',
473
470
  error: {
@@ -491,6 +488,7 @@ export class GoogleBatchLanguageModel
491
488
  const promptFeedback = preview.value.promptFeedback ?? undefined;
492
489
  const blockReason = promptFeedback?.blockReason ?? undefined;
493
490
  yield {
491
+ type: 'text',
494
492
  id: line.key,
495
493
  status: 'failed',
496
494
  error: {
@@ -522,6 +520,7 @@ export class GoogleBatchLanguageModel
522
520
  });
523
521
  if (!response.success) {
524
522
  yield {
523
+ type: 'text',
525
524
  id: line.key,
526
525
  status: 'failed',
527
526
  error: {
@@ -532,7 +531,8 @@ export class GoogleBatchLanguageModel
532
531
  continue;
533
532
  }
534
533
 
535
- const result = this.convertGenerateContentResponse({
534
+ const result = GoogleLanguageModel.convertGenerateContentResponse({
535
+ config: this.batchConfig,
536
536
  response: response.value,
537
537
  warnings: [],
538
538
  providerOptionsNames: ['google'],
@@ -543,6 +543,7 @@ export class GoogleBatchLanguageModel
543
543
 
544
544
  if (unsupportedPart != null) {
545
545
  yield {
546
+ type: 'text',
546
547
  id: line.key,
547
548
  status: 'failed',
548
549
  error: {
@@ -555,7 +556,7 @@ export class GoogleBatchLanguageModel
555
556
  continue;
556
557
  }
557
558
 
558
- yield { id: line.key, status: 'succeeded', result };
559
+ yield { type: 'text', id: line.key, status: 'succeeded', result };
559
560
  }
560
561
  }
561
562
 
@@ -680,3 +681,28 @@ const googleUploadUrlResponseHandler: ResponseHandler<string> = async ({
680
681
 
681
682
  return { value: uploadUrl };
682
683
  };
684
+
685
+ function getGoogleBatchModelId(
686
+ requests: readonly GoogleBatchRequest[],
687
+ ): GoogleModelId {
688
+ const modelId = requests[0]?.modelId;
689
+
690
+ if (modelId == null) {
691
+ throw new InvalidArgumentError({
692
+ argument: 'requests',
693
+ message: 'Google batches require at least one request.',
694
+ });
695
+ }
696
+
697
+ for (const request of requests) {
698
+ if (request.modelId !== modelId) {
699
+ throw new InvalidArgumentError({
700
+ argument: 'requests',
701
+ message:
702
+ 'Google batches require every request to use the same model because the model is part of the batch endpoint.',
703
+ });
704
+ }
705
+ }
706
+
707
+ return modelId;
708
+ }
@@ -243,6 +243,9 @@ export class GoogleImageModel implements ImageModelV4 {
243
243
 
244
244
  return {
245
245
  images,
246
+ ...(result.finishReason.unified === 'content-filter'
247
+ ? { isRetryable: false }
248
+ : {}),
246
249
  warnings,
247
250
  providerMetadata: {
248
251
  google: {
@@ -13,6 +13,7 @@ import type {
13
13
  } from '@ai-sdk/provider';
14
14
  import {
15
15
  combineHeaders,
16
+ createToolNameMapping,
16
17
  createEventSourceResponseHandler,
17
18
  createJsonResponseHandler,
18
19
  generateId,
@@ -113,8 +114,10 @@ export class GoogleLanguageModel implements LanguageModelV4 {
113
114
  return this.config.supportedUrls?.() ?? {};
114
115
  }
115
116
 
116
- protected async getArgs(
117
- {
117
+ static async prepareRequest({
118
+ modelId,
119
+ config,
120
+ options: {
118
121
  prompt,
119
122
  maxOutputTokens,
120
123
  temperature,
@@ -129,19 +132,25 @@ export class GoogleLanguageModel implements LanguageModelV4 {
129
132
  toolChoice,
130
133
  reasoning,
131
134
  providerOptions,
132
- }: LanguageModelV4CallOptions,
133
- { isStreaming = false }: { isStreaming?: boolean } = {},
134
- ) {
135
+ },
136
+ isStreaming = false,
137
+ }: {
138
+ modelId: GoogleModelId;
139
+ config: GoogleLanguageModelConfig;
140
+ options: LanguageModelV4CallOptions;
141
+ isStreaming?: boolean;
142
+ }) {
135
143
  const warnings: SharedV4Warning[] = [];
136
144
 
137
145
  // Names to look up in providerOptions and to write into providerMetadata.
138
146
  // For the Vertex provider we read both the new `googleVertex` key and the
139
147
  // legacy `vertex` key (new takes precedence) and write under both for
140
148
  // backward compatibility. For other Google providers we use just `google`.
141
- const providerOptionsNames: readonly string[] =
142
- this.config.provider.includes('vertex')
143
- ? (['googleVertex', 'vertex'] as const)
144
- : (['google'] as const);
149
+ const providerOptionsNames: readonly string[] = config.provider.includes(
150
+ 'vertex',
151
+ )
152
+ ? (['googleVertex', 'vertex'] as const)
153
+ : (['google'] as const);
145
154
 
146
155
  let googleOptions: GoogleLanguageModelOptions | undefined;
147
156
  for (const name of providerOptionsNames) {
@@ -164,7 +173,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
164
173
  }
165
174
 
166
175
  // Add warning if Vertex rag tools are used with a non-Vertex Google provider
167
- const isVertexProvider = this.config.provider.startsWith('google.vertex.');
176
+ const isVertexProvider = config.provider.startsWith('google.vertex.');
168
177
 
169
178
  if (
170
179
  tools?.some(
@@ -178,7 +187,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
178
187
  message:
179
188
  "The 'vertex_rag_store' tool is only supported with the Google Vertex provider " +
180
189
  'and might not be supported or could behave unexpectedly with the current Google provider ' +
181
- `(${this.config.provider}).`,
190
+ `(${config.provider}).`,
182
191
  });
183
192
  }
184
193
 
@@ -188,7 +197,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
188
197
  message:
189
198
  "'streamFunctionCallArguments' is only supported on the Vertex AI API " +
190
199
  'and will be ignored with the current Google provider ' +
191
- `(${this.config.provider}). See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling#streaming-fc`,
200
+ `(${config.provider}). See https://docs.cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling#streaming-fc`,
192
201
  });
193
202
  }
194
203
 
@@ -209,7 +218,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
209
218
  type: 'other',
210
219
  message:
211
220
  "'sharedRequestType' and 'requestType' are Vertex AI options and " +
212
- `are ignored with the current Google provider (${this.config.provider}).`,
221
+ `are ignored with the current Google provider (${config.provider}).`,
213
222
  });
214
223
  }
215
224
 
@@ -253,15 +262,15 @@ export class GoogleLanguageModel implements LanguageModelV4 {
253
262
  message:
254
263
  `${droppedImageConfigFields.join(', ')} ` +
255
264
  `${droppedImageConfigFields.length === 1 ? 'is a Vertex AI option and is' : 'are Vertex AI options and are'} ` +
256
- `ignored with the current Google provider (${this.config.provider}).`,
265
+ `ignored with the current Google provider (${config.provider}).`,
257
266
  });
258
267
  imageConfig = geminiApiImageConfig;
259
268
  }
260
269
  }
261
270
 
262
- const isGemmaModel = this.modelId.toLowerCase().startsWith('gemma-');
271
+ const isGemmaModel = modelId.toLowerCase().startsWith('gemma-');
263
272
  const isGemini25DeveloperApiModel =
264
- !isVertexProvider && gemini25ModelPattern.test(this.modelId);
273
+ !isVertexProvider && gemini25ModelPattern.test(modelId);
265
274
 
266
275
  if (isGemini25DeveloperApiModel && frequencyPenalty != null) {
267
276
  warnings.push({
@@ -276,7 +285,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
276
285
  });
277
286
  }
278
287
 
279
- const { usesGemini3Features } = getGoogleModelCapabilities(this.modelId);
288
+ const { usesGemini3Features } = getGoogleModelCapabilities(modelId);
280
289
 
281
290
  const { contents, systemInstruction } = convertToGoogleMessages(prompt, {
282
291
  isGemmaModel,
@@ -294,13 +303,19 @@ export class GoogleLanguageModel implements LanguageModelV4 {
294
303
  } = prepareTools({
295
304
  tools,
296
305
  toolChoice,
297
- modelId: this.modelId,
306
+ modelId,
298
307
  isVertexProvider,
299
308
  });
309
+ const toolNameMapping = createToolNameMapping({
310
+ tools,
311
+ providerToolNames: {
312
+ 'google.code_execution': 'code_execution',
313
+ },
314
+ });
300
315
 
301
316
  const resolvedThinking = resolveThinkingConfig({
302
317
  reasoning,
303
- modelId: this.modelId,
318
+ modelId,
304
319
  warnings,
305
320
  });
306
321
  const thinkingConfig =
@@ -394,17 +409,34 @@ export class GoogleLanguageModel implements LanguageModelV4 {
394
409
  warnings: [...warnings, ...toolWarnings],
395
410
  providerOptionsNames,
396
411
  extraHeaders: vertexPaygoHeaders,
412
+ toolNameMapping,
397
413
  };
398
414
  }
399
415
 
400
- protected convertGenerateContentResponse({
416
+ private getArgs(
417
+ options: LanguageModelV4CallOptions,
418
+ { isStreaming = false }: { isStreaming?: boolean } = {},
419
+ ) {
420
+ return GoogleLanguageModel.prepareRequest({
421
+ modelId: this.modelId,
422
+ config: this.config,
423
+ options,
424
+ isStreaming,
425
+ });
426
+ }
427
+
428
+ static convertGenerateContentResponse({
429
+ config,
401
430
  response,
402
431
  warnings,
403
432
  providerOptionsNames,
433
+ toolNameMapping,
404
434
  }: {
435
+ config: GoogleLanguageModelConfig;
405
436
  response: InferSchema<typeof responseSchema>;
406
437
  warnings: SharedV4Warning[];
407
438
  providerOptionsNames: readonly string[];
439
+ toolNameMapping?: ReturnType<typeof createToolNameMapping>;
408
440
  }): LanguageModelV4GenerateResult {
409
441
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
410
442
  Object.fromEntries(
@@ -431,13 +463,15 @@ export class GoogleLanguageModel implements LanguageModelV4 {
431
463
  // Build content array from all parts
432
464
  for (const part of parts) {
433
465
  if ('executableCode' in part && part.executableCode?.code) {
434
- const toolCallId = this.config.generateId();
466
+ const toolCallId = config.generateId();
435
467
  lastCodeExecutionToolCallId = toolCallId;
436
468
 
437
469
  content.push({
438
470
  type: 'tool-call',
439
471
  toolCallId,
440
- toolName: 'code_execution',
472
+ toolName:
473
+ toolNameMapping?.toCustomToolName('code_execution') ??
474
+ 'code_execution',
441
475
  input: JSON.stringify(part.executableCode),
442
476
  providerExecuted: true,
443
477
  });
@@ -446,7 +480,9 @@ export class GoogleLanguageModel implements LanguageModelV4 {
446
480
  type: 'tool-result',
447
481
  // Results correspond to the most recent executable code part.
448
482
  toolCallId: lastCodeExecutionToolCallId!,
449
- toolName: 'code_execution',
483
+ toolName:
484
+ toolNameMapping?.toCustomToolName('code_execution') ??
485
+ 'code_execution',
450
486
  result: {
451
487
  outcome: part.codeExecutionResult.outcome,
452
488
  output: part.codeExecutionResult.output ?? '',
@@ -474,7 +510,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
474
510
  } else if ('functionCall' in part && part.functionCall.name != null) {
475
511
  content.push({
476
512
  type: 'tool-call' as const,
477
- toolCallId: part.functionCall.id || this.config.generateId(),
513
+ toolCallId: part.functionCall.id || config.generateId(),
478
514
  toolName: part.functionCall.name,
479
515
  input: JSON.stringify(part.functionCall.args ?? {}),
480
516
  providerMetadata: part.thoughtSignature
@@ -497,7 +533,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
497
533
  : undefined,
498
534
  });
499
535
  } else if ('toolCall' in part && part.toolCall) {
500
- const toolCallId = part.toolCall.id || this.config.generateId();
536
+ const toolCallId = part.toolCall.id || config.generateId();
501
537
  lastServerToolCallId = toolCallId;
502
538
  content.push({
503
539
  type: 'tool-call',
@@ -519,9 +555,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
519
555
  });
520
556
  } else if ('toolResponse' in part && part.toolResponse) {
521
557
  const responseToolCallId =
522
- lastServerToolCallId ||
523
- part.toolResponse.id ||
524
- this.config.generateId();
558
+ lastServerToolCallId || part.toolResponse.id || config.generateId();
525
559
  content.push({
526
560
  type: 'tool-result',
527
561
  toolCallId: responseToolCallId,
@@ -545,7 +579,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
545
579
  const sources =
546
580
  extractSources({
547
581
  groundingMetadata: candidate?.groundingMetadata,
548
- generateId: this.config.generateId,
582
+ generateId: config.generateId,
549
583
  }) ?? [];
550
584
  for (const source of sources) {
551
585
  content.push(source);
@@ -586,8 +620,13 @@ export class GoogleLanguageModel implements LanguageModelV4 {
586
620
  async doGenerate(
587
621
  options: LanguageModelV4CallOptions,
588
622
  ): Promise<LanguageModelV4GenerateResult> {
589
- const { args, warnings, providerOptionsNames, extraHeaders } =
590
- await this.getArgs(options);
623
+ const {
624
+ args,
625
+ warnings,
626
+ providerOptionsNames,
627
+ extraHeaders,
628
+ toolNameMapping,
629
+ } = await this.getArgs(options);
591
630
 
592
631
  const mergedHeaders = combineHeaders(
593
632
  this.config.headers ? await resolve(this.config.headers) : undefined,
@@ -611,10 +650,12 @@ export class GoogleLanguageModel implements LanguageModelV4 {
611
650
  fetch: this.config.fetch,
612
651
  });
613
652
 
614
- const result = this.convertGenerateContentResponse({
653
+ const result = GoogleLanguageModel.convertGenerateContentResponse({
654
+ config: this.config,
615
655
  response,
616
656
  warnings,
617
657
  providerOptionsNames,
658
+ toolNameMapping,
618
659
  });
619
660
 
620
661
  return {
@@ -631,8 +672,13 @@ export class GoogleLanguageModel implements LanguageModelV4 {
631
672
  async doStream(
632
673
  options: LanguageModelV4CallOptions,
633
674
  ): Promise<LanguageModelV4StreamResult> {
634
- const { args, warnings, providerOptionsNames, extraHeaders } =
635
- await this.getArgs(options, { isStreaming: true });
675
+ const {
676
+ args,
677
+ warnings,
678
+ providerOptionsNames,
679
+ extraHeaders,
680
+ toolNameMapping,
681
+ } = await this.getArgs(options, { isStreaming: true });
636
682
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
637
683
  Object.fromEntries(
638
684
  providerOptionsNames.map(name => [name, payload]),
@@ -820,7 +866,8 @@ export class GoogleLanguageModel implements LanguageModelV4 {
820
866
  controller.enqueue({
821
867
  type: 'tool-call',
822
868
  toolCallId,
823
- toolName: 'code_execution',
869
+ toolName:
870
+ toolNameMapping.toCustomToolName('code_execution'),
824
871
  input: JSON.stringify(part.executableCode),
825
872
  providerExecuted: true,
826
873
  });
@@ -835,7 +882,8 @@ export class GoogleLanguageModel implements LanguageModelV4 {
835
882
  controller.enqueue({
836
883
  type: 'tool-result',
837
884
  toolCallId,
838
- toolName: 'code_execution',
885
+ toolName:
886
+ toolNameMapping.toCustomToolName('code_execution'),
839
887
  result: {
840
888
  outcome: part.codeExecutionResult.outcome,
841
889
  output: part.codeExecutionResult.output ?? '',