1use serde::{Deserialize, Serialize};
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 { tool_id: String, result: String },
60
61 #[serde(rename = "tool_result_delta")]
63 ToolResultDelta { tool_id: String, delta: String },
64
65 #[serde(rename = "usage")]
67 Usage {
68 input_tokens: u64,
69 output_tokens: u64,
70 #[serde(default, skip_serializing_if = "Option::is_none")]
72 cache_creation_5m: Option<u64>,
73 #[serde(default, skip_serializing_if = "Option::is_none")]
74 cache_creation_1h: Option<u64>,
75 },
76
77 #[serde(rename = "done")]
79 Done,
80
81 #[serde(rename = "notice")]
84 Notice { text: String },
85 #[serde(rename = "response_start")]
86 ResponseStart,
87 #[serde(rename = "response_reset")]
88 ResponseReset,
89
90 #[serde(rename = "error")]
92 Error { message: String },
93
94 #[serde(rename = "system")]
96 System { message: String },
97
98 #[serde(rename = "history")]
100 HistoryResponse { messages: Vec<HistoryEntry> },
101
102 #[serde(rename = "status")]
104 StatusResponse {
105 model: String,
106 thinking: String,
107 streaming: bool,
108 session_id: String,
109 total_input_tokens: u64,
110 total_output_tokens: u64,
111 session_cost: f64,
112 connected_clients: usize,
113 },
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
118#[serde(tag = "role")]
119pub enum HistoryEntry {
120 #[serde(rename = "user")]
121 User { content: String, time: String },
122 #[serde(rename = "thinking")]
123 Thinking { content: String, time: String },
124 #[serde(rename = "text")]
125 Text { content: String, time: String },
126 #[serde(rename = "tool_use")]
127 ToolUse {
128 tool_name: String,
129 input: String,
130 time: String,
131 },
132 #[serde(rename = "tool_result")]
133 ToolResult { result: String, time: String },
134 #[serde(rename = "system")]
135 System { content: String, time: String },
136 #[serde(rename = "error")]
137 Error { content: String, time: String },
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use serde_json::json;
144
145 #[test]
146 fn test_client_message_message_roundtrip() {
147 let msg = ClientMessage::Message {
148 content: "Hello, world!".to_string(),
149 };
150
151 let json_value = serde_json::to_value(&msg).unwrap();
153
154 assert_eq!(json_value["type"], "message");
156 assert_eq!(json_value["content"], "Hello, world!");
157
158 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
160 match deserialized {
161 ClientMessage::Message { content } => {
162 assert_eq!(content, "Hello, world!");
163 }
164 _ => panic!("Expected Message variant"),
165 }
166 }
167
168 #[test]
169 fn test_client_message_cancel_roundtrip() {
170 let msg = ClientMessage::Cancel;
171
172 let json_value = serde_json::to_value(&msg).unwrap();
174
175 assert_eq!(json_value["type"], "cancel");
177
178 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
180 matches!(deserialized, ClientMessage::Cancel);
181 }
182
183 #[test]
184 fn test_client_message_command_roundtrip() {
185 let msg = ClientMessage::Command {
186 name: "clear".to_string(),
187 args: "".to_string(),
188 };
189
190 let json_value = serde_json::to_value(&msg).unwrap();
192
193 assert_eq!(json_value["type"], "command");
195 assert_eq!(json_value["name"], "clear");
196 assert_eq!(json_value["args"], "");
197
198 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
200 match deserialized {
201 ClientMessage::Command { name, args } => {
202 assert_eq!(name, "clear");
203 assert_eq!(args, "");
204 }
205 _ => panic!("Expected Command variant"),
206 }
207 }
208
209 #[test]
210 fn test_server_message_text_roundtrip() {
211 let msg = ServerMessage::Text {
212 content: "Hello from server!".to_string(),
213 };
214
215 let json_value = serde_json::to_value(&msg).unwrap();
217
218 assert_eq!(json_value["type"], "text");
220 assert_eq!(json_value["content"], "Hello from server!");
221
222 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
224 match deserialized {
225 ServerMessage::Text { content } => {
226 assert_eq!(content, "Hello from server!");
227 }
228 _ => panic!("Expected Text variant"),
229 }
230 }
231
232 #[test]
233 fn test_server_message_done_roundtrip() {
234 let msg = ServerMessage::Done;
235
236 let json_value = serde_json::to_value(&msg).unwrap();
238
239 assert_eq!(json_value["type"], "done");
241
242 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
244 matches!(deserialized, ServerMessage::Done);
245 }
246
247 #[test]
248 fn test_server_message_error_roundtrip() {
249 let msg = ServerMessage::Error {
250 message: "Something went wrong".to_string(),
251 };
252
253 let json_value = serde_json::to_value(&msg).unwrap();
255
256 assert_eq!(json_value["type"], "error");
258 assert_eq!(json_value["message"], "Something went wrong");
259
260 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
262 match deserialized {
263 ServerMessage::Error { message } => {
264 assert_eq!(message, "Something went wrong");
265 }
266 _ => panic!("Expected Error variant"),
267 }
268 }
269
270 #[test]
271 fn test_server_message_tool_use_roundtrip() {
272 let msg = ServerMessage::ToolUse {
273 tool_name: "execute_bash".to_string(),
274 tool_id: "tool_123".to_string(),
275 input: json!({"command": "ls -la", "timeout": 30}),
276 };
277
278 let json_value = serde_json::to_value(&msg).unwrap();
280
281 assert_eq!(json_value["type"], "tool_use");
283 assert_eq!(json_value["tool_name"], "execute_bash");
284 assert_eq!(json_value["tool_id"], "tool_123");
285 assert_eq!(json_value["input"]["command"], "ls -la");
286 assert_eq!(json_value["input"]["timeout"], 30);
287
288 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
290 match deserialized {
291 ServerMessage::ToolUse {
292 tool_name,
293 tool_id,
294 input,
295 } => {
296 assert_eq!(tool_name, "execute_bash");
297 assert_eq!(tool_id, "tool_123");
298 assert_eq!(input["command"], "ls -la");
299 assert_eq!(input["timeout"], 30);
300 }
301 _ => panic!("Expected ToolUse variant"),
302 }
303 }
304
305 #[test]
306 fn test_server_message_usage_roundtrip() {
307 let msg = ServerMessage::Usage {
308 input_tokens: 150,
309 output_tokens: 75,
310 cache_creation_5m: None,
311 cache_creation_1h: None,
312 };
313
314 let json_value = serde_json::to_value(&msg).unwrap();
316
317 assert_eq!(json_value["type"], "usage");
319 assert_eq!(json_value["input_tokens"], 150);
320 assert_eq!(json_value["output_tokens"], 75);
321 assert!(json_value.get("cache_creation_5m").is_none());
324 assert!(json_value.get("cache_creation_1h").is_none());
325
326 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
328 match deserialized {
329 ServerMessage::Usage {
330 input_tokens,
331 output_tokens,
332 cache_creation_5m,
333 cache_creation_1h,
334 } => {
335 assert_eq!(input_tokens, 150);
336 assert_eq!(output_tokens, 75);
337 assert_eq!(cache_creation_5m, None);
338 assert_eq!(cache_creation_1h, None);
339 }
340 _ => panic!("Expected Usage variant"),
341 }
342 }
343
344 #[test]
345 fn test_history_entry_user_roundtrip() {
346 let entry = HistoryEntry::User {
347 content: "User message".to_string(),
348 time: "2023-10-01T12:00:00Z".to_string(),
349 };
350
351 let json_value = serde_json::to_value(&entry).unwrap();
353
354 assert_eq!(json_value["role"], "user");
356 assert_eq!(json_value["content"], "User message");
357 assert_eq!(json_value["time"], "2023-10-01T12:00:00Z");
358
359 let deserialized: HistoryEntry = serde_json::from_value(json_value).unwrap();
361 match deserialized {
362 HistoryEntry::User { content, time } => {
363 assert_eq!(content, "User message");
364 assert_eq!(time, "2023-10-01T12:00:00Z");
365 }
366 _ => panic!("Expected User variant"),
367 }
368 }
369}