1use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct AgentAction {
12 pub tool: String,
14
15 pub tool_input: ToolInput,
17
18 pub log: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type", rename_all = "snake_case")]
32pub enum ToolInput {
33 String {
35 value: String,
37 },
38
39 Object {
41 value: serde_json::Value,
43 },
44}
45
46impl Default for ToolInput {
47 fn default() -> Self {
48 ToolInput::String {
49 value: String::new(),
50 }
51 }
52}
53
54impl std::fmt::Display for ToolInput {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 match self {
57 ToolInput::String { value } => write!(f, "{}", value),
58 ToolInput::Object { value } => write!(
59 f,
60 "{}",
61 serde_json::to_string(value).unwrap_or_else(|_| "unknown".to_string())
62 ),
63 }
64 }
65}
66
67impl TryFrom<serde_json::Value> for ToolInput {
73 type Error = String;
74
75 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
76 match value {
77 serde_json::Value::String(s) => Ok(ToolInput::String { value: s }),
78 serde_json::Value::Object(_) => Ok(ToolInput::Object { value }),
79 other => Err(format!(
80 "ToolInput must be a string or object, got: {}",
81 other
82 )),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct AgentFinish {
92 pub return_values: HashMap<String, serde_json::Value>,
94
95 pub log: String,
97}
98
99impl AgentFinish {
100 pub fn new(output: impl Into<String>, log: impl Into<String>) -> Self {
102 let mut return_values = HashMap::new();
103 return_values.insert(
104 "output".to_string(),
105 serde_json::Value::String(output.into()),
106 );
107 Self {
108 return_values,
109 log: log.into(),
110 }
111 }
112
113 pub fn output(&self) -> Option<&str> {
115 self.return_values.get("output").and_then(|v| v.as_str())
116 }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct AgentStep {
124 pub action: AgentAction,
126
127 pub observation: String,
129}
130
131impl AgentStep {
132 pub fn new(action: AgentAction, observation: impl Into<String>) -> Self {
134 Self {
135 action,
136 observation: observation.into(),
137 }
138 }
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
145pub enum AgentOutput {
146 Action(AgentAction),
148
149 Actions(Vec<AgentAction>),
151
152 Finish(AgentFinish),
154}
155
156impl AgentOutput {
157 pub fn is_finish(&self) -> bool {
159 matches!(self, AgentOutput::Finish(_))
160 }
161
162 pub fn is_action(&self) -> bool {
164 matches!(self, AgentOutput::Action(_) | AgentOutput::Actions(_))
165 }
166
167 pub fn action(&self) -> Option<&AgentAction> {
169 match self {
170 AgentOutput::Action(action) => Some(action),
171 _ => None,
172 }
173 }
174
175 pub fn actions(&self) -> Vec<&AgentAction> {
177 match self {
178 AgentOutput::Action(action) => vec![action],
179 AgentOutput::Actions(actions) => actions.iter().collect(),
180 _ => vec![],
181 }
182 }
183
184 pub fn finish(&self) -> Option<&AgentFinish> {
186 match self {
187 AgentOutput::Finish(finish) => Some(finish),
188 _ => None,
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 fn create_action(tool: &str, input: &str) -> AgentAction {
198 AgentAction {
199 tool: tool.to_string(),
200 tool_input: ToolInput::String {
201 value: input.to_string(),
202 },
203 log: "test".to_string(),
204 }
205 }
206
207 #[test]
208 fn test_agent_output_single_action() {
209 let action = create_action("calculator", "1+2");
210 let output = AgentOutput::Action(action);
211
212 assert!(output.is_action());
213 assert!(!output.is_finish());
214 assert_eq!(output.actions().len(), 1);
215 }
216
217 #[test]
218 fn test_agent_output_multiple_actions() {
219 let actions = vec![
220 create_action("calculator", "1+2"),
221 create_action("datetime", "now"),
222 ];
223 let output = AgentOutput::Actions(actions);
224
225 assert!(output.is_action());
226 assert!(!output.is_finish());
227 assert_eq!(output.actions().len(), 2);
228 assert!(output.action().is_none());
229 }
230
231 #[test]
232 fn test_agent_output_finish() {
233 let finish = AgentFinish::new("answer".to_string(), "log".to_string());
234 let output = AgentOutput::Finish(finish);
235
236 assert!(!output.is_action());
237 assert!(output.is_finish());
238 assert_eq!(output.actions().len(), 0);
239 assert!(output.finish().is_some());
240 }
241
242 #[test]
243 fn test_agent_finish_output() {
244 let finish = AgentFinish::new("the answer is 42".to_string(), String::new());
245 assert_eq!(finish.output(), Some("the answer is 42"));
246 }
247}