mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
🧮 fix: Prevent String Corruption of Numeric Agent Model Parameters (#14119)
* 🧮 fix: Prevent String Corruption of Numeric Agent Model Parameters * 🧮 fix: Support Partial Numeric Input and Cover Parameter Aliases
This commit is contained in:
parent
1f7b38e972
commit
2d4ef52c22
8 changed files with 379 additions and 13 deletions
|
|
@ -9,6 +9,7 @@ const {
|
|||
refreshListAvatars,
|
||||
collectEdgeAgentIds,
|
||||
mergeAgentOcrConversion,
|
||||
sanitizeModelParameters,
|
||||
MAX_AVATAR_REFRESH_AGENTS,
|
||||
collectToolResourceFileIds,
|
||||
convertOcrToContextInPlace,
|
||||
|
|
@ -348,7 +349,10 @@ const createAgentHandler = async (req, res) => {
|
|||
const { tools = [], ...agentData } = removeNullishValues(validatedData);
|
||||
|
||||
if (agentData.model_parameters && typeof agentData.model_parameters === 'object') {
|
||||
agentData.model_parameters = removeNullishValues(agentData.model_parameters, true);
|
||||
agentData.model_parameters = removeNullishValues(
|
||||
sanitizeModelParameters(agentData.model_parameters),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
const { id: userId, role: userRole } = req.user;
|
||||
|
|
@ -604,7 +608,10 @@ const updateAgentHandler = async (req, res) => {
|
|||
const updateData = removeNullishValues(rest);
|
||||
|
||||
if (updateData.model_parameters && typeof updateData.model_parameters === 'object') {
|
||||
updateData.model_parameters = removeNullishValues(updateData.model_parameters, true);
|
||||
updateData.model_parameters = removeNullishValues(
|
||||
sanitizeModelParameters(updateData.model_parameters),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
if (avatarField === null) {
|
||||
|
|
|
|||
|
|
@ -500,6 +500,38 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
expect(agentInDb.model_parameters.maxContextTokens).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should drop non-numeric strings and coerce numeric strings in model_parameters', async () => {
|
||||
// Regression test for #12920: a stray placeholder string ("System") persisted
|
||||
// into max_tokens was forwarded to the provider, causing a 400
|
||||
const dataWithCorruptModelParams = {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
name: 'Agent with Corrupt Model Params',
|
||||
model_parameters: {
|
||||
max_tokens: 'System',
|
||||
maxContextTokens: '256000',
|
||||
fileTokenLimit: 256000,
|
||||
useResponsesApi: true,
|
||||
},
|
||||
};
|
||||
|
||||
mockReq.body = dataWithCorruptModelParams;
|
||||
|
||||
await createAgentHandler(mockReq, mockRes);
|
||||
|
||||
expect(mockRes.status).toHaveBeenCalledWith(201);
|
||||
|
||||
const createdAgent = mockRes.json.mock.calls[0][0];
|
||||
expect(createdAgent.model_parameters.max_tokens).toBeUndefined();
|
||||
expect(createdAgent.model_parameters.maxContextTokens).toBe(256000);
|
||||
expect(createdAgent.model_parameters.fileTokenLimit).toBe(256000);
|
||||
expect(createdAgent.model_parameters.useResponsesApi).toBe(true);
|
||||
|
||||
const agentInDb = await Agent.findOne({ id: createdAgent.id });
|
||||
expect(agentInDb.model_parameters.max_tokens).toBeUndefined();
|
||||
expect(agentInDb.model_parameters.maxContextTokens).toBe(256000);
|
||||
});
|
||||
|
||||
test('should handle invalid avatar format', async () => {
|
||||
const dataWithInvalidAvatar = {
|
||||
provider: 'openai',
|
||||
|
|
@ -697,6 +729,32 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
expect(agentInDb.name).toBe('Updated Agent');
|
||||
});
|
||||
|
||||
test('should sanitize corrupt numeric model_parameters on update', async () => {
|
||||
mockReq.user.id = existingAgentAuthorId.toString();
|
||||
mockReq.params.id = existingAgentId;
|
||||
mockReq.body = {
|
||||
name: 'Healed Agent',
|
||||
model_parameters: {
|
||||
max_tokens: 'System',
|
||||
maxContextTokens: 256000,
|
||||
temperature: '0.7',
|
||||
},
|
||||
};
|
||||
|
||||
await updateAgentHandler(mockReq, mockRes);
|
||||
|
||||
expect(mockRes.json).toHaveBeenCalled();
|
||||
|
||||
const updatedAgent = mockRes.json.mock.calls[0][0];
|
||||
expect(updatedAgent.model_parameters.max_tokens).toBeUndefined();
|
||||
expect(updatedAgent.model_parameters.maxContextTokens).toBe(256000);
|
||||
expect(updatedAgent.model_parameters.temperature).toBe(0.7);
|
||||
|
||||
const agentInDb = await Agent.findOne({ id: existingAgentId });
|
||||
expect(agentInDb.model_parameters.max_tokens).toBeUndefined();
|
||||
expect(agentInDb.model_parameters.maxContextTokens).toBe(256000);
|
||||
});
|
||||
|
||||
test('should reject update with unauthorized fields (mass assignment protection)', async () => {
|
||||
mockReq.user.id = existingAgentAuthorId.toString();
|
||||
mockReq.params.id = existingAgentId;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue