use std::path::PathBuf;
use std::time::Duration;
use crate::context::ContextBudget;
use crate::verify::Verification;
#[derive(Debug, Clone)]
pub struct TaskContract {
pub goal: String,
pub file: PathBuf,
pub root: Option<PathBuf>,
pub constraints: Vec<String>,
pub verify: Verification,
pub max_steps: u32,
pub max_duration: Option<Duration>,
pub max_tokens: Option<u64>,
pub max_retries: u32,
#[allow(clippy::doc_markdown)]
pub mcp: Vec<crate::mcp::McpServer>,
pub tools: crate::tools::Toolbox,
pub context: ContextBudget,
pub skills: Option<PathBuf>,
}
impl TaskContract {
pub fn new(goal: impl Into<String>, file: impl Into<PathBuf>, verify: Verification) -> Self {
Self {
goal: goal.into(),
file: file.into(),
root: None,
constraints: Vec::new(),
verify,
max_steps: 8,
max_duration: None,
max_tokens: None,
max_retries: 2,
mcp: Vec::new(),
tools: crate::tools::Toolbox::new(),
context: ContextBudget::default(),
skills: None,
}
}
pub fn workspace(
goal: impl Into<String>,
root: impl Into<PathBuf>,
verify: Verification,
) -> Self {
let root = root.into();
Self {
goal: goal.into(),
file: root.clone(),
root: Some(root),
constraints: Vec::new(),
verify,
max_steps: 12,
max_duration: None,
max_tokens: None,
max_retries: 2,
mcp: Vec::new(),
tools: crate::tools::Toolbox::new(),
context: ContextBudget::default(),
skills: None,
}
}
pub fn with_mcp<I>(mut self, servers: I) -> Self
where
I: IntoIterator<Item = crate::mcp::McpServer>,
{
self.mcp = servers.into_iter().collect();
self
}
pub fn with_tools(mut self, tools: crate::tools::Toolbox) -> Self {
self.tools = tools;
self
}
pub fn with_skills(mut self, dir: impl Into<PathBuf>) -> Self {
self.skills = Some(dir.into());
self
}
pub(crate) fn discover_skills(&self) -> crate::Result<crate::skills::Skills> {
match &self.skills {
Some(dir) => crate::skills::Skills::discover(dir),
None => Ok(crate::skills::Skills::none()),
}
}
pub fn with_max_steps(mut self, max_steps: u32) -> Self {
self.max_steps = max_steps;
self
}
pub fn with_time_budget(mut self, max_duration: Duration) -> Self {
self.max_duration = Some(max_duration);
self
}
pub fn with_token_budget(mut self, max_tokens: u64) -> Self {
self.max_tokens = Some(max_tokens);
self
}
pub fn with_context_budget(mut self, context: ContextBudget) -> Self {
self.context = context;
self
}
pub fn with_max_retries(mut self, max_retries: u32) -> Self {
self.max_retries = max_retries;
self
}
pub fn with_constraint(mut self, constraint: impl Into<String>) -> Self {
self.constraints.push(constraint.into());
self
}
}