@ai-sdk/google 3.0.88 → 3.0.90
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 +20 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +140 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +142 -25
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.d.mts +54 -1
- package/dist/internal/index.d.ts +54 -1
- package/dist/internal/index.js +2902 -2
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +2930 -3
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/convert-to-google-generative-ai-messages.ts +3 -3
- package/src/google-generative-ai-embedding-model.ts +1 -1
- package/src/google-provider.ts +39 -0
- package/src/interactions/build-google-interactions-stream-transform.ts +49 -1
- package/src/interactions/convert-google-interactions-usage.ts +22 -0
- package/src/interactions/convert-to-google-interactions-input.ts +2 -2
- package/src/interactions/google-interactions-api.ts +24 -0
- package/src/interactions/google-interactions-language-model.ts +9 -1
- package/src/interactions/google-interactions-provider-metadata.ts +8 -0
- package/src/interactions/parse-google-interactions-outputs.ts +33 -1
- package/src/internal/index.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.90",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@ai-sdk/provider": "3.0.13",
|
|
40
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
40
|
+
"@ai-sdk/provider-utils": "4.0.37"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "20.17.24",
|
|
44
44
|
"tsup": "^8",
|
|
45
45
|
"typescript": "5.8.3",
|
|
46
46
|
"zod": "3.25.76",
|
|
47
|
-
"@
|
|
48
|
-
"@ai-
|
|
47
|
+
"@ai-sdk/test-server": "1.0.6",
|
|
48
|
+
"@vercel/ai-tsconfig": "0.0.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"zod": "^3.25.76 || ^4.1.8"
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
type LanguageModelV3Prompt,
|
|
4
4
|
type SharedV3Warning,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
|
-
import { convertToBase64 } from '@ai-sdk/provider-utils';
|
|
6
|
+
import { convertToBase64, secureJsonParse } from '@ai-sdk/provider-utils';
|
|
7
7
|
import type {
|
|
8
8
|
GoogleGenerativeAIContent,
|
|
9
9
|
GoogleGenerativeAIContentPart,
|
|
@@ -385,7 +385,7 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
385
385
|
toolType: serverToolType,
|
|
386
386
|
args:
|
|
387
387
|
typeof part.input === 'string'
|
|
388
|
-
?
|
|
388
|
+
? secureJsonParse(part.input)
|
|
389
389
|
: part.input,
|
|
390
390
|
id: serverToolCallId,
|
|
391
391
|
},
|
|
@@ -510,7 +510,7 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
510
510
|
name: part.toolName,
|
|
511
511
|
content:
|
|
512
512
|
output.type === 'execution-denied'
|
|
513
|
-
? (output.reason ?? 'Tool execution denied.')
|
|
513
|
+
? (output.reason ?? 'Tool call execution denied.')
|
|
514
514
|
: output.value,
|
|
515
515
|
},
|
|
516
516
|
},
|
|
@@ -29,7 +29,7 @@ type GoogleGenerativeAIEmbeddingConfig = {
|
|
|
29
29
|
export class GoogleGenerativeAIEmbeddingModel implements EmbeddingModelV3 {
|
|
30
30
|
readonly specificationVersion = 'v3';
|
|
31
31
|
readonly modelId: GoogleGenerativeAIEmbeddingModelId;
|
|
32
|
-
readonly maxEmbeddingsPerCall =
|
|
32
|
+
readonly maxEmbeddingsPerCall = 100;
|
|
33
33
|
readonly supportsParallelCalls = true;
|
|
34
34
|
|
|
35
35
|
private readonly config: GoogleGenerativeAIEmbeddingConfig;
|
package/src/google-provider.ts
CHANGED
|
@@ -141,6 +141,37 @@ export interface GoogleGenerativeAIProviderSettings {
|
|
|
141
141
|
name?: string;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
const supportedExternalUrlMediaTypes = [
|
|
145
|
+
'text/html',
|
|
146
|
+
'text/css',
|
|
147
|
+
'text/plain',
|
|
148
|
+
'text/xml',
|
|
149
|
+
'text/csv',
|
|
150
|
+
'text/rtf',
|
|
151
|
+
'text/javascript',
|
|
152
|
+
'application/json',
|
|
153
|
+
'application/pdf',
|
|
154
|
+
'image/bmp',
|
|
155
|
+
'image/jpeg',
|
|
156
|
+
'image/png',
|
|
157
|
+
'image/webp',
|
|
158
|
+
'video/mp4',
|
|
159
|
+
'video/mpeg',
|
|
160
|
+
'video/quicktime',
|
|
161
|
+
'video/avi',
|
|
162
|
+
'video/x-flv',
|
|
163
|
+
'video/mpg',
|
|
164
|
+
'video/webm',
|
|
165
|
+
'video/wmv',
|
|
166
|
+
'video/3gpp',
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const externalHttpsUrlPattern = /^https:\/\/.*$/;
|
|
170
|
+
|
|
171
|
+
function supportsExternalFileUrls(modelId: string) {
|
|
172
|
+
return /(^|\/)gemini-/.test(modelId) && !/(^|\/)gemini-2\.0/.test(modelId);
|
|
173
|
+
}
|
|
174
|
+
|
|
144
175
|
/**
|
|
145
176
|
* Create a Google Generative AI provider instance.
|
|
146
177
|
*/
|
|
@@ -183,6 +214,14 @@ export function createGoogleGenerativeAI(
|
|
|
183
214
|
),
|
|
184
215
|
new RegExp(`^https://youtu\\.be/[\\w-]+(?:\\?[\\w=&.-]*)?$`),
|
|
185
216
|
],
|
|
217
|
+
...(supportsExternalFileUrls(modelId)
|
|
218
|
+
? Object.fromEntries(
|
|
219
|
+
supportedExternalUrlMediaTypes.map(mediaType => [
|
|
220
|
+
mediaType,
|
|
221
|
+
[externalHttpsUrlPattern],
|
|
222
|
+
]),
|
|
223
|
+
)
|
|
224
|
+
: {}),
|
|
186
225
|
}),
|
|
187
226
|
fetch: options.fetch,
|
|
188
227
|
});
|
|
@@ -11,7 +11,10 @@ import type {
|
|
|
11
11
|
GoogleInteractionsEvent,
|
|
12
12
|
GoogleInteractionsUsage,
|
|
13
13
|
} from './google-interactions-api';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
convertGoogleInteractionsUsage,
|
|
16
|
+
getGoogleInteractionsOutputTokensByModality,
|
|
17
|
+
} from './convert-google-interactions-usage';
|
|
15
18
|
import {
|
|
16
19
|
annotationsToSources,
|
|
17
20
|
builtinToolResultToSources,
|
|
@@ -490,6 +493,47 @@ export function buildGoogleInteractionsStreamTransform({
|
|
|
490
493
|
break;
|
|
491
494
|
}
|
|
492
495
|
|
|
496
|
+
/*
|
|
497
|
+
* `video` deltas inside `model_output` carry the full payload in a
|
|
498
|
+
* single chunk (no per-byte streaming), mirroring `image`. Emit the
|
|
499
|
+
* `file` part as soon as the delta arrives so it surfaces regardless
|
|
500
|
+
* of whether a text block is currently open at the same index.
|
|
501
|
+
*/
|
|
502
|
+
if (
|
|
503
|
+
dtype === 'video' &&
|
|
504
|
+
(open.kind === 'pending_model_output' || open.kind === 'text')
|
|
505
|
+
) {
|
|
506
|
+
const videoDelta = event.delta as
|
|
507
|
+
| { data?: string; mime_type?: string; uri?: string }
|
|
508
|
+
| undefined;
|
|
509
|
+
const google: Record<string, string> = {};
|
|
510
|
+
if (interactionId != null) google.interactionId = interactionId;
|
|
511
|
+
const providerMetadata =
|
|
512
|
+
Object.keys(google).length > 0 ? { google } : undefined;
|
|
513
|
+
if (videoDelta?.data != null && videoDelta.data.length > 0) {
|
|
514
|
+
controller.enqueue({
|
|
515
|
+
type: 'file',
|
|
516
|
+
mediaType: videoDelta.mime_type ?? 'video/mp4',
|
|
517
|
+
data: videoDelta.data,
|
|
518
|
+
...(providerMetadata ? { providerMetadata } : {}),
|
|
519
|
+
});
|
|
520
|
+
} else if (videoDelta?.uri != null && videoDelta.uri.length > 0) {
|
|
521
|
+
const uriProviderMetadata = {
|
|
522
|
+
google: {
|
|
523
|
+
...(interactionId != null ? { interactionId } : {}),
|
|
524
|
+
videoUri: videoDelta.uri,
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
controller.enqueue({
|
|
528
|
+
type: 'file',
|
|
529
|
+
mediaType: videoDelta.mime_type ?? 'video/mp4',
|
|
530
|
+
data: '',
|
|
531
|
+
providerMetadata: uriProviderMetadata,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
|
|
493
537
|
const delta = event.delta as
|
|
494
538
|
| {
|
|
495
539
|
type?: string;
|
|
@@ -824,10 +868,14 @@ export function buildGoogleInteractionsStreamTransform({
|
|
|
824
868
|
raw: finishStatus,
|
|
825
869
|
};
|
|
826
870
|
|
|
871
|
+
const outputTokensByModality =
|
|
872
|
+
getGoogleInteractionsOutputTokensByModality(usage);
|
|
873
|
+
|
|
827
874
|
const providerMetadata: SharedV3ProviderMetadata = {
|
|
828
875
|
google: {
|
|
829
876
|
...(interactionId != null ? { interactionId } : {}),
|
|
830
877
|
...(serviceTier != null ? { serviceTier } : {}),
|
|
878
|
+
...(outputTokensByModality != null ? { outputTokensByModality } : {}),
|
|
831
879
|
},
|
|
832
880
|
};
|
|
833
881
|
|
|
@@ -45,3 +45,25 @@ export function convertGoogleInteractionsUsage(
|
|
|
45
45
|
raw: usage as unknown as JSONObject,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Extracts the per-modality output token breakdown from an Interactions usage
|
|
51
|
+
* record (e.g. `{ video: 57920, text: 12 }`).
|
|
52
|
+
*/
|
|
53
|
+
export function getGoogleInteractionsOutputTokensByModality(
|
|
54
|
+
usage: GoogleInteractionsUsage | undefined | null,
|
|
55
|
+
): Record<string, number> | undefined {
|
|
56
|
+
const byModality = usage?.output_tokens_by_modality;
|
|
57
|
+
if (byModality == null) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const result: Record<string, number> = {};
|
|
62
|
+
for (const entry of byModality) {
|
|
63
|
+
if (entry?.modality != null && entry.tokens != null) {
|
|
64
|
+
result[entry.modality] = entry.tokens;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
69
|
+
}
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
LanguageModelV3ToolResultOutput,
|
|
5
5
|
SharedV3Warning,
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
|
-
import { convertToBase64 } from '@ai-sdk/provider-utils';
|
|
7
|
+
import { convertToBase64, secureJsonParse } from '@ai-sdk/provider-utils';
|
|
8
8
|
import type {
|
|
9
9
|
GoogleInteractionsContent,
|
|
10
10
|
GoogleInteractionsContentBlock,
|
|
@@ -372,7 +372,7 @@ function compactPromptForPreviousInteraction({
|
|
|
372
372
|
|
|
373
373
|
function safeParseToolArgs(input: string): Record<string, unknown> {
|
|
374
374
|
try {
|
|
375
|
-
const parsed =
|
|
375
|
+
const parsed = secureJsonParse(input);
|
|
376
376
|
if (
|
|
377
377
|
parsed != null &&
|
|
378
378
|
typeof parsed === 'object' &&
|
|
@@ -140,9 +140,19 @@ const contentBlockSchema = () => {
|
|
|
140
140
|
})
|
|
141
141
|
.loose();
|
|
142
142
|
|
|
143
|
+
const videoContent = z
|
|
144
|
+
.object({
|
|
145
|
+
type: z.literal('video'),
|
|
146
|
+
data: z.string().nullish(),
|
|
147
|
+
mime_type: z.string().nullish(),
|
|
148
|
+
uri: z.string().nullish(),
|
|
149
|
+
})
|
|
150
|
+
.loose();
|
|
151
|
+
|
|
143
152
|
return z.union([
|
|
144
153
|
textContent,
|
|
145
154
|
imageContent,
|
|
155
|
+
videoContent,
|
|
146
156
|
z.object({ type: z.string() }).loose(),
|
|
147
157
|
]);
|
|
148
158
|
};
|
|
@@ -384,6 +394,19 @@ export const googleInteractionsEventSchema = lazySchema(() =>
|
|
|
384
394
|
})
|
|
385
395
|
.loose();
|
|
386
396
|
|
|
397
|
+
/*
|
|
398
|
+
* `video` deltas carry the entire payload per delta (`data` base64 +
|
|
399
|
+
* `mime_type`, or `uri`) — there is no per-byte streaming.
|
|
400
|
+
*/
|
|
401
|
+
const stepDeltaVideo = z
|
|
402
|
+
.object({
|
|
403
|
+
type: z.literal('video'),
|
|
404
|
+
data: z.string().nullish(),
|
|
405
|
+
mime_type: z.string().nullish(),
|
|
406
|
+
uri: z.string().nullish(),
|
|
407
|
+
})
|
|
408
|
+
.loose();
|
|
409
|
+
|
|
387
410
|
/*
|
|
388
411
|
* Built-in tool call/result step deltas mirror the shape of their step
|
|
389
412
|
* counterparts (full payload per delta — there is no per-token
|
|
@@ -419,6 +442,7 @@ export const googleInteractionsEventSchema = lazySchema(() =>
|
|
|
419
442
|
const stepDeltaUnion = z.union([
|
|
420
443
|
stepDeltaText,
|
|
421
444
|
stepDeltaImage,
|
|
445
|
+
stepDeltaVideo,
|
|
422
446
|
stepDeltaThoughtSummary,
|
|
423
447
|
stepDeltaThoughtSignature,
|
|
424
448
|
stepDeltaArgumentsDelta,
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
} from '@ai-sdk/provider-utils';
|
|
21
21
|
import { googleFailedResponseHandler } from '../google-error';
|
|
22
22
|
import { buildGoogleInteractionsStreamTransform } from './build-google-interactions-stream-transform';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
convertGoogleInteractionsUsage,
|
|
25
|
+
getGoogleInteractionsOutputTokensByModality,
|
|
26
|
+
} from './convert-google-interactions-usage';
|
|
24
27
|
import { convertToGoogleInteractionsInput } from './convert-to-google-interactions-input';
|
|
25
28
|
import {
|
|
26
29
|
googleInteractionsEventSchema,
|
|
@@ -519,10 +522,15 @@ export class GoogleInteractionsLanguageModel implements LanguageModelV3 {
|
|
|
519
522
|
* `response.id` is omitted when `store: false` (fully stateless mode), so
|
|
520
523
|
* `interactionId` is only surfaced when the API actually returned one.
|
|
521
524
|
*/
|
|
525
|
+
const outputTokensByModality = getGoogleInteractionsOutputTokensByModality(
|
|
526
|
+
response.usage,
|
|
527
|
+
);
|
|
528
|
+
|
|
522
529
|
const providerMetadata: SharedV3ProviderMetadata = {
|
|
523
530
|
google: {
|
|
524
531
|
...(interactionId != null ? { interactionId } : {}),
|
|
525
532
|
...(serviceTier != null ? { serviceTier } : {}),
|
|
533
|
+
...(outputTokensByModality != null ? { outputTokensByModality } : {}),
|
|
526
534
|
},
|
|
527
535
|
};
|
|
528
536
|
|
|
@@ -15,6 +15,14 @@ export type GoogleInteractionsProviderMetadata = {
|
|
|
15
15
|
*/
|
|
16
16
|
serviceTier?: string;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Output token counts keyed by modality (e.g. `{ video: 57920 }`), sourced
|
|
20
|
+
* from the Interactions API `output_tokens_by_modality`. Present only when
|
|
21
|
+
* the response reports a breakdown. Preview surface for per-modality billing;
|
|
22
|
+
* may be promoted to a first-class usage field later.
|
|
23
|
+
*/
|
|
24
|
+
outputTokensByModality?: Record<string, number>;
|
|
25
|
+
|
|
18
26
|
/**
|
|
19
27
|
* Per-block signature hash for backend validation. Set by the SDK on output
|
|
20
28
|
* reasoning / tool-call parts and round-tripped on input parts.
|
|
@@ -68,7 +68,7 @@ function builtinToolNameFromResultType(type: string): string {
|
|
|
68
68
|
* `LanguageModelV3Content[]`. Surfaces:
|
|
69
69
|
*
|
|
70
70
|
* - `model_output` steps: iterates `step.content[]` for `text` (with
|
|
71
|
-
* annotations → source parts) and `
|
|
71
|
+
* annotations → source parts), `image`, and `video` content blocks.
|
|
72
72
|
* - `thought` steps: emits a single `reasoning` part from `summary[*]`.
|
|
73
73
|
* - `function_call` steps: emits a `tool-call` part directly.
|
|
74
74
|
* - Built-in tool `*_call` / `*_result` steps (Google Search, Code Execution,
|
|
@@ -162,6 +162,38 @@ export function parseGoogleInteractionsOutputs({
|
|
|
162
162
|
},
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
+
} else if (blockType === 'video') {
|
|
166
|
+
const video = block as {
|
|
167
|
+
data?: string;
|
|
168
|
+
mime_type?: string;
|
|
169
|
+
uri?: string;
|
|
170
|
+
};
|
|
171
|
+
if (video.data != null && video.data.length > 0) {
|
|
172
|
+
content.push({
|
|
173
|
+
type: 'file',
|
|
174
|
+
mediaType: video.mime_type ?? 'video/mp4',
|
|
175
|
+
data: video.data,
|
|
176
|
+
...googleProviderMetadata({ interactionId }),
|
|
177
|
+
});
|
|
178
|
+
} else if (video.uri != null && video.uri.length > 0) {
|
|
179
|
+
/*
|
|
180
|
+
* V3 `LanguageModelV3File` only supports inline data (`string` /
|
|
181
|
+
* `Uint8Array`). URL-only video outputs cannot be represented as
|
|
182
|
+
* a file content part on the v3 spec; surface the URI through
|
|
183
|
+
* provider metadata so callers can still recover it.
|
|
184
|
+
*/
|
|
185
|
+
content.push({
|
|
186
|
+
type: 'file',
|
|
187
|
+
mediaType: video.mime_type ?? 'video/mp4',
|
|
188
|
+
data: '',
|
|
189
|
+
providerMetadata: {
|
|
190
|
+
google: {
|
|
191
|
+
...(interactionId != null ? { interactionId } : {}),
|
|
192
|
+
videoUri: video.uri,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
}
|
|
165
197
|
}
|
|
166
198
|
}
|
|
167
199
|
break;
|
package/src/internal/index.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export * from '../google-generative-ai-language-model';
|
|
2
2
|
export { googleTools } from '../google-tools';
|
|
3
3
|
export type { GoogleGenerativeAIModelId } from '../google-generative-ai-options';
|
|
4
|
+
export {
|
|
5
|
+
GoogleInteractionsLanguageModel,
|
|
6
|
+
type GoogleInteractionsModelInput,
|
|
7
|
+
} from '../interactions/google-interactions-language-model';
|
|
8
|
+
export type { GoogleInteractionsModelId } from '../interactions/google-interactions-language-model-options';
|
|
9
|
+
export type { GoogleInteractionsAgentName } from '../interactions/google-interactions-agent';
|