claude_code_rs/
message_parser.rs1use serde_json::Value;
2
3use crate::error::{Error, Result};
4use crate::types::messages::{AssistantMessage, Message, ResultMessage, UserMessage};
5
6pub fn parse_message(raw: Value) -> Result<Message> {
15 let msg_type = raw
16 .get("type")
17 .and_then(|v| v.as_str())
18 .ok_or_else(|| Error::MessageParse {
19 reason: "missing 'type' field".into(),
20 })?;
21
22 match msg_type {
23 "assistant" => parse_assistant(raw),
24 "user" => parse_user(raw),
25 "result" => parse_result(raw),
26 "system" => parse_system(raw),
27 other => Ok(Message::Unknown {
28 message_type: other.to_string(),
29 raw,
30 }),
31 }
32}
33
34fn parse_assistant(raw: Value) -> Result<Message> {
35 let message_value = raw.get("message").cloned().unwrap_or(raw.clone());
37
38 let message: AssistantMessage =
39 serde_json::from_value(message_value).map_err(|e| Error::MessageParse {
40 reason: format!("assistant message parse failed: {e}"),
41 })?;
42
43 Ok(Message::Assistant { message })
44}
45
46fn parse_user(raw: Value) -> Result<Message> {
47 let message_value = raw.get("message").cloned().unwrap_or(raw.clone());
48
49 let message: UserMessage =
50 serde_json::from_value(message_value).map_err(|e| Error::MessageParse {
51 reason: format!("user message parse failed: {e}"),
52 })?;
53
54 Ok(Message::User { message })
55}
56
57fn parse_result(raw: Value) -> Result<Message> {
58 let result: ResultMessage =
60 serde_json::from_value(raw).map_err(|e| Error::MessageParse {
61 reason: format!("result message parse failed: {e}"),
62 })?;
63
64 Ok(Message::Result { result })
65}
66
67fn parse_system(raw: Value) -> Result<Message> {
68 let subtype = raw
69 .get("subtype")
70 .and_then(|v| v.as_str())
71 .unwrap_or("unknown")
72 .to_string();
73
74 Ok(Message::System {
75 subtype,
76 data: raw,
77 })
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn parse_assistant_message() {
86 let raw = serde_json::json!({
87 "type": "assistant",
88 "message": {
89 "model": "claude-sonnet-4-5",
90 "content": [
91 {"type": "text", "text": "Hello!"}
92 ]
93 }
94 });
95 let msg = parse_message(raw).unwrap();
96 assert!(matches!(msg, Message::Assistant { .. }));
97 assert_eq!(msg.text().unwrap(), "Hello!");
98 }
99
100 #[test]
101 fn parse_user_message() {
102 let raw = serde_json::json!({
103 "type": "user",
104 "message": {
105 "content": "What is 2+2?"
106 }
107 });
108 let msg = parse_message(raw).unwrap();
109 assert!(matches!(msg, Message::User { .. }));
110 }
111
112 #[test]
113 fn parse_result_message() {
114 let raw = serde_json::json!({
115 "type": "result",
116 "subtype": "success",
117 "is_error": false,
118 "duration_ms": 1234.0,
119 "num_turns": 3,
120 "session_id": "sess_123",
121 "total_cost_usd": 0.05
122 });
123 let msg = parse_message(raw).unwrap();
124 assert!(msg.is_result());
125 assert!(!msg.is_error());
126 assert_eq!(msg.session_id(), Some("sess_123"));
127 }
128
129 #[test]
130 fn parse_system_message() {
131 let raw = serde_json::json!({
132 "type": "system",
133 "subtype": "init",
134 "data": {"version": "2.1.0"}
135 });
136 let msg = parse_message(raw).unwrap();
137 match msg {
138 Message::System { subtype, .. } => assert_eq!(subtype, "init"),
139 _ => panic!("expected System"),
140 }
141 }
142
143 #[test]
144 fn parse_unknown_type() {
145 let raw = serde_json::json!({
146 "type": "stream_event",
147 "event": {"delta": "hello"}
148 });
149 let msg = parse_message(raw).unwrap();
150 match msg {
151 Message::Unknown { message_type, .. } => assert_eq!(message_type, "stream_event"),
152 _ => panic!("expected Unknown"),
153 }
154 }
155
156 #[test]
157 fn parse_missing_type() {
158 let raw = serde_json::json!({"data": "oops"});
159 assert!(parse_message(raw).is_err());
160 }
161
162 #[test]
163 fn parse_assistant_with_tool_use() {
164 let raw = serde_json::json!({
165 "type": "assistant",
166 "message": {
167 "model": "claude-sonnet-4-5",
168 "content": [
169 {"type": "text", "text": "Let me run that."},
170 {"type": "tool_use", "id": "tu_1", "name": "Bash", "input": {"command": "ls"}}
171 ]
172 }
173 });
174 let msg = parse_message(raw).unwrap();
175 if let Message::Assistant { message } = msg {
176 assert_eq!(message.content.len(), 2);
177 } else {
178 panic!("expected Assistant");
179 }
180 }
181}