📎 fix: Preserve Gemini PDF Media Blocks (#13357)

This commit is contained in:
Danny Avila 2026-05-27 22:00:53 -07:00 committed by GitHub
parent f28599ea7c
commit f95fa55cce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 10 deletions

View file

@ -749,6 +749,38 @@ describe('encodeAndFormatDocuments - fileConfig integration', () => {
file_data: `data:application/pdf;base64,${mockContent}`,
});
});
it.each([Providers.GOOGLE, Providers.VERTEXAI] as const)(
'should format %s PDF as media block when responses API is enabled',
async (provider) => {
const req = createMockRequest(15, provider) as ServerRequest;
const file = createMockFile(10);
const mockContent = Buffer.from('test-pdf-content').toString('base64');
mockedGetFileStream.mockResolvedValue({
file,
content: mockContent,
metadata: file,
});
mockedValidatePdf.mockResolvedValue({ isValid: true });
const result = await encodeAndFormatDocuments(
req,
[file],
{ provider, useResponsesApi: true },
mockStrategyFunctions,
);
expect(result.documents).toHaveLength(1);
expect(result.documents[0]).toMatchObject({
type: 'media',
mimeType: 'application/pdf',
data: mockContent,
});
expect(result.documents[0]).not.toHaveProperty('type', 'input_file');
},
);
});
describe('Generic document encoding path', () => {

View file

@ -55,6 +55,14 @@ function formatDocumentBlock(
return document;
}
if (provider === Providers.GOOGLE || provider === Providers.VERTEXAI) {
return {
type: 'media',
mimeType,
data: content,
};
}
const resolvedFilename = filename ?? 'document';
if (useResponsesApi) {
@ -65,14 +73,6 @@ function formatDocumentBlock(
};
}
if (provider === Providers.GOOGLE || provider === Providers.VERTEXAI) {
return {
type: 'media',
mimeType,
data: content,
};
}
if (isOpenAILikeProvider(provider) && provider !== Providers.AZURE) {
return {
type: 'file',
@ -86,6 +86,18 @@ function formatDocumentBlock(
return null;
}
function getBase64DecodedByteCount(content: string): number {
let paddingChars = 0;
if (content.endsWith('==')) {
paddingChars = 2;
} else if (content.endsWith('=')) {
paddingChars = 1;
}
return Math.floor((content.length * 3) / 4) - paddingChars;
}
/**
* Encodes and formats document files for various providers.
*
@ -208,8 +220,7 @@ export async function encodeAndFormatDocuments(
result.files.push(metadata);
}
} else if (isDocSupported && !isBedrock) {
const paddingChars = content.endsWith('==') ? 2 : content.endsWith('=') ? 1 : 0;
const decodedByteCount = Math.floor((content.length * 3) / 4) - paddingChars;
const decodedByteCount = getBase64DecodedByteCount(content);
if (configuredFileSizeLimit && decodedByteCount > configuredFileSizeLimit) {
throw new Error(
`File size (~${(decodedByteCount / 1024 / 1024).toFixed(1)}MB) exceeds the configured limit for ${provider}`,