use std::collections::HashMap;
use std::time::Duration;
use ferrin_spec::ToolName;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Timeout {
pub total: Option<Duration>,
pub step: Option<Duration>,
pub first_chunk: Option<Duration>,
pub chunk: Option<Duration>,
pub tool: Option<Duration>,
pub per_tool: HashMap<ToolName, Duration>,
}
impl Timeout {
#[must_use]
pub fn none() -> Self {
Self::default()
}
#[must_use]
pub fn with_total(mut self, total: Duration) -> Self {
self.total = Some(total);
self
}
#[must_use]
pub fn with_step(mut self, step: Duration) -> Self {
self.step = Some(step);
self
}
#[must_use]
pub fn with_first_chunk(mut self, first_chunk: Duration) -> Self {
self.first_chunk = Some(first_chunk);
self
}
#[must_use]
pub fn with_chunk(mut self, chunk: Duration) -> Self {
self.chunk = Some(chunk);
self
}
#[must_use]
pub fn with_tool(mut self, tool: Duration) -> Self {
self.tool = Some(tool);
self
}
#[must_use]
pub fn with_tool_for(mut self, name: impl Into<ToolName>, timeout: Duration) -> Self {
self.per_tool.insert(name.into(), timeout);
self
}
#[must_use]
pub fn tool_timeout(&self, tool: &ToolName) -> Option<Duration> {
self.per_tool.get(tool).copied().or(self.tool)
}
}
impl From<Duration> for Timeout {
fn from(total: Duration) -> Self {
Self::default().with_total(total)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "scope", rename_all = "kebab-case")]
#[non_exhaustive]
pub enum TimeoutScope {
Total,
Step,
FirstChunk,
Chunk,
Tool {
tool_name: ToolName,
},
}
impl std::fmt::Display for TimeoutScope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Total => f.write_str("total"),
Self::Step => f.write_str("step"),
Self::FirstChunk => f.write_str("first chunk"),
Self::Chunk => f.write_str("chunk"),
Self::Tool { tool_name } => write!(f, "tool `{tool_name}`"),
}
}
}