@ai-sdk/google 4.0.87 → 4.0.88

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.
@@ -2393,18 +2393,18 @@ Older models continue to use labelled transcripts, such as
2393
2393
  | `gemini-3.8-flash-tts` | <Check /> | <Check /> |
2394
2394
  | `gemini-3.8-flash-lite-tts` | <Check /> | <Check /> |
2395
2395
 
2396
- ## Evaluation Models
2396
+ ## Decision Models
2397
2397
 
2398
- Create an experimental evaluation model with `google.evaluationModel(modelId)`.
2398
+ Create an experimental decision model with `google.decisionModel(modelId)`.
2399
2399
  It uses Gemini structured output for Choice, Score, and Boolean questions. Choose a model
2400
2400
  that supports structured output, such as `gemini-3.5-flash-lite`.
2401
2401
 
2402
2402
  ```ts
2403
2403
  import { google } from '@ai-sdk/google';
2404
- import { experimental_evaluate } from 'ai';
2404
+ import { experimental_decide } from 'ai';
2405
2405
 
2406
- const { answers } = await experimental_evaluate({
2407
- model: google.evaluationModel('gemini-3.5-flash-lite'),
2406
+ const { answers } = await experimental_decide({
2407
+ model: google.decisionModel('gemini-3.5-flash-lite'),
2408
2408
  state: 'I was charged twice.',
2409
2409
  questions: {
2410
2410
  requestsRefund: {
@@ -2436,10 +2436,10 @@ and rejects safety-blocked, truncated, or invalid output. It preserves usage
2436
2436
  Choice and Score answers do not include probability distributions. Boolean
2437
2437
  answers contain prompted estimates of P(true), validated to be finite and in
2438
2438
  `[0, 1]`. These estimates are not guaranteed to be calibrated. Apply thresholds
2439
- in application code, for example `answers.requestsRefund.probability >= 0.5`. See [Evaluation](/docs/ai-sdk-core/evaluation).
2439
+ in application code, for example `answers.requestsRefund.probability >= 0.5`. See [Decisions](/docs/ai-sdk-core/decisions).
2440
2440
 
2441
- Evaluation models can also be accessed through `customProvider` aliases or
2442
- `createProviderRegistry().evaluationModel('provider:model')`. Direct string IDs
2441
+ Decision models can also be accessed through `customProvider` aliases or
2442
+ `createProviderRegistry().decisionModel('provider:model')`. Direct string IDs
2443
2443
  use Gateway by default, or an explicitly configured default provider with an
2444
- `evaluationModel` method. See
2445
- [model aliases and registries](/docs/ai-sdk-core/evaluation#model-aliases-and-registries).
2444
+ `decisionModel` method. See
2445
+ [model aliases and registries](/docs/ai-sdk-core/decisions#model-aliases-and-registries).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "4.0.87",
3
+ "version": "4.0.88",
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.21",
39
- "@ai-sdk/provider-utils": "5.0.53"
38
+ "@ai-sdk/provider": "4.0.22",
39
+ "@ai-sdk/provider-utils": "5.0.54"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.3",
@@ -2,6 +2,7 @@ import type {
2
2
  LanguageModelV4,
3
3
  LanguageModelV4CallOptions,
4
4
  LanguageModelV4Content,
5
+ LanguageModelV4FunctionTool,
5
6
  LanguageModelV4FinishReason,
6
7
  LanguageModelV4GenerateResult,
7
8
  LanguageModelV4Source,
@@ -13,6 +14,7 @@ import type {
13
14
  } from '@ai-sdk/provider';
14
15
  import {
15
16
  combineHeaders,
17
+ convertJsonResponseToolStream,
16
18
  createToolNameMapping,
17
19
  createEventSourceResponseHandler,
18
20
  createJsonResponseHandler,
@@ -448,16 +450,57 @@ export class GoogleLanguageModel implements LanguageModelV4 {
448
450
  };
449
451
  }
450
452
 
451
- private getArgs(
453
+ private async getArgs(
452
454
  options: LanguageModelV4CallOptions,
453
455
  { isStreaming = false }: { isStreaming?: boolean } = {},
454
456
  ) {
455
- return GoogleLanguageModel.prepareRequest({
457
+ const { responseFormat, tools, toolChoice } = options;
458
+ let jsonResponseTool: LanguageModelV4FunctionTool | undefined;
459
+ // Gemini models before Gemini 3 reject JSON response formatting together
460
+ // with function tools. Gemini 3 supports the combination only with automatic
461
+ // tool choice (AUTO). Forced tool choice (ANY) requires a JSON response tool.
462
+ if (
463
+ responseFormat?.type === 'json' &&
464
+ responseFormat.schema != null &&
465
+ tools?.some(tool => tool.type === 'function') &&
466
+ /(^|\/)gemini-/i.test(this.modelId) &&
467
+ (!getGoogleModelCapabilities(this.modelId).usesGemini3Features ||
468
+ toolChoice?.type === 'required' ||
469
+ toolChoice?.type === 'tool')
470
+ ) {
471
+ let name = 'json';
472
+ for (let suffix = 1; tools.some(tool => tool.name === name); suffix++) {
473
+ name = `json_${suffix}`;
474
+ }
475
+ jsonResponseTool = {
476
+ type: 'function',
477
+ name,
478
+ description:
479
+ responseFormat.description ?? 'Respond with a JSON object.',
480
+ inputSchema: responseFormat.schema,
481
+ };
482
+ }
483
+
484
+ const prepared = await GoogleLanguageModel.prepareRequest({
456
485
  modelId: this.modelId,
457
486
  config: this.config,
458
- options,
487
+ options:
488
+ jsonResponseTool == null
489
+ ? options
490
+ : {
491
+ ...options,
492
+ responseFormat: undefined,
493
+ tools: [...(tools ?? []), jsonResponseTool],
494
+ toolChoice:
495
+ toolChoice?.type === 'tool'
496
+ ? toolChoice
497
+ : toolChoice?.type === 'none'
498
+ ? { type: 'tool', toolName: jsonResponseTool.name }
499
+ : { type: 'required' },
500
+ },
459
501
  isStreaming,
460
502
  });
503
+ return { ...prepared, jsonResponseToolName: jsonResponseTool?.name };
461
504
  }
462
505
 
463
506
  static convertGenerateContentResponse({
@@ -466,12 +509,14 @@ export class GoogleLanguageModel implements LanguageModelV4 {
466
509
  warnings,
467
510
  providerOptionsNames,
468
511
  toolNameMapping,
512
+ jsonResponseToolName,
469
513
  }: {
470
514
  config: GoogleLanguageModelConfig;
471
515
  response: InferSchema<typeof responseSchema>;
472
516
  warnings: SharedV4Warning[];
473
517
  providerOptionsNames: readonly string[];
474
518
  toolNameMapping?: ReturnType<typeof createToolNameMapping>;
519
+ jsonResponseToolName?: string;
475
520
  }): LanguageModelV4GenerateResult {
476
521
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
477
522
  Object.fromEntries(
@@ -529,6 +574,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
529
574
  },
530
575
  });
531
576
  } else if ('text' in part && part.text != null) {
577
+ if (jsonResponseToolName != null && part.thought !== true) continue;
532
578
  const thoughtSignatureMetadata = part.thoughtSignature
533
579
  ? wrapProviderMetadata({
534
580
  thoughtSignature: part.thoughtSignature,
@@ -548,6 +594,23 @@ export class GoogleLanguageModel implements LanguageModelV4 {
548
594
  });
549
595
  }
550
596
  } else if ('functionCall' in part && part.functionCall.name != null) {
597
+ if (part.functionCall.name === jsonResponseToolName) {
598
+ content.push({
599
+ type: 'text',
600
+ text:
601
+ typeof part.functionCall.args === 'string'
602
+ ? part.functionCall.args
603
+ : JSON.stringify(part.functionCall.args ?? {}),
604
+ ...(part.thoughtSignature
605
+ ? {
606
+ providerMetadata: wrapProviderMetadata({
607
+ thoughtSignature: part.thoughtSignature,
608
+ }),
609
+ }
610
+ : {}),
611
+ });
612
+ continue;
613
+ }
551
614
  content.push({
552
615
  type: 'tool-call' as const,
553
616
  toolCallId: part.functionCall.id || config.generateId(),
@@ -666,6 +729,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
666
729
  providerOptionsNames,
667
730
  extraHeaders,
668
731
  toolNameMapping,
732
+ jsonResponseToolName,
669
733
  } = await this.getArgs(options);
670
734
 
671
735
  const mergedHeaders = combineHeaders(
@@ -696,6 +760,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
696
760
  warnings,
697
761
  providerOptionsNames,
698
762
  toolNameMapping,
763
+ jsonResponseToolName,
699
764
  });
700
765
 
701
766
  return {
@@ -718,6 +783,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
718
783
  providerOptionsNames,
719
784
  extraHeaders,
720
785
  toolNameMapping,
786
+ jsonResponseToolName,
721
787
  } = await this.getArgs(options, { isStreaming: true });
722
788
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
723
789
  Object.fromEntries(
@@ -813,7 +879,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
813
879
  hasToolCalls = true;
814
880
  };
815
881
 
816
- return {
882
+ const result = {
817
883
  stream: response.pipeThrough(
818
884
  new TransformStream<
819
885
  ParseResult<ChunkSchema>,
@@ -1301,6 +1367,15 @@ export class GoogleLanguageModel implements LanguageModelV4 {
1301
1367
  response: { headers: responseHeaders },
1302
1368
  request: { body: args },
1303
1369
  };
1370
+ return {
1371
+ ...result,
1372
+ stream:
1373
+ jsonResponseToolName == null
1374
+ ? result.stream
1375
+ : result.stream.pipeThrough(
1376
+ convertJsonResponseToolStream(jsonResponseToolName),
1377
+ ),
1378
+ };
1304
1379
  }
1305
1380
  }
1306
1381
 
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  EmbeddingModelV4,
3
3
  Experimental_BatchV4 as BatchV4,
4
- Experimental_EvaluationModelV4 as EvaluationModelV4,
4
+ Experimental_DecisionModelV4 as DecisionModelV4,
5
5
  Experimental_VideoModelV4,
6
6
  FilesV4,
7
7
  ImageModelV4,
@@ -21,7 +21,7 @@ import {
21
21
  type FetchFunction,
22
22
  type WebSocketConstructor,
23
23
  } from '@ai-sdk/provider-utils';
24
- import { Experimental_EvaluationLanguageModel as EvaluationLanguageModel } from '@ai-sdk/provider-utils/experimental-evaluation';
24
+ import { Experimental_DecisionLanguageModel as DecisionLanguageModel } from '@ai-sdk/provider-utils/experimental-decision';
25
25
  import { VERSION } from './version';
26
26
  import { GoogleEmbeddingModel } from './google-embedding-model';
27
27
  import type { GoogleEmbeddingModelId } from './google-embedding-model-options';
@@ -63,8 +63,12 @@ export interface GoogleProvider extends ProviderV4 {
63
63
 
64
64
  chat(modelId: GoogleModelId): LanguageModelV4;
65
65
 
66
- /** Creates an experimental Choice/Score/Boolean evaluation model using Gemini. */
67
- evaluationModel(modelId: GoogleModelId): EvaluationModelV4;
66
+ /** Creates an experimental Choice/Score/Boolean decision model using Gemini. */
67
+ decisionModel(modelId: GoogleModelId): DecisionModelV4;
68
+ /** @deprecated Use `decisionModel` instead. */
69
+ evaluationModel(modelId: GoogleModelId): DecisionModelV4 & {
70
+ doEvaluate: DecisionModelV4['doDecide'];
71
+ };
68
72
 
69
73
  experimental_batch(): BatchV4<{
70
74
  text: GoogleModelId;
@@ -435,11 +439,13 @@ export function createGoogle(
435
439
  provider.languageModel = createChatModel;
436
440
  provider.chat = createChatModel;
437
441
  provider.generativeAI = createChatModel;
438
- provider.evaluationModel = (modelId: GoogleModelId) =>
439
- new EvaluationLanguageModel({
442
+ provider.decisionModel = (modelId: GoogleModelId) =>
443
+ new DecisionLanguageModel({
440
444
  model: createChatModel(modelId),
441
- provider: `${providerName.replace(/\.generative-ai$/, '')}.evaluation`,
445
+ provider: `${providerName.replace(/\.generative-ai$/, '')}.decision`,
442
446
  });
447
+ provider.evaluationModel =
448
+ provider.decisionModel as GoogleProvider['evaluationModel'];
443
449
  provider.experimental_batch = createBatch;
444
450
  provider.embedding = createEmbeddingModel;
445
451
  provider.embeddingModel = createEmbeddingModel;