1use serde::{Serialize, Deserialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(tag = "type")]
7pub enum ClientMessage {
8 #[serde(rename = "message")]
10 Message { content: String },
11
12 #[serde(rename = "command")]
14 Command { name: String, args: String },
15
16 #[serde(rename = "cancel")]
18 Cancel,
19
20 #[serde(rename = "status")]
22 Status,
23
24 #[serde(rename = "history")]
26 History,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type")]
32pub enum ServerMessage {
33 #[serde(rename = "thinking")]
35 Thinking { content: String },
36
37 #[serde(rename = "text")]
39 Text { content: String },
40
41 #[serde(rename = "tool_use_start")]
43 ToolUseStart { tool_name: String },
44
45 #[serde(rename = "tool_use_delta")]
47 ToolUseDelta(String),
48
49 #[serde(rename = "tool_use")]
51 ToolUse {
52 tool_name: String,
53 tool_id: String,
54 input: Value,
55 },
56
57 #[serde(rename = "tool_result")]
59 ToolResult {
60 tool_id: String,
61 result: String,
62 },
63
64 #[serde(rename = "tool_result_delta")]
66 ToolResultDelta {
67 tool_id: String,
68 delta: String,
69 },
70
71 #[serde(rename = "usage")]
73 Usage {
74 input_tokens: u64,
75 output_tokens: u64,
76 },
77
78 #[serde(rename = "done")]
80 Done,
81
82 #[serde(rename = "error")]
84 Error { message: String },
85
86 #[serde(rename = "system")]
88 System { message: String },
89
90 #[serde(rename = "history")]
92 HistoryResponse { messages: Vec<HistoryEntry> },
93
94 #[serde(rename = "status")]
96 StatusResponse {
97 model: String,
98 thinking: String,
99 streaming: bool,
100 session_id: String,
101 total_input_tokens: u64,
102 total_output_tokens: u64,
103 session_cost: f64,
104 connected_clients: usize,
105 },
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(tag = "role")]
111pub enum HistoryEntry {
112 #[serde(rename = "user")]
113 User { content: String, time: String },
114 #[serde(rename = "thinking")]
115 Thinking { content: String, time: String },
116 #[serde(rename = "text")]
117 Text { content: String, time: String },
118 #[serde(rename = "tool_use")]
119 ToolUse { tool_name: String, input: String, time: String },
120 #[serde(rename = "tool_result")]
121 ToolResult { result: String, time: String },
122 #[serde(rename = "system")]
123 System { content: String, time: String },
124 #[serde(rename = "error")]
125 Error { content: String, time: String },
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use serde_json::json;
132
133 #[test]
134 fn test_client_message_message_roundtrip() {
135 let msg = ClientMessage::Message {
136 content: "Hello, world!".to_string(),
137 };
138
139 let json_value = serde_json::to_value(&msg).unwrap();
141
142 assert_eq!(json_value["type"], "message");
144 assert_eq!(json_value["content"], "Hello, world!");
145
146 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
148 match deserialized {
149 ClientMessage::Message { content } => {
150 assert_eq!(content, "Hello, world!");
151 }
152 _ => panic!("Expected Message variant"),
153 }
154 }
155
156 #[test]
157 fn test_client_message_cancel_roundtrip() {
158 let msg = ClientMessage::Cancel;
159
160 let json_value = serde_json::to_value(&msg).unwrap();
162
163 assert_eq!(json_value["type"], "cancel");
165
166 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
168 matches!(deserialized, ClientMessage::Cancel);
169 }
170
171 #[test]
172 fn test_client_message_command_roundtrip() {
173 let msg = ClientMessage::Command {
174 name: "clear".to_string(),
175 args: "".to_string(),
176 };
177
178 let json_value = serde_json::to_value(&msg).unwrap();
180
181 assert_eq!(json_value["type"], "command");
183 assert_eq!(json_value["name"], "clear");
184 assert_eq!(json_value["args"], "");
185
186 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
188 match deserialized {
189 ClientMessage::Command { name, args } => {
190 assert_eq!(name, "clear");
191 assert_eq!(args, "");
192 }
193 _ => panic!("Expected Command variant"),
194 }
195 }
196
197 #[test]
198 fn test_server_message_text_roundtrip() {
199 let msg = ServerMessage::Text {
200 content: "Hello from server!".to_string(),
201 };
202
203 let json_value = serde_json::to_value(&msg).unwrap();
205
206 assert_eq!(json_value["type"], "text");
208 assert_eq!(json_value["content"], "Hello from server!");
209
210 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
212 match deserialized {
213 ServerMessage::Text { content } => {
214 assert_eq!(content, "Hello from server!");
215 }
216 _ => panic!("Expected Text variant"),
217 }
218 }
219
220 #[test]
221 fn test_server_message_done_roundtrip() {
222 let msg = ServerMessage::Done;
223
224 let json_value = serde_json::to_value(&msg).unwrap();
226
227 assert_eq!(json_value["type"], "done");
229
230 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
232 matches!(deserialized, ServerMessage::Done);
233 }
234
235 #[test]
236 fn test_server_message_error_roundtrip() {
237 let msg = ServerMessage::Error {
238 message: "Something went wrong".to_string(),
239 };
240
241 let json_value = serde_json::to_value(&msg).unwrap();
243
244 assert_eq!(json_value["type"], "error");
246 assert_eq!(json_value["message"], "Something went wrong");
247
248 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
250 match deserialized {
251 ServerMessage::Error { message } => {
252 assert_eq!(message, "Something went wrong");
253 }
254 _ => panic!("Expected Error variant"),
255 }
256 }
257
258 #[test]
259 fn test_server_message_tool_use_roundtrip() {
260 let msg = ServerMessage::ToolUse {
261 tool_name: "execute_bash".to_string(),
262 tool_id: "tool_123".to_string(),
263 input: json!({"command": "ls -la", "timeout": 30}),
264 };
265
266 let json_value = serde_json::to_value(&msg).unwrap();
268
269 assert_eq!(json_value["type"], "tool_use");
271 assert_eq!(json_value["tool_name"], "execute_bash");
272 assert_eq!(json_value["tool_id"], "tool_123");
273 assert_eq!(json_value["input"]["command"], "ls -la");
274 assert_eq!(json_value["input"]["timeout"], 30);
275
276 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
278 match deserialized {
279 ServerMessage::ToolUse { tool_name, tool_id, input } => {
280 assert_eq!(tool_name, "execute_bash");
281 assert_eq!(tool_id, "tool_123");
282 assert_eq!(input["command"], "ls -la");
283 assert_eq!(input["timeout"], 30);
284 }
285 _ => panic!("Expected ToolUse variant"),
286 }
287 }
288
289 #[test]
290 fn test_server_message_usage_roundtrip() {
291 let msg = ServerMessage::Usage {
292 input_tokens: 150,
293 output_tokens: 75,
294 };
295
296 let json_value = serde_json::to_value(&msg).unwrap();
298
299 assert_eq!(json_value["type"], "usage");
301 assert_eq!(json_value["input_tokens"], 150);
302 assert_eq!(json_value["output_tokens"], 75);
303
304 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
306 match deserialized {
307 ServerMessage::Usage { input_tokens, output_tokens } => {
308 assert_eq!(input_tokens, 150);
309 assert_eq!(output_tokens, 75);
310 }
311 _ => panic!("Expected Usage variant"),
312 }
313 }
314
315 #[test]
316 fn test_history_entry_user_roundtrip() {
317 let entry = HistoryEntry::User {
318 content: "User message".to_string(),
319 time: "2023-10-01T12:00:00Z".to_string(),
320 };
321
322 let json_value = serde_json::to_value(&entry).unwrap();
324
325 assert_eq!(json_value["role"], "user");
327 assert_eq!(json_value["content"], "User message");
328 assert_eq!(json_value["time"], "2023-10-01T12:00:00Z");
329
330 let deserialized: HistoryEntry = serde_json::from_value(json_value).unwrap();
332 match deserialized {
333 HistoryEntry::User { content, time } => {
334 assert_eq!(content, "User message");
335 assert_eq!(time, "2023-10-01T12:00:00Z");
336 }
337 _ => panic!("Expected User variant"),
338 }
339 }
340}