1use crate::types::{SgrError, ToolCall};
4
5#[derive(Debug, Clone)]
7pub struct Decision {
8 pub situation: String,
10 pub task: Vec<String>,
12 pub tool_calls: Vec<ToolCall>,
14 pub completed: bool,
16}
17
18#[derive(Debug, thiserror::Error)]
20pub enum AgentError {
21 #[error("LLM error: {0}")]
22 Llm(#[from] SgrError),
23 #[error("tool error: {0}")]
24 Tool(String),
25 #[error("loop detected after {0} iterations")]
26 LoopDetected(usize),
27 #[error("max steps reached: {0}")]
28 MaxSteps(usize),
29 #[error("cancelled")]
30 Cancelled,
31}
32
33#[async_trait::async_trait]
40pub trait Agent: Send + Sync {
41 async fn decide(
43 &self,
44 messages: &[crate::types::Message],
45 tools: &crate::registry::ToolRegistry,
46 ) -> Result<Decision, AgentError>;
47
48 fn prepare_context(
50 &self,
51 _ctx: &mut crate::context::AgentContext,
52 _messages: &[crate::types::Message],
53 ) {
54 }
55
56 fn prepare_tools(
59 &self,
60 _ctx: &crate::context::AgentContext,
61 tools: &crate::registry::ToolRegistry,
62 ) -> Vec<String> {
63 tools.list().iter().map(|t| t.name().to_string()).collect()
64 }
65
66 fn after_action(
69 &self,
70 _ctx: &mut crate::context::AgentContext,
71 _tool_name: &str,
72 _output: &str,
73 ) {
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn decision_completed() {
83 let d = Decision {
84 situation: "done".into(),
85 task: vec![],
86 tool_calls: vec![],
87 completed: true,
88 };
89 assert!(d.completed);
90 }
91
92 #[test]
93 fn agent_error_display() {
94 let err = AgentError::LoopDetected(5);
95 assert_eq!(err.to_string(), "loop detected after 5 iterations");
96 let err = AgentError::MaxSteps(50);
97 assert_eq!(err.to_string(), "max steps reached: 50");
98 }
99}