1use crate::agent::Agent;
7use crate::client::LlmClient;
8use serde_json::Value;
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum AgentType {
13 Sgr,
15 ToolCalling,
17 Flexible,
19 Hybrid,
21 Planning,
23}
24
25impl AgentType {
26 pub fn from_str_loose(s: &str) -> Option<Self> {
28 match s.to_lowercase().as_str() {
29 "sgr" | "structured" => Some(Self::Sgr),
30 "tool_calling" | "toolcalling" | "fc" | "function_calling" => Some(Self::ToolCalling),
31 "flexible" | "text" | "iron" => Some(Self::Flexible),
32 "hybrid" | "sgr_tool_calling" => Some(Self::Hybrid),
33 "planning" | "plan" | "read_only" => Some(Self::Planning),
34 _ => None,
35 }
36 }
37}
38
39#[derive(Debug, Clone)]
41pub struct AgentConfig {
42 pub agent_type: AgentType,
43 pub system_prompt: String,
44 pub max_retries: usize,
46 pub max_reasoning_tools: usize,
48}
49
50impl Default for AgentConfig {
51 fn default() -> Self {
52 Self {
53 agent_type: AgentType::Sgr,
54 system_prompt: String::new(),
55 max_retries: 1,
56 max_reasoning_tools: 1,
57 }
58 }
59}
60
61impl AgentConfig {
62 pub fn from_value(val: &Value) -> Result<Self, String> {
74 let agent_type = val
75 .get("type")
76 .and_then(|t| t.as_str())
77 .and_then(AgentType::from_str_loose)
78 .unwrap_or(AgentType::Sgr);
79
80 let system_prompt = val
81 .get("system_prompt")
82 .and_then(|s| s.as_str())
83 .unwrap_or("")
84 .to_string();
85
86 let max_retries = val.get("max_retries").and_then(|v| v.as_u64()).unwrap_or(1) as usize;
87
88 let max_reasoning_tools = val
89 .get("max_reasoning_tools")
90 .and_then(|v| v.as_u64())
91 .unwrap_or(1) as usize;
92
93 Ok(Self {
94 agent_type,
95 system_prompt,
96 max_retries,
97 max_reasoning_tools,
98 })
99 }
100}
101
102pub fn create_agent<C: LlmClient + Clone + 'static>(
106 config: &AgentConfig,
107 client: C,
108) -> Box<dyn Agent> {
109 match config.agent_type {
110 AgentType::Sgr => Box::new(crate::agents::sgr::SgrAgent::new(
111 client,
112 &config.system_prompt,
113 )),
114 AgentType::ToolCalling => Box::new(crate::agents::tool_calling::ToolCallingAgent::new(
115 client,
116 &config.system_prompt,
117 )),
118 AgentType::Flexible => Box::new(crate::agents::flexible::FlexibleAgent::new(
119 client,
120 &config.system_prompt,
121 config.max_retries,
122 )),
123 AgentType::Hybrid => Box::new(crate::agents::hybrid::HybridAgent::new(
124 client,
125 &config.system_prompt,
126 )),
127 AgentType::Planning => {
128 let inner = Box::new(crate::agents::sgr::SgrAgent::new(
129 client,
130 &config.system_prompt,
131 ));
132 Box::new(crate::agents::planning::PlanningAgent::new(inner))
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use serde_json::json;
141
142 #[test]
143 fn agent_type_from_str() {
144 assert_eq!(AgentType::from_str_loose("sgr"), Some(AgentType::Sgr));
145 assert_eq!(
146 AgentType::from_str_loose("structured"),
147 Some(AgentType::Sgr)
148 );
149 assert_eq!(
150 AgentType::from_str_loose("tool_calling"),
151 Some(AgentType::ToolCalling)
152 );
153 assert_eq!(
154 AgentType::from_str_loose("fc"),
155 Some(AgentType::ToolCalling)
156 );
157 assert_eq!(
158 AgentType::from_str_loose("flexible"),
159 Some(AgentType::Flexible)
160 );
161 assert_eq!(AgentType::from_str_loose("text"), Some(AgentType::Flexible));
162 assert_eq!(AgentType::from_str_loose("hybrid"), Some(AgentType::Hybrid));
163 assert_eq!(AgentType::from_str_loose("unknown"), None);
164 }
165
166 #[test]
167 fn config_from_value() {
168 let val = json!({
169 "type": "flexible",
170 "system_prompt": "You are a test agent.",
171 "max_retries": 5
172 });
173 let config = AgentConfig::from_value(&val).unwrap();
174 assert_eq!(config.agent_type, AgentType::Flexible);
175 assert_eq!(config.system_prompt, "You are a test agent.");
176 assert_eq!(config.max_retries, 5);
177 }
178
179 #[test]
180 fn config_defaults() {
181 let val = json!({});
182 let config = AgentConfig::from_value(&val).unwrap();
183 assert_eq!(config.agent_type, AgentType::Sgr);
184 assert!(config.system_prompt.is_empty());
185 assert_eq!(config.max_retries, 1);
186 }
187
188 #[test]
189 fn config_default_struct() {
190 let config = AgentConfig::default();
191 assert_eq!(config.agent_type, AgentType::Sgr);
192 assert_eq!(config.max_retries, 1);
193 }
194}