@ai-sdk/google 3.0.116 → 3.0.119

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "3.0.116",
3
+ "version": "3.0.119",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@ai-sdk/provider": "3.0.15",
40
- "@ai-sdk/provider-utils": "4.0.49"
40
+ "@ai-sdk/provider-utils": "4.0.50"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "20.17.24",
@@ -8,13 +8,16 @@ export type GoogleGenerativeAITokenDetail = {
8
8
  export type GoogleGenerativeAIUsageMetadata = {
9
9
  promptTokenCount?: number | null;
10
10
  candidatesTokenCount?: number | null;
11
+ toolUsePromptTokenCount?: number | null;
11
12
  totalTokenCount?: number | null;
12
13
  cachedContentTokenCount?: number | null;
13
14
  thoughtsTokenCount?: number | null;
14
15
  trafficType?: string | null;
15
16
  serviceTier?: string | null;
16
17
  promptTokensDetails?: GoogleGenerativeAITokenDetail[] | null;
18
+ cacheTokensDetails?: GoogleGenerativeAITokenDetail[] | null;
17
19
  candidatesTokensDetails?: GoogleGenerativeAITokenDetail[] | null;
20
+ toolUsePromptTokensDetails?: GoogleGenerativeAITokenDetail[] | null;
18
21
  };
19
22
 
20
23
  export function convertGoogleGenerativeAIUsage(
@@ -58,6 +58,8 @@ const configurableSafetySettingCategories = [
58
58
  'HARM_CATEGORY_SEXUALLY_EXPLICIT',
59
59
  ] as const;
60
60
 
61
+ const gemini25ModelPattern = /(^|\/)gemini-2\.5(?:[.-]|$)/i;
62
+
61
63
  type GoogleGenerativeAIConfig = {
62
64
  provider: string;
63
65
  baseURL: string;
@@ -230,6 +232,22 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
230
232
  }
231
233
 
232
234
  const isGemmaModel = this.modelId.toLowerCase().startsWith('gemma-');
235
+ const isGemini25DeveloperApiModel =
236
+ !isVertexProvider && gemini25ModelPattern.test(this.modelId);
237
+
238
+ if (isGemini25DeveloperApiModel && frequencyPenalty != null) {
239
+ warnings.push({
240
+ type: 'unsupported',
241
+ feature: 'frequencyPenalty',
242
+ });
243
+ }
244
+ if (isGemini25DeveloperApiModel && presencePenalty != null) {
245
+ warnings.push({
246
+ type: 'unsupported',
247
+ feature: 'presencePenalty',
248
+ });
249
+ }
250
+
233
251
  const { usesGemini3Features } = getGoogleModelCapabilities(this.modelId);
234
252
 
235
253
  const { contents, systemInstruction } = convertToGoogleGenerativeAIMessages(
@@ -296,8 +314,12 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
296
314
  temperature,
297
315
  topK,
298
316
  topP,
299
- frequencyPenalty,
300
- presencePenalty,
317
+ frequencyPenalty: isGemini25DeveloperApiModel
318
+ ? undefined
319
+ : frequencyPenalty,
320
+ presencePenalty: isGemini25DeveloperApiModel
321
+ ? undefined
322
+ : presencePenalty,
301
323
  stopSequences,
302
324
  seed,
303
325
 
@@ -368,11 +390,16 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
368
390
  fetch: this.config.fetch,
369
391
  });
370
392
 
371
- const candidate = response.candidates[0];
393
+ const candidate = response.candidates?.[0];
394
+ const promptBlockReason = response.promptFeedback?.blockReason;
395
+ const isPromptBlocked =
396
+ candidate?.finishReason == null && promptBlockReason != null;
397
+ const rawFinishReason =
398
+ candidate?.finishReason ?? promptBlockReason ?? undefined;
372
399
  const content: Array<LanguageModelV3Content> = [];
373
400
 
374
401
  // map ordered parts to content:
375
- const parts = candidate.content?.parts ?? [];
402
+ const parts = candidate?.content?.parts ?? [];
376
403
 
377
404
  const usageMetadata = response.usageMetadata;
378
405
 
@@ -515,7 +542,7 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
515
542
 
516
543
  const sources =
517
544
  extractSources({
518
- groundingMetadata: candidate.groundingMetadata,
545
+ groundingMetadata: candidate?.groundingMetadata,
519
546
  generateId: this.config.generateId,
520
547
  }) ?? [];
521
548
  for (const source of sources) {
@@ -525,25 +552,27 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
525
552
  return {
526
553
  content,
527
554
  finishReason: {
528
- unified: mapGoogleGenerativeAIFinishReason({
529
- finishReason: candidate.finishReason,
530
- // Only count client-executed tool calls for finish reason determination.
531
- hasToolCalls: content.some(
532
- part => part.type === 'tool-call' && !part.providerExecuted,
533
- ),
534
- }),
535
- raw: candidate.finishReason ?? undefined,
555
+ unified: isPromptBlocked
556
+ ? 'content-filter'
557
+ : mapGoogleGenerativeAIFinishReason({
558
+ finishReason: rawFinishReason,
559
+ // Only count client-executed tool calls for finish reason determination.
560
+ hasToolCalls: content.some(
561
+ part => part.type === 'tool-call' && !part.providerExecuted,
562
+ ),
563
+ }),
564
+ raw: rawFinishReason,
536
565
  },
537
566
  usage: convertGoogleGenerativeAIUsage(usageMetadata),
538
567
  warnings,
539
568
  providerMetadata: {
540
569
  [providerOptionsName]: {
541
570
  promptFeedback: response.promptFeedback ?? null,
542
- groundingMetadata: candidate.groundingMetadata ?? null,
543
- urlContextMetadata: candidate.urlContextMetadata ?? null,
544
- safetyRatings: candidate.safetyRatings ?? null,
571
+ groundingMetadata: candidate?.groundingMetadata ?? null,
572
+ urlContextMetadata: candidate?.urlContextMetadata ?? null,
573
+ safetyRatings: candidate?.safetyRatings ?? null,
545
574
  usageMetadata: usageMetadata ?? null,
546
- finishMessage: candidate.finishMessage ?? null,
575
+ finishMessage: candidate?.finishMessage ?? null,
547
576
  serviceTier: usageMetadata?.serviceTier ?? null,
548
577
  } satisfies GoogleGenerativeAIProviderMetadata,
549
578
  },
@@ -689,6 +718,24 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
689
718
 
690
719
  // sometimes the API returns an empty candidates array
691
720
  if (candidate == null) {
721
+ const promptBlockReason = value.promptFeedback?.blockReason;
722
+ if (promptBlockReason != null) {
723
+ finishReason = {
724
+ unified: 'content-filter',
725
+ raw: promptBlockReason,
726
+ };
727
+ providerMetadata = {
728
+ [providerOptionsName]: {
729
+ promptFeedback: value.promptFeedback ?? null,
730
+ groundingMetadata: lastGroundingMetadata,
731
+ urlContextMetadata: lastUrlContextMetadata,
732
+ safetyRatings: null,
733
+ usageMetadata: usageMetadata ?? null,
734
+ finishMessage: null,
735
+ serviceTier: usage?.serviceTier ?? null,
736
+ } satisfies GoogleGenerativeAIProviderMetadata,
737
+ };
738
+ }
692
739
  return;
693
740
  }
694
741
 
@@ -1078,13 +1125,21 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
1078
1125
  }
1079
1126
  }
1080
1127
 
1081
- if (candidate.finishReason != null) {
1128
+ const promptBlockReason = value.promptFeedback?.blockReason;
1129
+ const isPromptBlocked =
1130
+ candidate.finishReason == null && promptBlockReason != null;
1131
+ const rawFinishReason =
1132
+ candidate.finishReason ?? promptBlockReason ?? undefined;
1133
+
1134
+ if (rawFinishReason != null) {
1082
1135
  finishReason = {
1083
- unified: mapGoogleGenerativeAIFinishReason({
1084
- finishReason: candidate.finishReason,
1085
- hasToolCalls,
1086
- }),
1087
- raw: candidate.finishReason,
1136
+ unified: isPromptBlocked
1137
+ ? 'content-filter'
1138
+ : mapGoogleGenerativeAIFinishReason({
1139
+ finishReason: rawFinishReason,
1140
+ hasToolCalls,
1141
+ }),
1142
+ raw: rawFinishReason,
1088
1143
  };
1089
1144
 
1090
1145
  providerMetadata = {
@@ -1426,26 +1481,33 @@ const getSafetyRatingSchema = () =>
1426
1481
 
1427
1482
  const tokenDetailsSchema = z
1428
1483
  .array(
1429
- z.object({
1430
- modality: z.string(),
1431
- tokenCount: z.number(),
1432
- }),
1484
+ z
1485
+ .object({
1486
+ modality: z.string(),
1487
+ tokenCount: z.number(),
1488
+ })
1489
+ .catchall(z.json()),
1433
1490
  )
1434
1491
  .nullish();
1435
1492
 
1436
- const usageSchema = z.object({
1437
- cachedContentTokenCount: z.number().nullish(),
1438
- thoughtsTokenCount: z.number().nullish(),
1439
- promptTokenCount: z.number().nullish(),
1440
- candidatesTokenCount: z.number().nullish(),
1441
- totalTokenCount: z.number().nullish(),
1442
- // https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest/v1/GenerateContentResponse#TrafficType
1443
- trafficType: z.string().nullish(),
1444
- serviceTier: z.string().nullish(),
1445
- // https://ai.google.dev/api/generate-content#Modality
1446
- promptTokensDetails: tokenDetailsSchema,
1447
- candidatesTokensDetails: tokenDetailsSchema,
1448
- });
1493
+ const usageSchema = z
1494
+ .object({
1495
+ cachedContentTokenCount: z.number().nullish(),
1496
+ thoughtsTokenCount: z.number().nullish(),
1497
+ promptTokenCount: z.number().nullish(),
1498
+ candidatesTokenCount: z.number().nullish(),
1499
+ toolUsePromptTokenCount: z.number().nullish(),
1500
+ totalTokenCount: z.number().nullish(),
1501
+ // https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest/v1/GenerateContentResponse#TrafficType
1502
+ trafficType: z.string().nullish(),
1503
+ serviceTier: z.string().nullish(),
1504
+ // https://ai.google.dev/api/generate-content#Modality
1505
+ promptTokensDetails: tokenDetailsSchema,
1506
+ cacheTokensDetails: tokenDetailsSchema,
1507
+ candidatesTokensDetails: tokenDetailsSchema,
1508
+ toolUsePromptTokensDetails: tokenDetailsSchema,
1509
+ })
1510
+ .catchall(z.json());
1449
1511
 
1450
1512
  // https://ai.google.dev/api/generate-content#UrlRetrievalMetadata
1451
1513
  export const getUrlContextMetadataSchema = () =>
@@ -1464,16 +1526,18 @@ const responseSchema = lazySchema(() =>
1464
1526
  zodSchema(
1465
1527
  z.object({
1466
1528
  responseId: z.string().nullish(),
1467
- candidates: z.array(
1468
- z.object({
1469
- content: getContentSchema().nullish().or(z.object({}).strict()),
1470
- finishReason: z.string().nullish(),
1471
- finishMessage: z.string().nullish(),
1472
- safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
1473
- groundingMetadata: getGroundingMetadataSchema().nullish(),
1474
- urlContextMetadata: getUrlContextMetadataSchema().nullish(),
1475
- }),
1476
- ),
1529
+ candidates: z
1530
+ .array(
1531
+ z.object({
1532
+ content: getContentSchema().nullish().or(z.object({}).strict()),
1533
+ finishReason: z.string().nullish(),
1534
+ finishMessage: z.string().nullish(),
1535
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
1536
+ groundingMetadata: getGroundingMetadataSchema().nullish(),
1537
+ urlContextMetadata: getUrlContextMetadataSchema().nullish(),
1538
+ }),
1539
+ )
1540
+ .nullish(),
1477
1541
  usageMetadata: usageSchema.nullish(),
1478
1542
  promptFeedback: z
1479
1543
  .object({
@@ -1485,11 +1549,14 @@ const responseSchema = lazySchema(() =>
1485
1549
  ),
1486
1550
  );
1487
1551
 
1488
- type ContentSchema = NonNullable<
1489
- InferSchema<typeof responseSchema>['candidates'][number]['content']
1490
- >;
1552
+ type CandidateSchema = NonNullable<
1553
+ InferSchema<typeof responseSchema>['candidates']
1554
+ >[number];
1555
+
1556
+ type ContentSchema = NonNullable<CandidateSchema['content']>;
1557
+
1491
1558
  export type GroundingMetadataSchema = NonNullable<
1492
- InferSchema<typeof responseSchema>['candidates'][number]['groundingMetadata']
1559
+ CandidateSchema['groundingMetadata']
1493
1560
  >;
1494
1561
 
1495
1562
  type GroundingChunkSchema = NonNullable<
@@ -1497,11 +1564,11 @@ type GroundingChunkSchema = NonNullable<
1497
1564
  >[number];
1498
1565
 
1499
1566
  export type UrlContextMetadataSchema = NonNullable<
1500
- InferSchema<typeof responseSchema>['candidates'][number]['urlContextMetadata']
1567
+ CandidateSchema['urlContextMetadata']
1501
1568
  >;
1502
1569
 
1503
1570
  export type SafetyRatingSchema = NonNullable<
1504
- InferSchema<typeof responseSchema>['candidates'][number]['safetyRatings']
1571
+ CandidateSchema['safetyRatings']
1505
1572
  >[number];
1506
1573
 
1507
1574
  export type PromptFeedbackSchema = NonNullable<