Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/popular-hounds-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@ai-sdk/provider': patch
'@ai-sdk/google': patch
'ai': patch
---

fix(google): add thought signature to gemini 3 pro image parts
31 changes: 31 additions & 0 deletions examples/ai-core/src/generate-text/google-image-multi-step.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { google } from '@ai-sdk/google';
import { generateText } from 'ai';

import { presentImages } from '../lib/present-image';
import { run } from '../lib/run';

import 'dotenv/config';

run(async () => {
const step1 = await generateText({
model: google('gemini-3-pro-image-preview'),
prompt:
'Create an image of Los Angeles where all car infrastructure has been replaced with bike infrastructure, trains, pedestrian zones, and parks. The image should be photorealistic and vibrant.',
});

await presentImages(step1.files);

const step2 = await generateText({
model: google('gemini-3-pro-image-preview'),
messages: [
...step1.response.messages,
{
role: 'user',
content:
'Now create a variation of the image, but in the style of a watercolor painting.',
},
],
});

await presentImages(step2.files);
});
3 changes: 3 additions & 0 deletions packages/ai/src/generate-text/generate-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,9 @@ function asContent<TOOLS extends ToolSet>({
return {
type: 'file' as const,
file: new DefaultGeneratedFile(part),
...(part.providerMetadata != null
? { providerMetadata: part.providerMetadata }
: {}),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,19 +323,6 @@ describe('assistant messages', () => {
});
});

it('should throw error for non-PNG images in assistant messages', async () => {
expect(() =>
convertToGoogleGenerativeAIMessages([
{
role: 'assistant',
content: [
{ type: 'file', data: 'AAECAw==', mediaType: 'image/jpeg' },
],
},
]),
).toThrow('Only PNG images are supported in assistant messages');
});

it('should throw error for URL file data in assistant messages', async () => {
expect(() =>
convertToGoogleGenerativeAIMessages([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,6 @@ export function convertToGoogleGenerativeAIMessages(
}

case 'file': {
if (part.mediaType !== 'image/png') {
throw new UnsupportedFunctionalityError({
functionality:
'Only PNG images are supported in assistant messages',
});
}

if (part.data instanceof URL) {
throw new UnsupportedFunctionalityError({
functionality:
Expand All @@ -126,6 +119,7 @@ export function convertToGoogleGenerativeAIMessages(
mimeType: part.mediaType,
data: convertToBase64(part.data),
},
thoughtSignature,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,7 @@ describe('doGenerate', () => {
{
"data": "base64encodedimagedata",
"mediaType": "image/jpeg",
"providerMetadata": undefined,
"type": "file",
},
{
Expand All @@ -1420,6 +1421,7 @@ describe('doGenerate', () => {
{
"data": "anotherbase64encodedimagedata",
"mediaType": "image/png",
"providerMetadata": undefined,
"type": "file",
},
]
Expand Down Expand Up @@ -1472,11 +1474,13 @@ describe('doGenerate', () => {
{
"data": "imagedata1",
"mediaType": "image/jpeg",
"providerMetadata": undefined,
"type": "file",
},
{
"data": "imagedata2",
"mediaType": "image/png",
"providerMetadata": undefined,
"type": "file",
},
]
Expand Down Expand Up @@ -1591,11 +1595,13 @@ describe('doGenerate', () => {
{
"data": "validimagedata",
"mediaType": "image/jpeg",
"providerMetadata": undefined,
"type": "file",
},
{
"data": "pdfdata",
"mediaType": "application/pdf",
"providerMetadata": undefined,
"type": "file",
},
]
Expand Down
4 changes: 4 additions & 0 deletions packages/google/src/google-generative-ai-language-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV2 {
type: 'file' as const,
data: part.inlineData.data,
mediaType: part.inlineData.mimeType,
providerMetadata: part.thoughtSignature
? { google: { thoughtSignature: part.thoughtSignature } }
: undefined,
});
}
}
Expand Down Expand Up @@ -809,6 +812,7 @@ const getContentSchema = () =>
mimeType: z.string(),
data: z.string(),
}),
thoughtSignature: z.string().nullish(),
}),
z.object({
executableCode: z
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SharedV2ProviderMetadata } from '../../shared';

/**
A file that has been generated by the model.
Generated files as base64 encoded strings or binary data.
Expand All @@ -22,4 +24,9 @@ as base64 encoded strings. If the API returns binary data, the file data should
be returned as binary data.
*/
data: string | Uint8Array;

/**
Optional provider-specific metadata for the file part.
*/
providerMetadata?: SharedV2ProviderMetadata;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

breaking change

};
Loading