Skip to main content

ironflow_engine/config/
agent.rs

1//! [`AgentStepConfig`] — serializable configuration for an agent step.
2
3use serde::{Deserialize, Serialize};
4
5/// Serializable configuration for an agent step.
6///
7/// # Examples
8///
9/// ```
10/// use ironflow_engine::config::AgentStepConfig;
11///
12/// let config = AgentStepConfig::new("Review this code for security issues")
13///     .model("haiku")
14///     .max_budget_usd(0.10);
15/// ```
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct AgentStepConfig {
18    /// The user prompt.
19    pub prompt: String,
20    /// Optional system prompt.
21    pub system_prompt: Option<String>,
22    /// Model name (e.g. "sonnet", "opus", "haiku").
23    pub model: Option<String>,
24    /// Maximum budget in USD.
25    pub max_budget_usd: Option<f64>,
26    /// Maximum number of agentic turns.
27    pub max_turns: Option<u32>,
28    /// Tool allowlist.
29    pub allowed_tools: Vec<String>,
30    /// Working directory for the agent.
31    pub working_dir: Option<String>,
32    /// Permission mode (e.g. "auto", "dont_ask").
33    pub permission_mode: Option<String>,
34}
35
36impl AgentStepConfig {
37    /// Create a new agent config with the given prompt.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use ironflow_engine::config::AgentStepConfig;
43    ///
44    /// let config = AgentStepConfig::new("Summarize this file");
45    /// assert_eq!(config.prompt, "Summarize this file");
46    /// ```
47    pub fn new(prompt: &str) -> Self {
48        Self {
49            prompt: prompt.to_string(),
50            system_prompt: None,
51            model: None,
52            max_budget_usd: None,
53            max_turns: None,
54            allowed_tools: Vec::new(),
55            working_dir: None,
56            permission_mode: None,
57        }
58    }
59
60    /// Set the system prompt.
61    pub fn system_prompt(mut self, prompt: &str) -> Self {
62        self.system_prompt = Some(prompt.to_string());
63        self
64    }
65
66    /// Set the model name.
67    pub fn model(mut self, model: &str) -> Self {
68        self.model = Some(model.to_string());
69        self
70    }
71
72    /// Set the maximum budget in USD.
73    pub fn max_budget_usd(mut self, budget: f64) -> Self {
74        self.max_budget_usd = Some(budget);
75        self
76    }
77
78    /// Set the maximum number of turns.
79    pub fn max_turns(mut self, turns: u32) -> Self {
80        self.max_turns = Some(turns);
81        self
82    }
83
84    /// Add an allowed tool.
85    pub fn allow_tool(mut self, tool: &str) -> Self {
86        self.allowed_tools.push(tool.to_string());
87        self
88    }
89
90    /// Set the working directory.
91    pub fn working_dir(mut self, dir: &str) -> Self {
92        self.working_dir = Some(dir.to_string());
93        self
94    }
95
96    /// Set the permission mode.
97    pub fn permission_mode(mut self, mode: &str) -> Self {
98        self.permission_mode = Some(mode.to_string());
99        self
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn builder() {
109        let config = AgentStepConfig::new("Review code")
110            .system_prompt("You are a code reviewer")
111            .model("haiku")
112            .max_budget_usd(0.50)
113            .max_turns(5)
114            .allow_tool("read")
115            .working_dir("/repo")
116            .permission_mode("auto");
117
118        assert_eq!(config.prompt, "Review code");
119        assert_eq!(config.system_prompt.unwrap(), "You are a code reviewer");
120        assert_eq!(config.model.unwrap(), "haiku");
121        assert_eq!(config.allowed_tools, vec!["read"]);
122    }
123}