LibreChat/api/server/middleware/buildEndpointOption.js
Danny Avila 75bbefb1c8
📎 fix: Scope Attachment Usage to Request Owner (#13557)
* fix: harden attachment usage handling

* fix: sort file method imports

* fix: clarify file usage scope
2026-06-06 14:23:04 -04:00

150 lines
4.8 KiB
JavaScript

const {
handleError,
applyModelSpecPreset,
findModelSpecByName,
isModelSpecEndpointMatch,
resolveModelSpecPromptPrefixVariables,
} = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const {
EndpointURLs,
EModelEndpoint,
isAgentsEndpoint,
parseCompactConvo,
getDefaultParamsEndpoint,
} = require('librechat-data-provider');
const azureAssistants = require('~/server/services/Endpoints/azureAssistants');
const assistants = require('~/server/services/Endpoints/assistants');
const { getEndpointsConfig } = require('~/server/services/Config');
const agents = require('~/server/services/Endpoints/agents');
const { updateFilesUsage } = require('~/models');
const buildFunction = {
[EModelEndpoint.agents]: agents.buildOptions,
[EModelEndpoint.assistants]: assistants.buildOptions,
[EModelEndpoint.azureAssistants]: azureAssistants.buildOptions,
};
async function buildEndpointOption(req, res, next) {
const { endpoint, endpointType } = req.body;
const isAgents =
isAgentsEndpoint(endpoint) || req.baseUrl.startsWith(EndpointURLs[EModelEndpoint.agents]);
let endpointsConfig;
try {
endpointsConfig = await getEndpointsConfig(req);
} catch (error) {
logger.error('Error fetching endpoints config in buildEndpointOption', error);
}
const defaultParamsEndpoint = getDefaultParamsEndpoint(endpointsConfig, endpoint);
let parsedBody;
try {
parsedBody = parseCompactConvo({
endpoint,
endpointType,
conversation: req.body,
defaultParamsEndpoint,
});
} catch (error) {
logger.error(`Error parsing compact conversation for endpoint ${endpoint}`, error);
logger.debug({
'Error parsing compact conversation': { endpoint, endpointType, conversation: req.body },
});
return handleError(res, { text: 'Error parsing conversation' });
}
const appConfig = req.config;
let appliedModelSpecPrivateFields = new Set();
if (appConfig.modelSpecs?.list?.length && appConfig.modelSpecs?.enforce) {
/** @type {{ list: TModelSpec[] }}*/
const { list } = appConfig.modelSpecs;
const { spec } = parsedBody;
if (!spec) {
return handleError(res, { text: 'No model spec selected' });
}
const currentModelSpec = findModelSpecByName({ list }, spec);
if (!currentModelSpec) {
return handleError(res, { text: 'Invalid model spec' });
}
if (!isModelSpecEndpointMatch(currentModelSpec, endpoint)) {
return handleError(res, { text: 'Model spec mismatch' });
}
try {
const result = applyModelSpecPreset({
modelSpec: currentModelSpec,
parsedBody: currentModelSpec.preset,
endpoint,
endpointType,
defaultParamsEndpoint,
includePresetDefaults: true,
});
parsedBody = result.parsedBody;
appliedModelSpecPrivateFields = result.appliedPrivateFields;
} catch (error) {
logger.error(`Error parsing model spec for endpoint ${endpoint}`, error);
return handleError(res, { text: 'Error parsing model spec' });
}
} else if (parsedBody.spec && appConfig.modelSpecs?.list) {
const modelSpec = findModelSpecByName(appConfig.modelSpecs, parsedBody.spec);
if (modelSpec) {
if (!isModelSpecEndpointMatch(modelSpec, endpoint)) {
return handleError(res, { text: 'Model spec mismatch' });
}
try {
const result = applyModelSpecPreset({
modelSpec,
parsedBody,
endpoint,
endpointType,
defaultParamsEndpoint,
});
parsedBody = result.parsedBody;
appliedModelSpecPrivateFields = result.appliedPrivateFields;
} catch (error) {
logger.error(`Error parsing model spec for endpoint ${endpoint}`, error);
return handleError(res, { text: 'Error parsing model spec' });
}
}
}
if (!isAgents && appliedModelSpecPrivateFields.has('promptPrefix')) {
parsedBody = resolveModelSpecPromptPrefixVariables(
parsedBody,
req.user,
req.body.clientTimestamp,
);
}
try {
const builder = isAgents
? (...args) => buildFunction[EModelEndpoint.agents](req, ...args)
: buildFunction[endpointType ?? endpoint];
// TODO: use object params
req.body = req.body || {}; // Express 5: ensure req.body exists
req.body.endpointOption = await builder(endpoint, parsedBody, endpointType);
if (req.body.files && !isAgents) {
req.body.endpointOption.attachments = updateFilesUsage(req.body.files, undefined, {
user: req.user.id,
});
}
next();
} catch (error) {
logger.error(
`Error building endpoint option for endpoint ${endpoint} with type ${endpointType}`,
error,
);
return handleError(res, { text: 'Error building endpoint option' });
}
}
module.exports = buildEndpointOption;