autoagents_core/
protocol.rs

1use crate::runtime::Task;
2use autoagents_llm::chat::ChatMessage;
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// Submission IDs are used to track agent tasks
7pub type SubmissionId = Uuid;
8
9/// Agent IDs are used to identify agents
10pub type AgentID = Uuid;
11
12/// Session IDs are used to identify sessions
13pub type RuntimeID = Uuid;
14
15/// Event IDs are used to correlate events with their responses
16pub type EventId = Uuid;
17
18/// Protocol events represent the various events that can occur during agent execution
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub enum Event {
21    /// A new task has been submitted to an agent
22    NewTask {
23        agent_id: AgentID,
24        task: Task,
25    },
26
27    /// A task has started execution
28    TaskStarted {
29        sub_id: SubmissionId,
30        agent_id: AgentID,
31        task_description: String,
32    },
33
34    /// A task has been completed
35    TaskComplete {
36        sub_id: SubmissionId,
37        result: TaskResult,
38    },
39
40    /// A task encountered an error
41    TaskError {
42        sub_id: SubmissionId,
43        result: TaskResult,
44    },
45
46    /// Tool call requested (with ID)
47    ToolCallRequested {
48        id: String,
49        tool_name: String,
50        arguments: String,
51    },
52
53    /// Tool call completed (with ID and result)
54    ToolCallCompleted {
55        id: String,
56        tool_name: String,
57        result: serde_json::Value,
58    },
59
60    /// Tool call has failed
61    ToolCallFailed {
62        id: String,
63        tool_name: String,
64        error: String,
65    },
66
67    /// A turn has started
68    TurnStarted {
69        turn_number: usize,
70        max_turns: usize,
71    },
72
73    /// A turn has completed
74    TurnCompleted {
75        turn_number: usize,
76        final_turn: bool,
77    },
78    PublishMessage {
79        topic: String,
80        message: String,
81    },
82    SendMessage {
83        message: String,
84        agent_id: AgentID,
85    },
86}
87
88/// Results from a completed task
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub enum TaskResult {
91    /// The task was completed with a value
92    Value(serde_json::Value),
93
94    /// The task failed
95    Failure(String),
96
97    /// The task was aborted
98    Aborted,
99}
100
101/// Messages from the agent - used for A2A communication
102#[derive(Debug, Clone, Serialize, Deserialize)]
103struct AgentMessage {
104    /// The content of the message
105    pub content: String,
106
107    /// Optional chat messages for a full conversation history
108    pub chat_messages: Option<Vec<ChatMessage>>,
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use serde_json::json;
115
116    #[test]
117    fn test_event_serialization_new_task() {
118        let agent_id = Uuid::new_v4();
119        let event = Event::NewTask {
120            agent_id,
121            task: Task::new(String::from("test"), Some(agent_id)),
122        };
123
124        //Check if serialization and deserilization works properly
125        let serialized = serde_json::to_string(&event).unwrap();
126        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
127
128        match deserialized {
129            Event::NewTask { task, .. } => {
130                assert_eq!(task.prompt, "test");
131            }
132            _ => panic!("Expected NewTask variant"),
133        }
134    }
135
136    #[test]
137    fn test_event_serialization_task_started() {
138        let event = Event::TaskStarted {
139            sub_id: Uuid::new_v4(),
140            agent_id: Uuid::new_v4(),
141            task_description: "Started task".to_string(),
142        };
143
144        let serialized = serde_json::to_string(&event).unwrap();
145        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
146
147        match deserialized {
148            Event::TaskStarted {
149                task_description, ..
150            } => {
151                assert_eq!(task_description, "Started task");
152            }
153            _ => panic!("Expected TaskStarted variant"),
154        }
155    }
156
157    #[test]
158    fn test_event_serialization_tool_calls() {
159        let tool_call_requested = Event::ToolCallRequested {
160            id: "call_123".to_string(),
161            tool_name: "test_tool".to_string(),
162            arguments: "{\"param\": \"value\"}".to_string(),
163        };
164
165        let serialized = serde_json::to_string(&tool_call_requested).unwrap();
166        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
167
168        match deserialized {
169            Event::ToolCallRequested {
170                id,
171                tool_name,
172                arguments,
173            } => {
174                assert_eq!(id, "call_123");
175                assert_eq!(tool_name, "test_tool");
176                assert_eq!(arguments, "{\"param\": \"value\"}");
177            }
178            _ => panic!("Expected ToolCallRequested variant"),
179        }
180    }
181
182    #[test]
183    fn test_event_serialization_tool_call_completed() {
184        let result = json!({"output": "tool result"});
185        let event = Event::ToolCallCompleted {
186            id: "call_456".to_string(),
187            tool_name: "completed_tool".to_string(),
188            result: result.clone(),
189        };
190
191        let serialized = serde_json::to_string(&event).unwrap();
192        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
193
194        match deserialized {
195            Event::ToolCallCompleted {
196                id,
197                tool_name,
198                result: res,
199            } => {
200                assert_eq!(id, "call_456");
201                assert_eq!(tool_name, "completed_tool");
202                assert_eq!(res, result);
203            }
204            _ => panic!("Expected ToolCallCompleted variant"),
205        }
206    }
207
208    #[test]
209    fn test_event_serialization_tool_call_failed() {
210        let event = Event::ToolCallFailed {
211            id: "call_789".to_string(),
212            tool_name: "failed_tool".to_string(),
213            error: "Tool execution failed".to_string(),
214        };
215
216        let serialized = serde_json::to_string(&event).unwrap();
217        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
218
219        match deserialized {
220            Event::ToolCallFailed {
221                id,
222                tool_name,
223                error,
224            } => {
225                assert_eq!(id, "call_789");
226                assert_eq!(tool_name, "failed_tool");
227                assert_eq!(error, "Tool execution failed");
228            }
229            _ => panic!("Expected ToolCallFailed variant"),
230        }
231    }
232
233    #[test]
234    fn test_event_serialization_turn_events() {
235        let turn_started = Event::TurnStarted {
236            turn_number: 1,
237            max_turns: 10,
238        };
239
240        let serialized = serde_json::to_string(&turn_started).unwrap();
241        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
242
243        match deserialized {
244            Event::TurnStarted {
245                turn_number,
246                max_turns,
247            } => {
248                assert_eq!(turn_number, 1);
249                assert_eq!(max_turns, 10);
250            }
251            _ => panic!("Expected TurnStarted variant"),
252        }
253
254        let turn_completed = Event::TurnCompleted {
255            turn_number: 1,
256            final_turn: false,
257        };
258
259        let serialized = serde_json::to_string(&turn_completed).unwrap();
260        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
261
262        match deserialized {
263            Event::TurnCompleted {
264                turn_number,
265                final_turn,
266            } => {
267                assert_eq!(turn_number, 1);
268                assert!(!final_turn);
269            }
270            _ => panic!("Expected TurnCompleted variant"),
271        }
272    }
273
274    #[test]
275    fn test_agent_message_serialization() {
276        let message = AgentMessage {
277            content: "Test message".to_string(),
278            chat_messages: None,
279        };
280
281        let serialized = serde_json::to_string(&message).unwrap();
282        let deserialized: AgentMessage = serde_json::from_str(&serialized).unwrap();
283
284        assert_eq!(deserialized.content, "Test message");
285        assert!(deserialized.chat_messages.is_none());
286    }
287
288    #[test]
289    fn test_agent_message_with_chat_messages() {
290        use autoagents_llm::chat::{ChatMessage, ChatRole, MessageType};
291
292        let chat_msg = ChatMessage {
293            role: ChatRole::User,
294            message_type: MessageType::Text,
295            content: "Hello".to_string(),
296        };
297
298        let message = AgentMessage {
299            content: "Agent response".to_string(),
300            chat_messages: Some(vec![chat_msg]),
301        };
302
303        let serialized = serde_json::to_string(&message).unwrap();
304        let deserialized: AgentMessage = serde_json::from_str(&serialized).unwrap();
305
306        assert_eq!(deserialized.content, "Agent response");
307        assert!(deserialized.chat_messages.is_some());
308        assert_eq!(deserialized.chat_messages.unwrap().len(), 1);
309    }
310
311    #[test]
312    fn test_agent_message_debug_format() {
313        let message = AgentMessage {
314            content: "Debug message".to_string(),
315            chat_messages: None,
316        };
317
318        let debug_str = format!("{message:?}");
319        assert!(debug_str.contains("AgentMessage"));
320        assert!(debug_str.contains("Debug message"));
321    }
322
323    #[test]
324    fn test_agent_message_clone() {
325        let message = AgentMessage {
326            content: "Test content".to_string(),
327            chat_messages: None,
328        };
329
330        let cloned = message.clone();
331        assert_eq!(message.content, cloned.content);
332        assert_eq!(
333            message.chat_messages.is_none(),
334            cloned.chat_messages.is_none()
335        );
336    }
337
338    #[test]
339    fn test_uuid_types() {
340        let submission_id: SubmissionId = Uuid::new_v4();
341        let agent_id: AgentID = Uuid::new_v4();
342        let runtime_id: RuntimeID = Uuid::new_v4();
343        let event_id: EventId = Uuid::new_v4();
344
345        // Test that all UUID types can be used interchangeably
346        assert_ne!(submission_id, agent_id);
347        assert_ne!(runtime_id, event_id);
348    }
349}