Skip to main content

saorsa_agent/config/
mod.rs

1//! Agent configuration.
2
3pub mod auth;
4pub mod import;
5pub mod models;
6pub mod paths;
7pub mod settings;
8
9use crate::context::ContextBundle;
10
11/// Configuration for the agent loop.
12#[derive(Clone, Debug)]
13pub struct AgentConfig {
14    /// The LLM model to use.
15    pub model: String,
16    /// The system prompt.
17    pub system_prompt: String,
18    /// Maximum number of agent turns before stopping.
19    pub max_turns: u32,
20    /// Maximum tokens per response.
21    pub max_tokens: u32,
22    /// Context bundle (AGENTS.md, SYSTEM.md, user context).
23    pub context: ContextBundle,
24}
25
26impl AgentConfig {
27    /// Create a new agent config with the given model.
28    pub fn new(model: impl Into<String>) -> Self {
29        Self {
30            model: model.into(),
31            system_prompt: "You are a helpful assistant.".into(),
32            max_turns: 10,
33            max_tokens: 4096,
34            context: ContextBundle::new(),
35        }
36    }
37
38    /// Set the system prompt.
39    #[must_use]
40    pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
41        self.system_prompt = prompt.into();
42        self
43    }
44
45    /// Set the maximum number of turns.
46    #[must_use]
47    pub fn max_turns(mut self, max: u32) -> Self {
48        self.max_turns = max;
49        self
50    }
51
52    /// Set the maximum tokens per response.
53    #[must_use]
54    pub fn max_tokens(mut self, max: u32) -> Self {
55        self.max_tokens = max;
56        self
57    }
58
59    /// Set the context bundle.
60    #[must_use]
61    pub fn context(mut self, context: ContextBundle) -> Self {
62        self.context = context;
63        self
64    }
65}
66
67impl Default for AgentConfig {
68    fn default() -> Self {
69        Self::new("claude-sonnet-4-5-20250929")
70    }
71}
72
73#[cfg(test)]
74#[allow(clippy::unwrap_used)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn default_config() {
80        let config = AgentConfig::default();
81        assert_eq!(config.model, "claude-sonnet-4-5-20250929");
82        assert_eq!(config.max_turns, 10);
83        assert_eq!(config.max_tokens, 4096);
84        assert!(!config.system_prompt.is_empty());
85    }
86
87    #[test]
88    fn builder_pattern() {
89        let config = AgentConfig::new("claude-opus-4-20250514")
90            .system_prompt("Be concise")
91            .max_turns(5)
92            .max_tokens(8192);
93        assert_eq!(config.model, "claude-opus-4-20250514");
94        assert_eq!(config.system_prompt, "Be concise");
95        assert_eq!(config.max_turns, 5);
96        assert_eq!(config.max_tokens, 8192);
97    }
98
99    #[test]
100    fn new_custom_model() {
101        let config = AgentConfig::new("gpt-4");
102        assert_eq!(config.model, "gpt-4");
103    }
104}