reminder: fix symlink escape + db bloat cap + handler consistency

This commit is contained in:
damocles 2026-05-17 11:26:59 +02:00
parent 3da6912e73
commit 753409a5ef
4 changed files with 121 additions and 37 deletions

View file

@ -177,7 +177,7 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
message,
timing,
file_path,
} => handle_remind(broker, agent, message, timing, file_path.as_deref()),
} => handle_remind(coord, agent, message, timing, file_path.as_deref()),
}
}
@ -214,7 +214,7 @@ fn handle_ask_operator(
}
}
/// Cap on the inline `message` byte length the Remind request accepts.
/// Cap on the inline `message` byte length when no `file_path` is set.
/// Reminders land in the agent's inbox and feed the next wake prompt — a
/// multi-kilobyte body bloats every subsequent turn's context. Anything
/// bigger should be persisted to disk by the caller and pointed at via
@ -222,19 +222,31 @@ fn handle_ask_operator(
/// than the full body).
const REMIND_MESSAGE_MAX: usize = 4096;
/// Upper cap when `file_path` IS set. The body still lands in the
/// reminders sqlite row until delivery, so without an upper bound a
/// caller could DOS the broker DB with a single multi-megabyte
/// reminder. 64 KiB is generous for any reasonable payload + keeps a
/// single row small enough that sqlite won't choke.
const REMIND_MESSAGE_MAX_WITH_FILE: usize = 64 * 1024;
fn handle_remind(
broker: &crate::broker::Broker,
coord: &Arc<Coordinator>,
agent: &str,
message: &str,
timing: &hive_sh4re::ReminderTiming,
file_path: Option<&str>,
) -> AgentResponse {
if file_path.is_none() && message.len() > REMIND_MESSAGE_MAX {
let (cap, hint) = match file_path {
None => (
REMIND_MESSAGE_MAX,
"; set `file_path` to persist a larger payload to a file instead",
),
Some(_) => (REMIND_MESSAGE_MAX_WITH_FILE, ""),
};
if message.len() > cap {
return AgentResponse::Err {
message: format!(
"reminder body too long ({} bytes, max {REMIND_MESSAGE_MAX}); write the \
payload to a file under your /state/ dir and pass its path as \
`file_path` so the reminder delivers a pointer instead of the full body",
"reminder body too long ({} bytes, max {cap}){hint}",
message.len()
),
};
@ -247,7 +259,7 @@ fn handle_remind(
};
}
};
match broker.store_reminder(agent, message, file_path, due_at) {
match coord.broker.store_reminder(agent, message, file_path, due_at) {
Ok(id) => {
tracing::info!(%id, %agent, %due_at, "reminder scheduled");
AgentResponse::Ok