🖼️ feat: File Size and MIME Type Filtering at Agent level (#10446)

* refactor: add image file size validation as part of payload build

* feat: implement file size and MIME type filtering in endpoint configuration

* chore: import order
This commit is contained in:
Danny Avila 2025-11-10 21:36:48 -05:00 committed by GitHub
parent b443254151
commit 937563f645
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 768 additions and 7 deletions

View file

@ -1,12 +1,14 @@
const axios = require('axios');
const { logAxiosError } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { logAxiosError, validateImage } = require('@librechat/api');
const {
FileSources,
VisionModes,
ImageDetail,
ContentTypes,
EModelEndpoint,
mergeFileConfig,
getEndpointFileConfig,
} = require('librechat-data-provider');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
@ -152,6 +154,17 @@ async function encodeAndFormat(req, files, params, mode) {
const formattedImages = await Promise.all(promises);
promises.length = 0;
/** Extract configured file size limit from fileConfig for this endpoint */
let configuredFileSizeLimit;
if (req.config?.fileConfig) {
const fileConfig = mergeFileConfig(req.config.fileConfig);
const endpointConfig = getEndpointFileConfig({
fileConfig,
endpoint: effectiveEndpoint,
});
configuredFileSizeLimit = endpointConfig?.fileSizeLimit;
}
for (const [file, imageContent] of formattedImages) {
const fileMetadata = {
type: file.type,
@ -172,6 +185,26 @@ async function encodeAndFormat(req, files, params, mode) {
continue;
}
/** Validate image buffer against size limits */
if (file.height && file.width) {
const imageBuffer = imageContent.startsWith('http')
? null
: Buffer.from(imageContent, 'base64');
if (imageBuffer) {
const validation = await validateImage(
imageBuffer,
imageBuffer.length,
effectiveEndpoint,
configuredFileSizeLimit,
);
if (!validation.isValid) {
throw new Error(`Image validation failed for ${file.filename}: ${validation.error}`);
}
}
}
const imagePart = {
type: ContentTypes.IMAGE_URL,
image_url: {