@ai-sdk/google 3.0.138 → 3.0.140
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 +16 -0
- package/dist/index.d.mts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +570 -519
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +570 -519
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +544 -493
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +544 -493
- package/dist/internal/index.mjs.map +1 -1
- package/docs/15-google-generative-ai.mdx +18 -2
- package/package.json +2 -2
- package/src/convert-to-google-generative-ai-messages.ts +17 -5
- package/src/google-generative-ai-prompt.ts +21 -2
- package/src/google-json-accumulator.ts +52 -3
- package/src/index.ts +4 -1
|
@@ -505,7 +505,14 @@ const result = await generateText({
|
|
|
505
505
|
});
|
|
506
506
|
```
|
|
507
507
|
|
|
508
|
-
You can also use YouTube URLs directly
|
|
508
|
+
You can also use YouTube URLs directly. Pass `videoMetadata` through
|
|
509
|
+
`providerOptions.google` on a video file part to clip a segment or control the
|
|
510
|
+
frame rate. This also works with inline video data and uploaded file URLs.
|
|
511
|
+
The metadata supports these optional fields:
|
|
512
|
+
|
|
513
|
+
- `startOffset` (string): Start time as a duration in seconds, e.g. `'60s'` or `'3.5s'`.
|
|
514
|
+
- `endOffset` (string): End time in the same duration format.
|
|
515
|
+
- `fps` (number): Frames per second in the range `(0, 24]`. The default is `1`.
|
|
509
516
|
|
|
510
517
|
```ts
|
|
511
518
|
import { google } from '@ai-sdk/google';
|
|
@@ -519,12 +526,21 @@ const result = await generateText({
|
|
|
519
526
|
content: [
|
|
520
527
|
{
|
|
521
528
|
type: 'text',
|
|
522
|
-
text: 'Summarize this video',
|
|
529
|
+
text: 'Summarize this part of the video',
|
|
523
530
|
},
|
|
524
531
|
{
|
|
525
532
|
type: 'file',
|
|
526
533
|
data: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
|
527
534
|
mediaType: 'video/mp4',
|
|
535
|
+
providerOptions: {
|
|
536
|
+
google: {
|
|
537
|
+
videoMetadata: {
|
|
538
|
+
startOffset: '60s',
|
|
539
|
+
endOffset: '600s',
|
|
540
|
+
fps: 1,
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
},
|
|
528
544
|
},
|
|
529
545
|
],
|
|
530
546
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.140",
|
|
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.19",
|
|
40
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
40
|
+
"@ai-sdk/provider-utils": "4.0.63"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "20.17.24",
|
|
@@ -8,11 +8,12 @@ import {
|
|
|
8
8
|
isUrlSupported,
|
|
9
9
|
secureJsonParse,
|
|
10
10
|
} from '@ai-sdk/provider-utils';
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
import {
|
|
12
|
+
googleVideoMetadataSchema,
|
|
13
|
+
type GoogleGenerativeAIContent,
|
|
14
|
+
type GoogleGenerativeAIContentPart,
|
|
15
|
+
type GoogleGenerativeAIFunctionResponsePart,
|
|
16
|
+
type GoogleGenerativeAIPrompt,
|
|
16
17
|
} from './google-generative-ai-prompt';
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -34,6 +35,7 @@ type GoogleProviderOptions = {
|
|
|
34
35
|
thoughtSignature?: unknown;
|
|
35
36
|
serverToolCallId?: unknown;
|
|
36
37
|
serverToolType?: unknown;
|
|
38
|
+
videoMetadata?: unknown;
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
function getGoogleProviderOptions(
|
|
@@ -313,6 +315,14 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
313
315
|
// default to image/jpeg for unknown image/* types
|
|
314
316
|
const mediaType =
|
|
315
317
|
part.mediaType === 'image/*' ? 'image/jpeg' : part.mediaType;
|
|
318
|
+
const rawVideoMetadata = getGoogleProviderOptions(
|
|
319
|
+
part.providerOptions,
|
|
320
|
+
providerOptionsName,
|
|
321
|
+
)?.videoMetadata;
|
|
322
|
+
const videoMetadata =
|
|
323
|
+
rawVideoMetadata == null
|
|
324
|
+
? undefined
|
|
325
|
+
: googleVideoMetadataSchema.parse(rawVideoMetadata);
|
|
316
326
|
|
|
317
327
|
parts.push(
|
|
318
328
|
part.data instanceof URL
|
|
@@ -325,12 +335,14 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
325
335
|
? part.originalUrl
|
|
326
336
|
: part.data.toString(),
|
|
327
337
|
},
|
|
338
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
328
339
|
}
|
|
329
340
|
: {
|
|
330
341
|
inlineData: {
|
|
331
342
|
mimeType: mediaType,
|
|
332
343
|
data: convertToBase64(part.data),
|
|
333
344
|
},
|
|
345
|
+
...(videoMetadata != null ? { videoMetadata } : {}),
|
|
334
346
|
},
|
|
335
347
|
);
|
|
336
348
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
1
2
|
import {
|
|
2
3
|
type GroundingMetadataSchema,
|
|
3
4
|
type PromptFeedbackSchema,
|
|
@@ -20,9 +21,24 @@ export type GoogleGenerativeAIContent = {
|
|
|
20
21
|
parts: Array<GoogleGenerativeAIContentPart>;
|
|
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 GoogleGenerativeAIContentPart =
|
|
24
37
|
| { text: string; thought?: boolean; thoughtSignature?: string }
|
|
25
|
-
| {
|
|
38
|
+
| {
|
|
39
|
+
inlineData: { mimeType: string; data: string };
|
|
40
|
+
videoMetadata?: GoogleVideoMetadata;
|
|
41
|
+
}
|
|
26
42
|
| {
|
|
27
43
|
functionCall: { id?: string; name: string; args: unknown };
|
|
28
44
|
thoughtSignature?: string;
|
|
@@ -35,7 +51,10 @@ export type GoogleGenerativeAIContentPart =
|
|
|
35
51
|
parts?: Array<GoogleGenerativeAIFunctionResponsePart>;
|
|
36
52
|
};
|
|
37
53
|
}
|
|
38
|
-
| {
|
|
54
|
+
| {
|
|
55
|
+
fileData: { mimeType: string; fileUri: string };
|
|
56
|
+
videoMetadata?: GoogleVideoMetadata;
|
|
57
|
+
}
|
|
39
58
|
| {
|
|
40
59
|
toolCall: {
|
|
41
60
|
toolType: string;
|
|
@@ -51,8 +51,14 @@ export class GoogleJSONAccumulator {
|
|
|
51
51
|
let delta = '';
|
|
52
52
|
|
|
53
53
|
for (const arg of partialArgs) {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Vertex terminates an array with a value-less `$.path[]` entry. For an
|
|
55
|
+
// empty array, that terminator is the only entry sent for the path.
|
|
56
|
+
const isArrayTerminator = arg.jsonPath.endsWith('[]');
|
|
57
|
+
const jsonPath = isArrayTerminator
|
|
58
|
+
? arg.jsonPath.slice(0, -2)
|
|
59
|
+
: arg.jsonPath;
|
|
60
|
+
const rawPath = jsonPath.replace(/^\$\./, '');
|
|
61
|
+
if (!rawPath || rawPath === '$') continue;
|
|
56
62
|
|
|
57
63
|
const segments = parsePath(rawPath);
|
|
58
64
|
|
|
@@ -72,7 +78,20 @@ export class GoogleJSONAccumulator {
|
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
const resolved = resolvePartialArgValue(arg);
|
|
75
|
-
if (resolved == null)
|
|
81
|
+
if (resolved == null) {
|
|
82
|
+
// A value-less entry for a path without a value is an empty container
|
|
83
|
+
// (an empty container has no leaves to stream). Value-less entries for
|
|
84
|
+
// existing paths are string or array terminators and are ignored.
|
|
85
|
+
if (existingValue !== undefined || arg.willContinue === true) continue;
|
|
86
|
+
|
|
87
|
+
setNestedValue(
|
|
88
|
+
this.accumulatedArgs,
|
|
89
|
+
segments,
|
|
90
|
+
isArrayTerminator ? [] : {},
|
|
91
|
+
);
|
|
92
|
+
delta += this.emitContainer(segments, isArrayTerminator);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
76
95
|
|
|
77
96
|
setNestedValue(this.accumulatedArgs, segments, resolved.value);
|
|
78
97
|
delta += this.emitNavigationTo(segments, arg, resolved.json);
|
|
@@ -141,6 +160,36 @@ export class GoogleJSONAccumulator {
|
|
|
141
160
|
return fragment;
|
|
142
161
|
}
|
|
143
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Navigates to `targetSegments` and opens a container there. The container
|
|
165
|
+
* stays open so later entries for its children continue inside it; it is
|
|
166
|
+
* closed by subsequent navigation or by `finalize()`.
|
|
167
|
+
*
|
|
168
|
+
* Input: targetSegments=["nested","tags"], isArray=true
|
|
169
|
+
* Output: '{"nested":{"tags":['
|
|
170
|
+
*/
|
|
171
|
+
private emitContainer(
|
|
172
|
+
targetSegments: PathSegment[],
|
|
173
|
+
isArray: boolean,
|
|
174
|
+
): string {
|
|
175
|
+
let fragment = '';
|
|
176
|
+
|
|
177
|
+
if (this.stringOpen) {
|
|
178
|
+
fragment += '"';
|
|
179
|
+
this.stringOpen = false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
fragment += this.ensureRoot();
|
|
183
|
+
|
|
184
|
+
const commonDepth = this.findCommonStackDepth(targetSegments);
|
|
185
|
+
|
|
186
|
+
fragment += this.closeDownTo(commonDepth);
|
|
187
|
+
// openDownTo infers the innermost container type from the leaf segment type
|
|
188
|
+
fragment += this.openDownTo(targetSegments, isArray ? 0 : '');
|
|
189
|
+
|
|
190
|
+
return fragment;
|
|
191
|
+
}
|
|
192
|
+
|
|
144
193
|
/**
|
|
145
194
|
* Returns the stack depth to preserve when navigating to a new target
|
|
146
195
|
* container path. Always >= 1 (the root is never popped).
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,10 @@ export type {
|
|
|
4
4
|
/** @deprecated Use `GoogleLanguageModelOptions` instead. */
|
|
5
5
|
GoogleLanguageModelOptions as GoogleGenerativeAIProviderOptions,
|
|
6
6
|
} from './google-generative-ai-options';
|
|
7
|
-
export type {
|
|
7
|
+
export type {
|
|
8
|
+
GoogleGenerativeAIProviderMetadata,
|
|
9
|
+
GoogleVideoMetadata,
|
|
10
|
+
} from './google-generative-ai-prompt';
|
|
8
11
|
export type {
|
|
9
12
|
GoogleImageModelOptions,
|
|
10
13
|
/** @deprecated Use `GoogleImageModelOptions` instead. */
|