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 async fn decide_stateful(
56 &self,
57 messages: &[crate::types::Message],
58 tools: &crate::registry::ToolRegistry,
59 _previous_response_id: Option<&str>,
60 ) -> Result<(Decision, Option<String>), AgentError> {
61 let d = self.decide(messages, tools).await?;
62 Ok((d, None))
63 }
64
65 fn prepare_context(
67 &self,
68 _ctx: &mut crate::context::AgentContext,
69 _messages: &[crate::types::Message],
70 ) {
71 }
72
73 fn prepare_tools(
76 &self,
77 _ctx: &crate::context::AgentContext,
78 tools: &crate::registry::ToolRegistry,
79 ) -> Vec<String> {
80 tools.list().iter().map(|t| t.name().to_string()).collect()
81 }
82
83 fn after_action(
86 &self,
87 _ctx: &mut crate::context::AgentContext,
88 _tool_name: &str,
89 _output: &str,
90 ) {
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn decision_completed() {
100 let d = Decision {
101 situation: "done".into(),
102 task: vec![],
103 tool_calls: vec![],
104 completed: true,
105 };
106 assert!(d.completed);
107 }
108
109 #[test]
110 fn agent_error_display() {
111 let err = AgentError::LoopDetected(5);
112 assert_eq!(err.to_string(), "loop detected after 5 iterations");
113 let err = AgentError::MaxSteps(50);
114 assert_eq!(err.to_string(), "max steps reached: 50");
115 }
116}