@ai-sdk/google 4.0.107 → 4.0.108
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/CHANGELOG.md +19 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +87 -50
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +9 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +86 -49
- package/dist/internal/index.js.map +1 -1
- package/docs/15-google.mdx +18 -2
- package/package.json +2 -2
- package/src/convert-to-google-messages.ts +16 -5
- package/src/google-json-accumulator.ts +26 -14
- package/src/google-language-model.ts +19 -14
- package/src/google-prompt.ts +15 -0
- package/src/index.ts +1 -0
package/docs/15-google.mdx
CHANGED
|
@@ -540,7 +540,14 @@ const result = await generateText({
|
|
|
540
540
|
});
|
|
541
541
|
```
|
|
542
542
|
|
|
543
|
-
You can also use YouTube URLs directly
|
|
543
|
+
You can also use YouTube URLs directly. Pass `videoMetadata` through
|
|
544
|
+
`providerOptions.google` on a video file part to clip a segment or control the
|
|
545
|
+
frame rate. This also works with inline video data and uploaded file references.
|
|
546
|
+
The metadata supports these optional fields:
|
|
547
|
+
|
|
548
|
+
- `startOffset` (string): Start time as a duration in seconds, e.g. `'60s'` or `'3.5s'`.
|
|
549
|
+
- `endOffset` (string): End time in the same duration format.
|
|
550
|
+
- `fps` (number): Frames per second in the range `(0, 24]`. The default is `1`.
|
|
544
551
|
|
|
545
552
|
```ts
|
|
546
553
|
import { google } from '@ai-sdk/google';
|
|
@@ -554,12 +561,21 @@ const result = await generateText({
|
|
|
554
561
|
content: [
|
|
555
562
|
{
|
|
556
563
|
type: 'text',
|
|
557
|
-
text: 'Summarize this video',
|
|
564
|
+
text: 'Summarize this part of the video',
|
|
558
565
|
},
|
|
559
566
|
{
|
|
560
567
|
type: 'file',
|
|
561
568
|
data: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
|
562
569
|
mediaType: 'video/mp4',
|
|
570
|
+
providerOptions: {
|
|
571
|
+
google: {
|
|
572
|
+
videoMetadata: {
|
|
573
|
+
startOffset: '60s',
|
|
574
|
+
endOffset: '600s',
|
|
575
|
+
fps: 1,
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
},
|
|
563
579
|
},
|
|
564
580
|
],
|
|
565
581
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.108",
|
|
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.34",
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.71"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.4",
|
|
@@ -14,11 +14,12 @@ import {
|
|
|
14
14
|
resolveProviderReference,
|
|
15
15
|
secureJsonParse,
|
|
16
16
|
} from '@ai-sdk/provider-utils';
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
import {
|
|
18
|
+
googleVideoMetadataSchema,
|
|
19
|
+
type GoogleContent,
|
|
20
|
+
type GoogleContentPart,
|
|
21
|
+
type GoogleFunctionResponsePart,
|
|
22
|
+
type GooglePrompt,
|
|
22
23
|
} from './google-prompt';
|
|
23
24
|
import {
|
|
24
25
|
codeExecutionInputSchema,
|
|
@@ -330,6 +331,12 @@ export function convertToGoogleMessages(
|
|
|
330
331
|
}
|
|
331
332
|
|
|
332
333
|
case 'file': {
|
|
334
|
+
const rawVideoMetadata = readProviderOpts(part)?.videoMetadata;
|
|
335
|
+
const videoMetadata =
|
|
336
|
+
rawVideoMetadata == null
|
|
337
|
+
? undefined
|
|
338
|
+
: googleVideoMetadataSchema.parse(rawVideoMetadata);
|
|
339
|
+
|
|
333
340
|
switch (part.data.type) {
|
|
334
341
|
case 'url': {
|
|
335
342
|
parts.push({
|
|
@@ -341,6 +348,7 @@ export function convertToGoogleMessages(
|
|
|
341
348
|
? part.data.originalUrl
|
|
342
349
|
: part.data.url.toString(),
|
|
343
350
|
},
|
|
351
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
344
352
|
});
|
|
345
353
|
break;
|
|
346
354
|
}
|
|
@@ -359,6 +367,7 @@ export function convertToGoogleMessages(
|
|
|
359
367
|
provider: 'google',
|
|
360
368
|
}),
|
|
361
369
|
},
|
|
370
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
362
371
|
});
|
|
363
372
|
break;
|
|
364
373
|
}
|
|
@@ -372,6 +381,7 @@ export function convertToGoogleMessages(
|
|
|
372
381
|
new TextEncoder().encode(part.data.text),
|
|
373
382
|
),
|
|
374
383
|
},
|
|
384
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
375
385
|
});
|
|
376
386
|
break;
|
|
377
387
|
}
|
|
@@ -381,6 +391,7 @@ export function convertToGoogleMessages(
|
|
|
381
391
|
mimeType: resolveFullMediaType({ part }),
|
|
382
392
|
data: convertToBase64(part.data.data),
|
|
383
393
|
},
|
|
394
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
384
395
|
});
|
|
385
396
|
break;
|
|
386
397
|
}
|
|
@@ -74,6 +74,9 @@ export class GoogleJSONAccumulator {
|
|
|
74
74
|
(existingValue as string) + arg.stringValue,
|
|
75
75
|
);
|
|
76
76
|
delta += escaped;
|
|
77
|
+
if (arg.willContinue !== true) {
|
|
78
|
+
delta += this.closeOpenString();
|
|
79
|
+
}
|
|
77
80
|
continue;
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -81,8 +84,15 @@ export class GoogleJSONAccumulator {
|
|
|
81
84
|
if (resolved == null) {
|
|
82
85
|
// A value-less entry for a path without a value is an empty container
|
|
83
86
|
// (an empty container has no leaves to stream). Value-less entries for
|
|
84
|
-
// existing paths are string or array terminators
|
|
85
|
-
|
|
87
|
+
// existing paths are string or array terminators. A string terminator
|
|
88
|
+
// closes the open string, an array terminator is ignored.
|
|
89
|
+
if (existingValue !== undefined) {
|
|
90
|
+
if (typeof existingValue === 'string' && arg.willContinue !== true) {
|
|
91
|
+
delta += this.closeOpenString();
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (arg.willContinue === true) continue;
|
|
86
96
|
|
|
87
97
|
setNestedValue(
|
|
88
98
|
this.accumulatedArgs,
|
|
@@ -115,6 +125,18 @@ export class GoogleJSONAccumulator {
|
|
|
115
125
|
return { finalJSON: finalArgs, closingDelta };
|
|
116
126
|
}
|
|
117
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Input: stringOpen=true
|
|
130
|
+
* Output: '"' (and stringOpen=false), or '' when no string is open
|
|
131
|
+
*/
|
|
132
|
+
private closeOpenString(): string {
|
|
133
|
+
if (!this.stringOpen) {
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
this.stringOpen = false;
|
|
137
|
+
return '"';
|
|
138
|
+
}
|
|
139
|
+
|
|
118
140
|
/**
|
|
119
141
|
* Input: pathStack=[] (first call) or pathStack=[root,...] (subsequent calls)
|
|
120
142
|
* Output: '{' (first call) or '' (subsequent calls)
|
|
@@ -139,12 +161,7 @@ export class GoogleJSONAccumulator {
|
|
|
139
161
|
arg: PartialArg,
|
|
140
162
|
valueJson: string,
|
|
141
163
|
): string {
|
|
142
|
-
let fragment =
|
|
143
|
-
|
|
144
|
-
if (this.stringOpen) {
|
|
145
|
-
fragment += '"';
|
|
146
|
-
this.stringOpen = false;
|
|
147
|
-
}
|
|
164
|
+
let fragment = this.closeOpenString();
|
|
148
165
|
|
|
149
166
|
fragment += this.ensureRoot();
|
|
150
167
|
|
|
@@ -172,12 +189,7 @@ export class GoogleJSONAccumulator {
|
|
|
172
189
|
targetSegments: PathSegment[],
|
|
173
190
|
isArray: boolean,
|
|
174
191
|
): string {
|
|
175
|
-
let fragment =
|
|
176
|
-
|
|
177
|
-
if (this.stringOpen) {
|
|
178
|
-
fragment += '"';
|
|
179
|
-
this.stringOpen = false;
|
|
180
|
-
}
|
|
192
|
+
let fragment = this.closeOpenString();
|
|
181
193
|
|
|
182
194
|
fragment += this.ensureRoot();
|
|
183
195
|
|
|
@@ -1583,6 +1583,15 @@ function getMaxThinkingTokensForGemini25Model(modelId: string): number {
|
|
|
1583
1583
|
return 24576;
|
|
1584
1584
|
}
|
|
1585
1585
|
|
|
1586
|
+
/**
|
|
1587
|
+
* Gemini 2.5 Pro cannot disable thinking and requires a thinking budget of at
|
|
1588
|
+
* least 128 tokens. Other Gemini 2.5 models can disable thinking with a budget
|
|
1589
|
+
* of 0.
|
|
1590
|
+
*/
|
|
1591
|
+
function getMinThinkingTokensForGemini25Model(modelId: string): number {
|
|
1592
|
+
return modelId.toLowerCase().includes('2.5-pro') ? 128 : 0;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1586
1595
|
type GoogleThinkingConfig = NonNullable<
|
|
1587
1596
|
InferSchema<typeof googleLanguageModelOptions>['thinkingConfig']
|
|
1588
1597
|
>;
|
|
@@ -1624,20 +1633,17 @@ function resolveGemini3ThinkingConfig({
|
|
|
1624
1633
|
}): Pick<GoogleThinkingConfig, 'thinkingLevel'> | undefined {
|
|
1625
1634
|
const minimumThinkingLevel = getMinimumThinkingLevelForGemini3Model(modelId);
|
|
1626
1635
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
return { thinkingLevel: minimumThinkingLevel };
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1636
|
+
// It's not possible to fully disable thinking with Gemini 3, so reasoning
|
|
1637
|
+
// 'none' maps to the lowest supported thinking level.
|
|
1632
1638
|
const thinkingLevel = mapReasoningToProviderEffort({
|
|
1633
1639
|
reasoning,
|
|
1634
1640
|
effortMap: {
|
|
1635
|
-
minimal
|
|
1641
|
+
...(minimumThinkingLevel === 'minimal' && {
|
|
1642
|
+
minimal: 'minimal' as const,
|
|
1643
|
+
}),
|
|
1636
1644
|
low: 'low',
|
|
1637
1645
|
medium: 'medium',
|
|
1638
1646
|
high: 'high',
|
|
1639
|
-
xhigh: 'high',
|
|
1640
|
-
max: 'high',
|
|
1641
1647
|
},
|
|
1642
1648
|
warnings,
|
|
1643
1649
|
});
|
|
@@ -1695,8 +1701,10 @@ function resolveGemini25ThinkingConfig({
|
|
|
1695
1701
|
>;
|
|
1696
1702
|
modelId: string;
|
|
1697
1703
|
warnings: SharedV4Warning[];
|
|
1698
|
-
}): Pick<GoogleThinkingConfig, 'thinkingBudget'>
|
|
1699
|
-
|
|
1704
|
+
}): Pick<GoogleThinkingConfig, 'thinkingBudget'> {
|
|
1705
|
+
const minThinkingBudget = getMinThinkingTokensForGemini25Model(modelId);
|
|
1706
|
+
|
|
1707
|
+
if (reasoning === 'none' && minThinkingBudget === 0) {
|
|
1700
1708
|
return { thinkingBudget: 0 };
|
|
1701
1709
|
}
|
|
1702
1710
|
|
|
@@ -1704,12 +1712,9 @@ function resolveGemini25ThinkingConfig({
|
|
|
1704
1712
|
reasoning,
|
|
1705
1713
|
maxOutputTokens: getMaxOutputTokensForGemini25Model(),
|
|
1706
1714
|
maxReasoningBudget: getMaxThinkingTokensForGemini25Model(modelId),
|
|
1707
|
-
minReasoningBudget:
|
|
1715
|
+
minReasoningBudget: minThinkingBudget,
|
|
1708
1716
|
warnings,
|
|
1709
1717
|
});
|
|
1710
|
-
if (thinkingBudget == null) {
|
|
1711
|
-
return undefined;
|
|
1712
|
-
}
|
|
1713
1718
|
return { thinkingBudget };
|
|
1714
1719
|
}
|
|
1715
1720
|
|
package/src/google-prompt.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
1
2
|
import type {
|
|
2
3
|
GroundingMetadataSchema,
|
|
3
4
|
PromptFeedbackSchema,
|
|
@@ -20,10 +21,23 @@ export type GoogleContent = {
|
|
|
20
21
|
parts: Array<GoogleContentPart>;
|
|
21
22
|
};
|
|
22
23
|
|
|
24
|
+
export const googleVideoMetadataSchema = z.object({
|
|
25
|
+
/** Start offset as a duration in seconds, e.g. `'3.5s'`. */
|
|
26
|
+
startOffset: z.string().optional(),
|
|
27
|
+
/** End offset as a duration in seconds, e.g. `'10s'`. */
|
|
28
|
+
endOffset: z.string().optional(),
|
|
29
|
+
/** Frames per second in the range (0, 24]. Defaults to 1. */
|
|
30
|
+
fps: z.number().gt(0).max(24).optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** Metadata for preprocessing video file parts. */
|
|
34
|
+
export type GoogleVideoMetadata = z.infer<typeof googleVideoMetadataSchema>;
|
|
35
|
+
|
|
23
36
|
export type GoogleContentPart =
|
|
24
37
|
| { text: string; thought?: boolean; thoughtSignature?: string }
|
|
25
38
|
| {
|
|
26
39
|
inlineData: { mimeType: string; data: string };
|
|
40
|
+
videoMetadata?: GoogleVideoMetadata;
|
|
27
41
|
thought?: boolean;
|
|
28
42
|
thoughtSignature?: string;
|
|
29
43
|
}
|
|
@@ -41,6 +55,7 @@ export type GoogleContentPart =
|
|
|
41
55
|
}
|
|
42
56
|
| {
|
|
43
57
|
fileData: { mimeType: string; fileUri: string };
|
|
58
|
+
videoMetadata?: GoogleVideoMetadata;
|
|
44
59
|
thought?: boolean;
|
|
45
60
|
thoughtSignature?: string;
|
|
46
61
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type {
|
|
|
6
6
|
} from './google-language-model-options';
|
|
7
7
|
export type {
|
|
8
8
|
GoogleProviderMetadata,
|
|
9
|
+
GoogleVideoMetadata,
|
|
9
10
|
/** @deprecated Use `GoogleProviderMetadata` instead. */
|
|
10
11
|
GoogleProviderMetadata as GoogleGenerativeAIProviderMetadata,
|
|
11
12
|
} from './google-prompt';
|