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 #[serde(default, skip_serializing_if = "Option::is_none")]
78 cache_creation_5m: Option<u64>,
79 #[serde(default, skip_serializing_if = "Option::is_none")]
80 cache_creation_1h: Option<u64>,
81 },
82
83 #[serde(rename = "done")]
85 Done,
86
87 #[serde(rename = "notice")]
90 Notice { text: String },
91
92 #[serde(rename = "error")]
94 Error { message: String },
95
96 #[serde(rename = "system")]
98 System { message: String },
99
100 #[serde(rename = "history")]
102 HistoryResponse { messages: Vec<HistoryEntry> },
103
104 #[serde(rename = "status")]
106 StatusResponse {
107 model: String,
108 thinking: String,
109 streaming: bool,
110 session_id: String,
111 total_input_tokens: u64,
112 total_output_tokens: u64,
113 session_cost: f64,
114 connected_clients: usize,
115 },
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(tag = "role")]
121pub enum HistoryEntry {
122 #[serde(rename = "user")]
123 User { content: String, time: String },
124 #[serde(rename = "thinking")]
125 Thinking { content: String, time: String },
126 #[serde(rename = "text")]
127 Text { content: String, time: String },
128 #[serde(rename = "tool_use")]
129 ToolUse { tool_name: String, input: String, time: String },
130 #[serde(rename = "tool_result")]
131 ToolResult { result: String, time: String },
132 #[serde(rename = "system")]
133 System { content: String, time: String },
134 #[serde(rename = "error")]
135 Error { content: String, time: String },
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use serde_json::json;
142
143 #[test]
144 fn test_client_message_message_roundtrip() {
145 let msg = ClientMessage::Message {
146 content: "Hello, world!".to_string(),
147 };
148
149 let json_value = serde_json::to_value(&msg).unwrap();
151
152 assert_eq!(json_value["type"], "message");
154 assert_eq!(json_value["content"], "Hello, world!");
155
156 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
158 match deserialized {
159 ClientMessage::Message { content } => {
160 assert_eq!(content, "Hello, world!");
161 }
162 _ => panic!("Expected Message variant"),
163 }
164 }
165
166 #[test]
167 fn test_client_message_cancel_roundtrip() {
168 let msg = ClientMessage::Cancel;
169
170 let json_value = serde_json::to_value(&msg).unwrap();
172
173 assert_eq!(json_value["type"], "cancel");
175
176 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
178 matches!(deserialized, ClientMessage::Cancel);
179 }
180
181 #[test]
182 fn test_client_message_command_roundtrip() {
183 let msg = ClientMessage::Command {
184 name: "clear".to_string(),
185 args: "".to_string(),
186 };
187
188 let json_value = serde_json::to_value(&msg).unwrap();
190
191 assert_eq!(json_value["type"], "command");
193 assert_eq!(json_value["name"], "clear");
194 assert_eq!(json_value["args"], "");
195
196 let deserialized: ClientMessage = serde_json::from_value(json_value).unwrap();
198 match deserialized {
199 ClientMessage::Command { name, args } => {
200 assert_eq!(name, "clear");
201 assert_eq!(args, "");
202 }
203 _ => panic!("Expected Command variant"),
204 }
205 }
206
207 #[test]
208 fn test_server_message_text_roundtrip() {
209 let msg = ServerMessage::Text {
210 content: "Hello from server!".to_string(),
211 };
212
213 let json_value = serde_json::to_value(&msg).unwrap();
215
216 assert_eq!(json_value["type"], "text");
218 assert_eq!(json_value["content"], "Hello from server!");
219
220 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
222 match deserialized {
223 ServerMessage::Text { content } => {
224 assert_eq!(content, "Hello from server!");
225 }
226 _ => panic!("Expected Text variant"),
227 }
228 }
229
230 #[test]
231 fn test_server_message_done_roundtrip() {
232 let msg = ServerMessage::Done;
233
234 let json_value = serde_json::to_value(&msg).unwrap();
236
237 assert_eq!(json_value["type"], "done");
239
240 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
242 matches!(deserialized, ServerMessage::Done);
243 }
244
245 #[test]
246 fn test_server_message_error_roundtrip() {
247 let msg = ServerMessage::Error {
248 message: "Something went wrong".to_string(),
249 };
250
251 let json_value = serde_json::to_value(&msg).unwrap();
253
254 assert_eq!(json_value["type"], "error");
256 assert_eq!(json_value["message"], "Something went wrong");
257
258 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
260 match deserialized {
261 ServerMessage::Error { message } => {
262 assert_eq!(message, "Something went wrong");
263 }
264 _ => panic!("Expected Error variant"),
265 }
266 }
267
268 #[test]
269 fn test_server_message_tool_use_roundtrip() {
270 let msg = ServerMessage::ToolUse {
271 tool_name: "execute_bash".to_string(),
272 tool_id: "tool_123".to_string(),
273 input: json!({"command": "ls -la", "timeout": 30}),
274 };
275
276 let json_value = serde_json::to_value(&msg).unwrap();
278
279 assert_eq!(json_value["type"], "tool_use");
281 assert_eq!(json_value["tool_name"], "execute_bash");
282 assert_eq!(json_value["tool_id"], "tool_123");
283 assert_eq!(json_value["input"]["command"], "ls -la");
284 assert_eq!(json_value["input"]["timeout"], 30);
285
286 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
288 match deserialized {
289 ServerMessage::ToolUse { tool_name, tool_id, input } => {
290 assert_eq!(tool_name, "execute_bash");
291 assert_eq!(tool_id, "tool_123");
292 assert_eq!(input["command"], "ls -la");
293 assert_eq!(input["timeout"], 30);
294 }
295 _ => panic!("Expected ToolUse variant"),
296 }
297 }
298
299 #[test]
300 fn test_server_message_usage_roundtrip() {
301 let msg = ServerMessage::Usage {
302 input_tokens: 150,
303 output_tokens: 75,
304 cache_creation_5m: None,
305 cache_creation_1h: None,
306 };
307
308 let json_value = serde_json::to_value(&msg).unwrap();
310
311 assert_eq!(json_value["type"], "usage");
313 assert_eq!(json_value["input_tokens"], 150);
314 assert_eq!(json_value["output_tokens"], 75);
315 assert!(json_value.get("cache_creation_5m").is_none());
318 assert!(json_value.get("cache_creation_1h").is_none());
319
320 let deserialized: ServerMessage = serde_json::from_value(json_value).unwrap();
322 match deserialized {
323 ServerMessage::Usage { input_tokens, output_tokens, cache_creation_5m, cache_creation_1h } => {
324 assert_eq!(input_tokens, 150);
325 assert_eq!(output_tokens, 75);
326 assert_eq!(cache_creation_5m, None);
327 assert_eq!(cache_creation_1h, None);
328 }
329 _ => panic!("Expected Usage variant"),
330 }
331 }
332
333 #[test]
334 fn test_history_entry_user_roundtrip() {
335 let entry = HistoryEntry::User {
336 content: "User message".to_string(),
337 time: "2023-10-01T12:00:00Z".to_string(),
338 };
339
340 let json_value = serde_json::to_value(&entry).unwrap();
342
343 assert_eq!(json_value["role"], "user");
345 assert_eq!(json_value["content"], "User message");
346 assert_eq!(json_value["time"], "2023-10-01T12:00:00Z");
347
348 let deserialized: HistoryEntry = serde_json::from_value(json_value).unwrap();
350 match deserialized {
351 HistoryEntry::User { content, time } => {
352 assert_eq!(content, "User message");
353 assert_eq!(time, "2023-10-01T12:00:00Z");
354 }
355 _ => panic!("Expected User variant"),
356 }
357 }
358}