🪨 feat: AWS Bedrock Document Uploads (#11912)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions

* feat: add aws bedrock upload to provider support

* chore: address copilot comments

* feat: add shared Bedrock document format types and MIME mapping

Bedrock Converse API accepts 9 document formats beyond PDF. Add
BedrockDocumentFormat union type, MIME-to-format mapping, and helpers
in data-provider so both client and backend can reference them.

* refactor: generalize Bedrock PDF validation to support all document types

Rename validateBedrockPdf to validateBedrockDocument with MIME-aware
logic: 4.5MB hard limit applies to all types, PDF header check only
runs for application/pdf. Adds test coverage for non-PDF documents.

* feat: support all Bedrock document formats in encoding pipeline

Widen file type gates to accept csv, doc, docx, xls, xlsx, html, txt,
md for Bedrock. Uses shared MIME-to-format map instead of hardcoded
'pdf'. Other providers' PDF-only paths remain unchanged.

* feat: expand Bedrock file upload UI to accept all document types

Add 'image_document_extended' upload type for Bedrock with accept
filters for all 9 supported formats. Update drag-and-drop validation
to use isBedrockDocumentType helper.

* fix: route Bedrock document types through provider pipeline
This commit is contained in:
Dustin Healy 2026-02-23 19:32:44 -08:00 committed by GitHub
parent b349f2f876
commit 1d0a4c501f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 528 additions and 47 deletions

View file

@ -1,5 +1,10 @@
import { Providers } from '@librechat/agents';
import { isOpenAILikeProvider, isDocumentSupportedProvider } from 'librechat-data-provider';
import {
isOpenAILikeProvider,
isBedrockDocumentType,
bedrockDocumentFormats,
isDocumentSupportedProvider,
} from 'librechat-data-provider';
import type { IMongoFile } from '@librechat/data-schemas';
import type {
AnthropicDocumentBlock,
@ -7,8 +12,8 @@ import type {
DocumentResult,
ServerRequest,
} from '~/types';
import { validatePdf, validateBedrockDocument } from '~/files/validation';
import { getFileStream, getConfiguredFileSizeLimit } from './utils';
import { validatePdf } from '~/files/validation';
/**
* Processes and encodes document files for various providers
@ -35,9 +40,15 @@ export async function encodeAndFormatDocuments(
const encodingMethods: Record<string, StrategyFunctions> = {};
const result: DocumentResult = { documents: [], files: [] };
const documentFiles = files.filter(
(file) => file.type === 'application/pdf' || file.type?.startsWith('application/'),
);
const isBedrock = provider === Providers.BEDROCK;
const isDocSupported = isDocumentSupportedProvider(provider);
const documentFiles = files.filter((file) => {
if (isBedrock && isBedrockDocumentType(file.type)) {
return true;
}
return file.type === 'application/pdf' || file.type?.startsWith('application/');
});
if (!documentFiles.length) {
return result;
@ -45,7 +56,10 @@ export async function encodeAndFormatDocuments(
const results = await Promise.allSettled(
documentFiles.map((file) => {
if (file.type !== 'application/pdf' || !isDocumentSupportedProvider(provider)) {
const isProcessable = isBedrock
? isBedrockDocumentType(file.type)
: file.type === 'application/pdf' && isDocSupported;
if (!isProcessable) {
return Promise.resolve(null);
}
return getFileStream(req, file, encodingMethods, getStrategyFunctions);
@ -68,14 +82,40 @@ export async function encodeAndFormatDocuments(
continue;
}
if (file.type === 'application/pdf' && isDocumentSupportedProvider(provider)) {
const pdfBuffer = Buffer.from(content, 'base64');
const configuredFileSizeLimit = getConfiguredFileSizeLimit(req, { provider, endpoint });
const mimeType = file.type ?? '';
/** Extract configured file size limit from fileConfig for this endpoint */
const configuredFileSizeLimit = getConfiguredFileSizeLimit(req, {
provider,
endpoint,
if (isBedrock && isBedrockDocumentType(mimeType)) {
const fileBuffer = Buffer.from(content, 'base64');
const format = bedrockDocumentFormats[mimeType];
const validation = await validateBedrockDocument(
fileBuffer.length,
mimeType,
fileBuffer,
configuredFileSizeLimit,
);
if (!validation.isValid) {
throw new Error(`Document validation failed: ${validation.error}`);
}
const sanitizedName = (file.filename || 'document')
.replace(/[^a-zA-Z0-9\s\-()[\]]/g, '_')
.slice(0, 200);
result.documents.push({
type: 'document',
document: {
name: sanitizedName,
format,
source: {
bytes: fileBuffer,
},
},
});
result.files.push(metadata);
} else if (file.type === 'application/pdf' && isDocSupported) {
const pdfBuffer = Buffer.from(content, 'base64');
const validation = await validatePdf(
pdfBuffer,