@ai-sdk/google 4.0.114 → 4.0.116

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": "4.0.114",
3
+ "version": "4.0.116",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@ai-sdk/provider": "4.0.37",
39
- "@ai-sdk/provider-utils": "5.0.76"
39
+ "@ai-sdk/provider-utils": "5.0.78"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.4",
@@ -61,7 +61,7 @@ export class GoogleJSONAccumulator {
61
61
  if (!rawPath || rawPath === '$') continue;
62
62
 
63
63
  const segments = parsePath(rawPath);
64
- if (!hasContiguousIndexes(this.accumulatedArgs, segments)) continue;
64
+ if (!normalizeAndCheckIndexes(this.accumulatedArgs, segments)) continue;
65
65
 
66
66
  const existingValue = getNestedValue(this.accumulatedArgs, segments);
67
67
  const isStringContinuation =
@@ -388,20 +388,35 @@ function getNestedValue(
388
388
  }
389
389
 
390
390
  /**
391
- * Checks that every array index on the path is an existing element or the next
392
- * one. Arrays are streamed in order, and a sparse index would make `finalize()`
393
- * serialize one `null` per hole, so a tiny response could allocate without bound.
391
+ * Normalizes dotted array indexes in place and checks that every array index
392
+ * is an existing element or the next one. Arrays are streamed in order, and a
393
+ * sparse index would make `finalize()` serialize one `null` per hole, so a tiny
394
+ * response could allocate without bound.
394
395
  * A missing or `null` parent is replaced with a new array, so it starts at 0.
395
396
  *
396
397
  * Input: ({items:["a"]}, ["items",1]) or ({items:["a"]}, ["items",5])
397
398
  * Output: true or false
398
399
  */
399
- function hasContiguousIndexes(
400
+ function normalizeAndCheckIndexes(
400
401
  obj: Record<string, unknown>,
401
402
  segments: Array<string | number>,
402
403
  ): boolean {
403
404
  let current: unknown = obj;
404
- for (const pathSegment of segments) {
405
+ for (let i = 0; i < segments.length; i++) {
406
+ let pathSegment = segments[i];
407
+ if (Array.isArray(current) && typeof pathSegment === 'string') {
408
+ const index = Number(pathSegment);
409
+ // Only canonical array-index keys affect length. Keep object keys as strings.
410
+ if (
411
+ Number.isInteger(index) &&
412
+ index >= 0 &&
413
+ index < 2 ** 32 - 1 &&
414
+ String(index) === pathSegment
415
+ ) {
416
+ pathSegment = index;
417
+ segments[i] = index;
418
+ }
419
+ }
405
420
  if (typeof pathSegment === 'number') {
406
421
  const length = Array.isArray(current)
407
422
  ? current.length
@@ -518,6 +518,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
518
518
  static convertGenerateContentResponse({
519
519
  config,
520
520
  response,
521
+ responseHeaders,
521
522
  warnings,
522
523
  providerOptionsNames,
523
524
  toolNameMapping,
@@ -527,6 +528,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
527
528
  }: {
528
529
  config: GoogleLanguageModelConfig;
529
530
  response: InferSchema<typeof responseSchema>;
531
+ responseHeaders?: Record<string, string>;
530
532
  warnings: SharedV4Warning[];
531
533
  providerOptionsNames: readonly string[];
532
534
  toolNameMapping?: ReturnType<typeof createToolNameMapping>;
@@ -730,7 +732,10 @@ export class GoogleLanguageModel implements LanguageModelV4 {
730
732
  safetyRatings: candidate?.safetyRatings ?? null,
731
733
  usageMetadata: usageMetadata ?? null,
732
734
  finishMessage: candidate?.finishMessage ?? null,
733
- serviceTier: usageMetadata?.serviceTier ?? null,
735
+ serviceTier:
736
+ usageMetadata?.serviceTier ??
737
+ responseHeaders?.['x-gemini-service-tier'] ??
738
+ null,
734
739
  ...(candidate?.continuationToken != null
735
740
  ? { continuationToken: candidate.continuationToken }
736
741
  : {}),
@@ -832,6 +837,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
832
837
  const lastResult = GoogleLanguageModel.convertGenerateContentResponse({
833
838
  config: this.config,
834
839
  response: { ...response, usageMetadata },
840
+ responseHeaders,
835
841
  warnings,
836
842
  providerOptionsNames,
837
843
  toolNameMapping,
@@ -1591,7 +1597,10 @@ export class GoogleLanguageModel implements LanguageModelV4 {
1591
1597
  safetyRatings: lastSafetyRatings,
1592
1598
  usageMetadata: usage ?? null,
1593
1599
  finishMessage: lastFinishMessage,
1594
- serviceTier: usage?.serviceTier ?? null,
1600
+ serviceTier:
1601
+ usage?.serviceTier ??
1602
+ responseHeaders?.['x-gemini-service-tier'] ??
1603
+ null,
1595
1604
  // Only surface the token when the response stopped early
1596
1605
  // (budget used up, or continuing failed), not for the
1597
1606
  // checkpoint tokens of a stream that finished normally.