@ai-sdk/google 4.0.0-canary.63 → 4.0.0-canary.65
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 +12 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +510 -335
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.js +43 -28
- package/dist/internal/index.js.map +1 -1
- package/docs/15-google.mdx +72 -16
- package/package.json +1 -1
- package/src/convert-to-google-messages.ts +20 -2
- package/src/google-language-model.ts +5 -4
- package/src/google-prompt.ts +5 -1
- package/src/interactions/build-google-interactions-stream-transform.ts +273 -154
- package/src/interactions/convert-to-google-interactions-input.ts +57 -143
- package/src/interactions/extract-google-interactions-sources.ts +3 -3
- package/src/interactions/google-interactions-api.ts +179 -115
- package/src/interactions/google-interactions-language-model-options.ts +61 -0
- package/src/interactions/google-interactions-language-model.ts +100 -38
- package/src/interactions/google-interactions-prompt.ts +189 -114
- package/src/interactions/map-google-interactions-finish-reason.ts +3 -5
- package/src/interactions/parse-google-interactions-outputs.ts +69 -63
- package/src/interactions/prepare-google-interactions-tools.ts +1 -1
- package/src/interactions/stream-google-interactions.ts +1 -1
- package/src/interactions/synthesize-google-interactions-agent-stream.ts +1 -1
package/docs/15-google.mdx
CHANGED
|
@@ -1154,21 +1154,28 @@ The following optional provider options are available:
|
|
|
1154
1154
|
Whether the model returns synthesized thought summaries on reasoning
|
|
1155
1155
|
parts. Defaults to the API default.
|
|
1156
1156
|
|
|
1157
|
-
- **
|
|
1157
|
+
- **responseFormat** _Array\<\{ type: 'text' | 'image' | 'audio'; mimeType?: string; schema?: unknown; aspectRatio?: string; imageSize?: '1K' \| '2K' \| '4K' \| '512' \}\>_
|
|
1158
1158
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1159
|
+
Output-format entries that map directly to the API's `response_format`
|
|
1160
|
+
array. Use this for fine-grained control over image, audio, or non-JSON
|
|
1161
|
+
text outputs (e.g. `aspectRatio` and `imageSize` for image generation).
|
|
1162
|
+
The AI SDK call-level `responseFormat: { type: 'json', schema }` still
|
|
1163
|
+
drives JSON-mode automatically and prepends a matching text entry;
|
|
1164
|
+
entries listed here are appended.
|
|
1162
1165
|
|
|
1163
|
-
|
|
1166
|
+
`aspectRatio` accepts `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`,
|
|
1167
|
+
`9:16`, `16:9`, `21:9`, `1:8`, `8:1`, `1:4`, `4:1`.
|
|
1164
1168
|
|
|
1165
|
-
|
|
1169
|
+
- **imageConfig** _\{ aspectRatio?: string; imageSize?: '1K' | '2K' | '4K' | '512' \}_ (deprecated)
|
|
1166
1170
|
|
|
1167
|
-
|
|
1171
|
+
Use **responseFormat** with a `{ type: 'image', ... }` entry instead.
|
|
1172
|
+
Retained for backwards compatibility; the SDK translates `imageConfig`
|
|
1173
|
+
into a matching `response_format` image entry and emits a warning when
|
|
1174
|
+
set. Ignored when `responseFormat` already supplies an image entry.
|
|
1168
1175
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1176
|
+
- **mediaResolution** _'low' | 'medium' | 'high' | 'ultra_high'_
|
|
1177
|
+
|
|
1178
|
+
Media resolution applied to image inputs / outputs.
|
|
1172
1179
|
|
|
1173
1180
|
- **serviceTier** _'flex' | 'standard' | 'priority'_
|
|
1174
1181
|
|
|
@@ -1321,9 +1328,10 @@ const { text, toolCalls } = await generateText({
|
|
|
1321
1328
|
|
|
1322
1329
|
### Image output via Interactions
|
|
1323
1330
|
|
|
1324
|
-
|
|
1325
|
-
images as `LanguageModelV4FilePart` files in
|
|
1326
|
-
is required
|
|
1331
|
+
Add a `{ type: 'image' }` entry to `responseFormat` on a Gemini
|
|
1332
|
+
image-capable model to get images as `LanguageModelV4FilePart` files in
|
|
1333
|
+
the response. No tool wrapping is required, and the entry doubles as the
|
|
1334
|
+
place to set `aspectRatio`, `imageSize`, and `mimeType`.
|
|
1327
1335
|
|
|
1328
1336
|
```ts
|
|
1329
1337
|
import { google } from '@ai-sdk/google';
|
|
@@ -1334,7 +1342,7 @@ const result = await generateText({
|
|
|
1334
1342
|
prompt: 'Generate an image of a comic cat in a spaceship.',
|
|
1335
1343
|
providerOptions: {
|
|
1336
1344
|
google: {
|
|
1337
|
-
|
|
1345
|
+
responseFormat: [{ type: 'image' }],
|
|
1338
1346
|
},
|
|
1339
1347
|
},
|
|
1340
1348
|
});
|
|
@@ -1346,6 +1354,54 @@ for (const file of result.files) {
|
|
|
1346
1354
|
}
|
|
1347
1355
|
```
|
|
1348
1356
|
|
|
1357
|
+
To control aspect ratio, image size, or output mime type, add those
|
|
1358
|
+
fields to the same image entry:
|
|
1359
|
+
|
|
1360
|
+
```ts
|
|
1361
|
+
const result = await generateText({
|
|
1362
|
+
model: google.interactions('gemini-3-pro-image-preview'),
|
|
1363
|
+
prompt: 'Generate a high-quality landscape photo of mountains at sunset.',
|
|
1364
|
+
providerOptions: {
|
|
1365
|
+
google: {
|
|
1366
|
+
responseFormat: [
|
|
1367
|
+
{
|
|
1368
|
+
type: 'image',
|
|
1369
|
+
aspectRatio: '16:9',
|
|
1370
|
+
imageSize: '4K',
|
|
1371
|
+
},
|
|
1372
|
+
],
|
|
1373
|
+
},
|
|
1374
|
+
},
|
|
1375
|
+
});
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
For multimodal output, list one entry per modality. The model returns
|
|
1379
|
+
text in `result.text` and the accompanying image(s) in `result.files`:
|
|
1380
|
+
|
|
1381
|
+
```ts
|
|
1382
|
+
import { google } from '@ai-sdk/google';
|
|
1383
|
+
import { generateText } from 'ai';
|
|
1384
|
+
|
|
1385
|
+
const result = await generateText({
|
|
1386
|
+
model: google.interactions('gemini-2.5-flash-image'),
|
|
1387
|
+
prompt:
|
|
1388
|
+
'Tell me a three sentence bedtime story about a unicorn, accompanied by a suitable illustration.',
|
|
1389
|
+
providerOptions: {
|
|
1390
|
+
google: {
|
|
1391
|
+
responseFormat: [
|
|
1392
|
+
{ type: 'text' },
|
|
1393
|
+
{ type: 'image', aspectRatio: '16:9' },
|
|
1394
|
+
],
|
|
1395
|
+
},
|
|
1396
|
+
},
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
console.log(result.text);
|
|
1400
|
+
|
|
1401
|
+
const images = result.files.filter(file => file.mediaType.startsWith('image/'));
|
|
1402
|
+
// images[0].uint8Array | images[0].base64 | images[0].mediaType
|
|
1403
|
+
```
|
|
1404
|
+
|
|
1349
1405
|
Iterative image editing pairs naturally with stateful chaining — keep
|
|
1350
1406
|
`previousInteractionId` set across turns and the model edits its prior
|
|
1351
1407
|
output:
|
|
@@ -1359,7 +1415,7 @@ const model = google.interactions('gemini-3-pro-image-preview');
|
|
|
1359
1415
|
const turn1 = await generateText({
|
|
1360
1416
|
model,
|
|
1361
1417
|
prompt: 'Generate an image of a comic cat in a spaceship.',
|
|
1362
|
-
providerOptions: { google: {
|
|
1418
|
+
providerOptions: { google: { responseFormat: [{ type: 'image' }] } },
|
|
1363
1419
|
});
|
|
1364
1420
|
|
|
1365
1421
|
const interactionId = turn1.providerMetadata?.google?.interactionId as
|
|
@@ -1371,7 +1427,7 @@ const turn2 = await generateText({
|
|
|
1371
1427
|
prompt: 'now make the cat red',
|
|
1372
1428
|
providerOptions: {
|
|
1373
1429
|
google: {
|
|
1374
|
-
|
|
1430
|
+
responseFormat: [{ type: 'image' }],
|
|
1375
1431
|
previousInteractionId: interactionId,
|
|
1376
1432
|
},
|
|
1377
1433
|
},
|
package/package.json
CHANGED
|
@@ -64,6 +64,7 @@ function appendToolResultParts(
|
|
|
64
64
|
LanguageModelV4ToolResultOutput,
|
|
65
65
|
{ type: 'content' }
|
|
66
66
|
>['value'],
|
|
67
|
+
toolCallId?: string,
|
|
67
68
|
): void {
|
|
68
69
|
const functionResponseParts: GoogleFunctionResponsePart[] = [];
|
|
69
70
|
const responseTextParts: string[] = [];
|
|
@@ -106,6 +107,7 @@ function appendToolResultParts(
|
|
|
106
107
|
|
|
107
108
|
parts.push({
|
|
108
109
|
functionResponse: {
|
|
110
|
+
...(toolCallId != null ? { id: toolCallId } : {}),
|
|
109
111
|
name: toolName,
|
|
110
112
|
response: {
|
|
111
113
|
name: toolName,
|
|
@@ -133,12 +135,14 @@ function appendLegacyToolResultParts(
|
|
|
133
135
|
LanguageModelV4ToolResultOutput,
|
|
134
136
|
{ type: 'content' }
|
|
135
137
|
>['value'],
|
|
138
|
+
toolCallId?: string,
|
|
136
139
|
): void {
|
|
137
140
|
for (const contentPart of outputValue) {
|
|
138
141
|
switch (contentPart.type) {
|
|
139
142
|
case 'text':
|
|
140
143
|
parts.push({
|
|
141
144
|
functionResponse: {
|
|
145
|
+
...(toolCallId != null ? { id: toolCallId } : {}),
|
|
142
146
|
name: toolName,
|
|
143
147
|
response: {
|
|
144
148
|
name: toolName,
|
|
@@ -447,6 +451,9 @@ export function convertToGoogleMessages(
|
|
|
447
451
|
|
|
448
452
|
return {
|
|
449
453
|
functionCall: {
|
|
454
|
+
...(part.toolCallId != null
|
|
455
|
+
? { id: part.toolCallId }
|
|
456
|
+
: {}),
|
|
450
457
|
name: part.toolName,
|
|
451
458
|
args: part.input,
|
|
452
459
|
},
|
|
@@ -533,13 +540,24 @@ export function convertToGoogleMessages(
|
|
|
533
540
|
|
|
534
541
|
if (output.type === 'content') {
|
|
535
542
|
if (supportsFunctionResponseParts) {
|
|
536
|
-
appendToolResultParts(
|
|
543
|
+
appendToolResultParts(
|
|
544
|
+
parts,
|
|
545
|
+
part.toolName,
|
|
546
|
+
output.value,
|
|
547
|
+
part.toolCallId,
|
|
548
|
+
);
|
|
537
549
|
} else {
|
|
538
|
-
appendLegacyToolResultParts(
|
|
550
|
+
appendLegacyToolResultParts(
|
|
551
|
+
parts,
|
|
552
|
+
part.toolName,
|
|
553
|
+
output.value,
|
|
554
|
+
part.toolCallId,
|
|
555
|
+
);
|
|
539
556
|
}
|
|
540
557
|
} else {
|
|
541
558
|
parts.push({
|
|
542
559
|
functionResponse: {
|
|
560
|
+
...(part.toolCallId != null ? { id: part.toolCallId } : {}),
|
|
543
561
|
name: part.toolName,
|
|
544
562
|
response: {
|
|
545
563
|
name: part.toolName,
|
|
@@ -387,7 +387,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
|
|
|
387
387
|
} else if ('functionCall' in part && part.functionCall.name != null) {
|
|
388
388
|
content.push({
|
|
389
389
|
type: 'tool-call' as const,
|
|
390
|
-
toolCallId: this.config.generateId(),
|
|
390
|
+
toolCallId: part.functionCall.id ?? this.config.generateId(),
|
|
391
391
|
toolName: part.functionCall.name,
|
|
392
392
|
input: JSON.stringify(part.functionCall.args ?? {}),
|
|
393
393
|
providerMetadata: part.thoughtSignature
|
|
@@ -838,7 +838,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
|
|
|
838
838
|
part.functionCall.name != null &&
|
|
839
839
|
part.functionCall.willContinue === true
|
|
840
840
|
) {
|
|
841
|
-
const toolCallId = generateId();
|
|
841
|
+
const toolCallId = part.functionCall.id ?? generateId();
|
|
842
842
|
const accumulator = new GoogleJSONAccumulator();
|
|
843
843
|
activeStreamingToolCalls.push({
|
|
844
844
|
toolCallId,
|
|
@@ -920,7 +920,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
|
|
|
920
920
|
|
|
921
921
|
hasToolCalls = true;
|
|
922
922
|
} else if (isCompleteCall) {
|
|
923
|
-
const toolCallId = generateId();
|
|
923
|
+
const toolCallId = part.functionCall.id ?? generateId();
|
|
924
924
|
const toolName = part.functionCall.name!;
|
|
925
925
|
const args =
|
|
926
926
|
typeof part.functionCall.args === 'string'
|
|
@@ -957,7 +957,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
|
|
|
957
957
|
|
|
958
958
|
hasToolCalls = true;
|
|
959
959
|
} else if (isNoArgsCompleteCall) {
|
|
960
|
-
const toolCallId = generateId();
|
|
960
|
+
const toolCallId = part.functionCall.id ?? generateId();
|
|
961
961
|
const toolName = part.functionCall.name!;
|
|
962
962
|
|
|
963
963
|
controller.enqueue({
|
|
@@ -1333,6 +1333,7 @@ const getContentSchema = () =>
|
|
|
1333
1333
|
// note: order matters since text can be fully empty
|
|
1334
1334
|
z.object({
|
|
1335
1335
|
functionCall: z.object({
|
|
1336
|
+
id: z.string().nullish(),
|
|
1336
1337
|
name: z.string().nullish(),
|
|
1337
1338
|
args: z.unknown().nullish(),
|
|
1338
1339
|
partialArgs: z.array(partialArgSchema).nullish(),
|
package/src/google-prompt.ts
CHANGED
|
@@ -27,9 +27,13 @@ export type GoogleContentPart =
|
|
|
27
27
|
thought?: boolean;
|
|
28
28
|
thoughtSignature?: string;
|
|
29
29
|
}
|
|
30
|
-
| {
|
|
30
|
+
| {
|
|
31
|
+
functionCall: { id?: string; name: string; args: unknown };
|
|
32
|
+
thoughtSignature?: string;
|
|
33
|
+
}
|
|
31
34
|
| {
|
|
32
35
|
functionResponse: {
|
|
36
|
+
id?: string;
|
|
33
37
|
name: string;
|
|
34
38
|
response: unknown;
|
|
35
39
|
parts?: Array<GoogleFunctionResponsePart>;
|