-
Notifications
You must be signed in to change notification settings - Fork 28
Validate user messages on chat completions endpoint #383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Validate user messages on chat completions endpoint #383
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this particular endpoint currently, where /content
detectors are invokable on chat completions input or output, we would expect text content to be provided for the last message, with any of the roles that this endpoint will work for. The role validation is done here
fms-guardrails-orchestrator/src/orchestrator/handlers/chat_completions_detection/unary.rs
Line 121 in 6bc045f
Some(Role::User) | Some(Role::Assistant) | Some(Role::System) |
Thanks for catching that. I'm not super familiar with the codebase for this endpoint yet, so I wasn't sure that was the best place to put the validation. Request {
"messages": [
{
"role": "user",
"name": "string"
}
],
"model": "my_model_id",
"n": 1,
"temperature": 1,
"top_p": 1,
"user": "user-1234",
"detectors": {}
} Response {
"code": 422,
"details": "chat completion request failed for `my_model_id`: list index out of range"
} |
12acc24
to
fdc369e
Compare
Signed-off-by: Mateus Devino <mdevino@ibm.com>
Signed-off-by: Mateus Devino <mdevino@ibm.com>
fdc369e
to
9aac20d
Compare
let messages = if let Some(messages) = value.get("messages") { | ||
Vec::<Message>::deserialize(messages) | ||
.map_err(|_| ValidationError::Invalid("error deserializing `messages`".into())) | ||
.map(|messages| { | ||
for message in &messages { | ||
if message.role == Role::User && message.content.is_none() { | ||
return Err(ValidationError::Invalid( | ||
"`content` is mandatory for user messages".into(), | ||
)); | ||
} | ||
} | ||
Ok(messages) | ||
}) | ||
.map_err(|_| ValidationError::Invalid("error deserializing `messages`".into()))? | ||
} else { | ||
Err(ValidationError::Required("messages".into())) | ||
}?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is finished yet, but a better way to write this would be below. It's good to use any
/ all
iterator methods for stuff like this.
let messages = if let Some(messages) = value.get("messages") {
Vec::<Message>::deserialize(messages)
.map_err(|_| ValidationError::Invalid("error deserializing `messages`".into()))
} else {
Err(ValidationError::Required("messages".into()))
}?;
if messages
.iter()
.any(|message| message.role == Role::User && message.content.is_none())
{
return Err(ValidationError::Invalid(
"`content` is required for user messages".into(),
));
};
Btw, this just validates that Content
is provided, but the inner value Content::Text(text)
could still be an empty String
. Do we want to validate that it isn't empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not the final code yet. I just pushed what I have before going on vacations, so someone could pick up form there if needed. I like the any()
suggestion!
Closes #382.