🧑‍💼 feat: Add Agent Model Validation (#8995)

* fix: Update logger import to use data-schemas module

* feat: agent model validation

* fix: Remove invalid error messages from translation file
This commit is contained in:
Danny Avila 2025-08-11 14:26:28 -04:00 committed by GitHub
parent 8cefa566da
commit c5ca621efd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 189 additions and 54 deletions

View file

@ -1,4 +1,7 @@
import { z } from 'zod';
import { ViolationTypes, ErrorTypes } from 'librechat-data-provider';
import type { Agent, TModelsConfig } from 'librechat-data-provider';
import type { Request, Response } from 'express';
/** Avatar schema shared between create and update */
export const agentAvatarSchema = z.object({
@ -59,3 +62,90 @@ export const agentUpdateSchema = agentBaseSchema.extend({
removeProjectIds: z.array(z.string()).optional(),
isCollaborative: z.boolean().optional(),
});
interface ValidateAgentModelParams {
req: Request;
res: Response;
agent: Agent;
modelsConfig: TModelsConfig;
logViolation: (
req: Request,
res: Response,
type: string,
errorMessage: Record<string, unknown>,
score?: number | string,
) => Promise<void>;
}
interface ValidateAgentModelResult {
isValid: boolean;
error?: {
message: string;
};
}
/**
* Validates an agent's model against the available models configuration.
* This is a non-middleware version of validateModel that can be used
* in service initialization flows.
*
* @param params - Validation parameters
* @returns Object indicating whether the model is valid and any error details
*/
export async function validateAgentModel(
params: ValidateAgentModelParams,
): Promise<ValidateAgentModelResult> {
const { req, res, agent, modelsConfig, logViolation } = params;
const { model, provider: endpoint } = agent;
if (!model) {
return {
isValid: false,
error: {
message: `{ "type": "${ErrorTypes.MISSING_MODEL}", "info": "${endpoint}" }`,
},
};
}
if (!modelsConfig) {
return {
isValid: false,
error: {
message: `{ "type": "${ErrorTypes.MODELS_NOT_LOADED}" }`,
},
};
}
const availableModels = modelsConfig[endpoint];
if (!availableModels) {
return {
isValid: false,
error: {
message: `{ "type": "${ErrorTypes.ENDPOINT_MODELS_NOT_LOADED}", "info": "${endpoint}" }`,
},
};
}
const validModel = !!availableModels.find((availableModel) => availableModel === model);
if (validModel) {
return { isValid: true };
}
const { ILLEGAL_MODEL_REQ_SCORE: score = 1 } = process.env ?? {};
const type = ViolationTypes.ILLEGAL_MODEL_REQUEST;
const errorMessage = {
type,
model,
endpoint,
};
await logViolation(req, res, type, errorMessage, score);
return {
isValid: false,
error: {
message: `{ "type": "${ViolationTypes.ILLEGAL_MODEL_REQUEST}", "info": "${endpoint}|${model}" }`,
},
};
}

View file

@ -1347,6 +1347,18 @@ export enum ErrorTypes {
* Invalid Agent Provider (excluded by Admin)
*/
INVALID_AGENT_PROVIDER = 'invalid_agent_provider',
/**
* Missing model selection
*/
MISSING_MODEL = 'missing_model',
/**
* Models configuration not loaded
*/
MODELS_NOT_LOADED = 'models_not_loaded',
/**
* Endpoint models not loaded
*/
ENDPOINT_MODELS_NOT_LOADED = 'endpoint_models_not_loaded',
}
/**