use std::time::Duration;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Bounds {
pub deadline: Option<Duration>,
pub tool_budget: Option<usize>,
pub token_budget: Option<u64>,
}
impl Bounds {
pub fn new() -> Self {
Self::default()
}
pub fn with_deadline(self, deadline: Duration) -> Self {
Self {
deadline: Some(deadline),
..self
}
}
pub fn with_tool_budget(self, tool_budget: usize) -> Self {
Self {
tool_budget: Some(tool_budget),
..self
}
}
pub fn with_token_budget(self, token_budget: u64) -> Self {
Self {
token_budget: Some(token_budget),
..self
}
}
#[must_use]
pub fn or(self, fallback: Self) -> Self {
Self {
deadline: self.deadline.or(fallback.deadline),
tool_budget: self.tool_budget.or(fallback.tool_budget),
token_budget: self.token_budget.or(fallback.token_budget),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builders_return_new_values() {
let base = Bounds::new();
let bounded = base.with_deadline(Duration::from_secs(60));
assert_eq!(base.deadline, None, "the original must be untouched");
assert_eq!(bounded.deadline, Some(Duration::from_secs(60)));
}
#[test]
fn an_explicit_bound_wins_and_a_configured_one_fills_in() {
let explicit = Bounds::new().with_deadline(Duration::from_secs(30));
let configured = Bounds::new()
.with_deadline(Duration::from_secs(600))
.with_tool_budget(12);
let merged = explicit.or(configured);
assert_eq!(merged.deadline, Some(Duration::from_secs(30)));
assert_eq!(merged.tool_budget, Some(12));
assert_eq!(merged.token_budget, None, "unset stays unset");
}
}