use a2a_protocol_types::message::Message;
use a2a_protocol_types::params::MessageSendParams;
use super::super::RequestHandler;
use super::super::helpers::{validate_id, validate_metadata_object};
use super::decisions::json_byte_len;
use crate::error::{ServerError, ServerResult};
impl RequestHandler {
pub(super) fn validate_send_params(&self, params: &mut MessageSendParams) -> ServerResult<()> {
unset_proto3_empty_ids(&mut params.message);
validate_id(
¶ms.message.id.0,
"message.id",
self.limits.effective_max_message_id_length(),
)?;
if let Some(ref ctx_id) = params.message.context_id {
validate_id(&ctx_id.0, "context_id", self.limits.max_id_length)?;
}
if let Some(ref task_id) = params.message.task_id {
validate_id(&task_id.0, "task_id", self.limits.max_id_length)?;
}
if params.message.parts.is_empty() {
return Err(ServerError::InvalidParams(
"message must contain at least one part".into(),
));
}
self.ensure_input_modes_supported(¶ms.message)?;
validate_metadata_object(params.message.metadata.as_ref(), "message")?;
validate_metadata_object(params.metadata.as_ref(), "request")?;
for (i, part) in params.message.parts.iter().enumerate() {
validate_metadata_object(part.metadata.as_ref(), &format!("message part {i}"))?;
}
let max_meta = self.limits.max_metadata_size;
check_metadata_size(params.message.metadata.as_ref(), "message", max_meta)?;
check_metadata_size(params.metadata.as_ref(), "request", max_meta)
}
}
fn check_metadata_size(
metadata: Option<&serde_json::Value>,
what: &str,
max_meta: usize,
) -> ServerResult<()> {
let Some(meta) = metadata else {
return Ok(());
};
let meta_size = json_byte_len(meta)
.map_err(|_| ServerError::InvalidParams(format!("{what} metadata is not serializable")))?;
if meta_size > max_meta {
return Err(ServerError::InvalidParams(format!(
"{what} metadata exceeds maximum size ({meta_size} bytes, max {max_meta})"
)));
}
Ok(())
}
fn unset_proto3_empty_ids(message: &mut Message) {
if message.context_id.as_ref().is_some_and(|c| c.0.is_empty()) {
message.context_id = None;
}
if message.task_id.as_ref().is_some_and(|t| t.0.is_empty()) {
message.task_id = None;
}
}