66 lines
2.6 KiB
Rust
66 lines
2.6 KiB
Rust
//! Wire-protocol size limits shared across the agent + manager
|
|
//! sockets. Caps on inline message bodies stop a single chatty agent
|
|
//! (or a misbehaving extra-MCP server) from flooding the broker
|
|
//! sqlite with megabyte-sized rows that then bloat every recipient's
|
|
//! wake-prompt context. Anything genuinely larger should be written
|
|
//! to a state file and the path sent as the body.
|
|
//!
|
|
//! Reminders get a separate auto-file escape hatch (see
|
|
//! `agent_server::handle_remind`) so callers don't have to think
|
|
//! about it — oversized reminder bodies get persisted to disk
|
|
//! transparently and the inbox sees a pointer.
|
|
|
|
/// Per-message body cap. Applies to `send`, `ask` question text,
|
|
/// `answer` body, and the stored inline form of a reminder. 4 KiB
|
|
/// catches the bulk of conversational overflow (status reports,
|
|
/// bullet-list summaries, short proposals) while staying small
|
|
/// enough that a backed-up inbox of ~10 unread messages only adds
|
|
/// ~40 KiB to the recipient's wake-prompt context. Genuinely
|
|
/// long-form artifacts (audit reports, full diffs, transcripts)
|
|
/// still belong in a state file — the error message on overflow
|
|
/// points callers at that escape hatch.
|
|
pub const MESSAGE_MAX_BYTES: usize = 4096;
|
|
|
|
/// Validate that `body` fits under [`MESSAGE_MAX_BYTES`]. Returns a
|
|
/// caller-ready error string (caller wraps in
|
|
/// `AgentResponse::Err`/`ManagerResponse::Err`) on failure.
|
|
///
|
|
/// `label` shows up in the error message verbatim — pass a short
|
|
/// noun like `"send"`, `"question"`, `"broadcast"` so the model can
|
|
/// tell which call got rejected.
|
|
pub fn check_size(label: &str, body: &str) -> Result<(), String> {
|
|
if body.len() > MESSAGE_MAX_BYTES {
|
|
Err(format!(
|
|
"{label} body too long ({} bytes, max {MESSAGE_MAX_BYTES}); write the \
|
|
payload to a file under your `/agents/<you>/state/` dir and send the \
|
|
path as the body instead",
|
|
body.len()
|
|
))
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn accepts_short_body() {
|
|
assert!(check_size("send", "hello").is_ok());
|
|
assert!(check_size("send", &"x".repeat(MESSAGE_MAX_BYTES)).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_oversize_body() {
|
|
let err = check_size("send", &"x".repeat(MESSAGE_MAX_BYTES + 1)).unwrap_err();
|
|
assert!(err.contains("send body too long"));
|
|
assert!(err.contains(&format!("max {MESSAGE_MAX_BYTES}")));
|
|
}
|
|
|
|
#[test]
|
|
fn label_threads_through() {
|
|
let err = check_size("question", &"x".repeat(MESSAGE_MAX_BYTES + 1)).unwrap_err();
|
|
assert!(err.starts_with("question body too long"));
|
|
}
|
|
}
|