microagents_events/
types.rs1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{Map, Value};
5use thiserror::Error;
6
7const JSONRPC: &str = "2.0";
8
9#[derive(Debug, Clone, Error)]
11#[non_exhaustive]
12pub enum AgentEventError {
13 #[error("Missing required field: {0}")]
15 MissingField(String),
16 #[error("Invalid type for field: {0}")]
18 InvalidFieldType(String),
19 #[error("Unknown method: {0}")]
21 UnknownMethod(String),
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ToolCall {
26 pub id: String,
27 pub call_type: String,
28 pub function: FunctionCall,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct FunctionCall {
33 pub name: String,
34 pub arguments: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39#[non_exhaustive]
40pub enum ToolResult {
41 Ok(String),
43 Err(String),
45}
46
47#[derive(Debug, Serialize, Deserialize, Clone)]
49pub struct JsonRpcNotification {
50 pub jsonrpc: String,
51 pub method: String,
52 pub params: Map<String, Value>,
53}
54
55impl JsonRpcNotification {
56 pub fn builder() -> Self {
57 Self {
58 jsonrpc: JSONRPC.into(),
59 method: String::new(),
60 params: Map::new(),
61 }
62 }
63
64 pub fn method(mut self, method: String) -> Self {
65 self.method = method;
66 self
67 }
68
69 pub fn add_param(mut self, key: String, value: Value) -> Self {
70 self.params.insert(key, value);
71 self
72 }
73}
74
75pub trait AgentEvent: Debug + Send + Sync {
77 fn to_jsonrpc(&self) -> JsonRpcNotification;
79 fn session_id(&self) -> String;
81}
82
83#[cfg(test)]
84mod tests {
85
86 use serde_json::{Error, json};
87
88 use super::*;
89
90 #[test]
91 fn test_value_from_toolcall() {
92 let tc = ToolCall {
93 call_type: "function".into(),
94 id: "1".into(),
95 function: FunctionCall {
96 name: "tool".into(),
97 arguments: "{}".into(),
98 },
99 };
100 let val = serde_json::to_value(&tc).expect("Should be able to convert to Value");
101 if let Some(v) = val.as_object() {
102 assert_eq!(v.get("call_type"), Some(Value::from("function")).as_ref());
103 assert_eq!(v.get("id"), Some(Value::from("1")).as_ref());
104 assert!(v.get("function").is_some_and(|o| o.is_object()));
105 }
106 }
107
108 #[test]
109 fn test_toolcall_from_value_ok() {
110 let value = json!({
111 "call_type": "function",
112 "id": "1",
113 "function": {
114 "name": "tool",
115 "arguments": "{}"
116 }
117 });
118 let tc: ToolCall = serde_json::from_value(value)
119 .expect("Value should be correctly converted to tool call");
120 assert_eq!(tc.call_type, "function".to_string());
121 assert_eq!(tc.id, "1".to_string());
122 assert_eq!(tc.function.name, "tool".to_string());
123 assert_eq!(tc.function.arguments, "{}".to_string());
124 }
125
126 #[test]
127 fn test_toolcall_from_value_err() {
128 let value = json!({
129 "call_typ": "function",
130 "id": "1",
131 "func": {
132 "name": "tool",
133 "arguments": "{}"
134 }
135 });
136 let result: Result<ToolCall, Error> = serde_json::from_value(value);
137 assert!(result.is_err());
138 }
139
140 #[test]
141 fn test_value_from_tool_result() {
142 let trs = ToolResult::Ok("success!".to_string());
143 let trf = ToolResult::Err("error!".to_string());
144 let value_s = serde_json::to_value(trs).expect("Should be able to convert to value");
145 let value_f = serde_json::to_value(trf).expect("Should be able to convert to value");
146 assert_eq!(
147 value_s,
148 json!({
149 "Ok": "success!",
150 })
151 );
152 assert_eq!(
153 value_f,
154 json!({
155 "Err": "error!",
156 })
157 );
158 }
159
160 #[test]
161 fn test_jsonrpc_notification_builder() {
162 let jsonrpc = JsonRpcNotification::builder();
163 assert_eq!(jsonrpc.jsonrpc, JSONRPC.to_string());
164 assert_eq!(jsonrpc.method, String::new());
165 assert_eq!(jsonrpc.params, Map::<String, Value>::new());
166
167 let j = jsonrpc
168 .method("test".into())
169 .add_param("test".into(), Value::from("string"))
170 .add_param("number".into(), Value::from(1));
171
172 assert_eq!(j.method, "test".to_string());
173 assert_eq!(j.params.len(), 2);
174 assert!(j.params.get("test").is_some_and(|v| v.is_string()));
175 assert!(j.params.get("number").is_some_and(|v| v.is_number()));
176 }
177}