Skip to main content

claude_agent_sdk/internal/
parser.rs

1use crate::error::{ClaudeSDKError, MessageParseError, Result};
2use crate::types::{
3    HookEventMessage, Message, MirrorErrorMessage, TaskNotificationMessage, TaskProgressMessage,
4    TaskStartedMessage,
5};
6
7const KNOWN_MESSAGE_TYPES: &[&str] = &[
8    "user",
9    "assistant",
10    "system",
11    "result",
12    "stream_event",
13    "rate_limit_event",
14];
15
16pub fn parse_message_line(line: &str) -> Result<Option<Message>> {
17    let value = serde_json::from_str::<serde_json::Value>(line)?;
18    parse_message_value(value)
19}
20
21pub fn parse_message_value(value: serde_json::Value) -> Result<Option<Message>> {
22    let message_type = value.get("type").and_then(|v| v.as_str()).ok_or_else(|| {
23        let data = value.as_object().cloned();
24        let mut error = MessageParseError::new("Message missing 'type' field");
25        if let Some(data) = data {
26            error = error.with_data(data);
27        }
28        ClaudeSDKError::MessageParse(error)
29    })?;
30
31    if !KNOWN_MESSAGE_TYPES.contains(&message_type) {
32        return Ok(None);
33    }
34
35    if message_type == "system" {
36        return parse_system_message_value(value);
37    }
38
39    serde_json::from_value::<Message>(value)
40        .map(Some)
41        .map_err(ClaudeSDKError::Serialization)
42}
43
44fn parse_system_message_value(value: serde_json::Value) -> Result<Option<Message>> {
45    let subtype = value.get("subtype").and_then(|v| v.as_str());
46    match subtype {
47        Some("task_started") => parse_task_started(value)
48            .map(Message::TaskStartedMsg)
49            .map(Some),
50        Some("task_progress") => parse_task_progress(value)
51            .map(Message::TaskProgressMsg)
52            .map(Some),
53        Some("task_notification") => parse_task_notification(value)
54            .map(Message::TaskNotificationMsg)
55            .map(Some),
56        Some("hook_started" | "hook_response") => {
57            parse_hook_event(value).map(Message::HookEventMsg).map(Some)
58        }
59        Some("mirror_error") => parse_mirror_error(value)
60            .map(Message::MirrorErrorMsg)
61            .map(Some),
62        _ => serde_json::from_value::<Message>(value)
63            .map(Some)
64            .map_err(ClaudeSDKError::Serialization),
65    }
66}
67
68fn parse_mirror_error(value: serde_json::Value) -> Result<MirrorErrorMessage> {
69    let mut data = value.as_object().cloned().ok_or_else(|| {
70        ClaudeSDKError::MessageParse(MessageParseError::new("System message must be an object"))
71    })?;
72    data.remove("type");
73    let key = data.get("key").and_then(|value| value.as_object()).cloned();
74    let error = data
75        .get("error")
76        .and_then(|value| value.as_str())
77        .unwrap_or_default()
78        .to_string();
79    Ok(MirrorErrorMessage { key, error, data })
80}
81
82fn parse_task_started(value: serde_json::Value) -> Result<TaskStartedMessage> {
83    serde_json::from_value::<TaskStartedMessage>(strip_system_fields(value)?)
84        .map_err(ClaudeSDKError::Serialization)
85}
86
87fn parse_task_progress(value: serde_json::Value) -> Result<TaskProgressMessage> {
88    serde_json::from_value::<TaskProgressMessage>(strip_system_fields(value)?)
89        .map_err(ClaudeSDKError::Serialization)
90}
91
92fn parse_task_notification(value: serde_json::Value) -> Result<TaskNotificationMessage> {
93    serde_json::from_value::<TaskNotificationMessage>(strip_system_fields(value)?)
94        .map_err(ClaudeSDKError::Serialization)
95}
96
97fn parse_hook_event(value: serde_json::Value) -> Result<HookEventMessage> {
98    let mut data = value.as_object().cloned().ok_or_else(|| {
99        ClaudeSDKError::MessageParse(MessageParseError::new("System message must be an object"))
100    })?;
101    let subtype = data
102        .get("subtype")
103        .and_then(|value| value.as_str())
104        .unwrap_or_default()
105        .to_string();
106    let hook_event_name = data
107        .get("hook_event")
108        .or_else(|| data.get("hook_name"))
109        .and_then(|value| value.as_str())
110        .map(ToString::to_string);
111    let session_id = data
112        .get("session_id")
113        .and_then(|value| value.as_str())
114        .map(ToString::to_string);
115    let uuid = data
116        .get("uuid")
117        .and_then(|value| value.as_str())
118        .map(ToString::to_string);
119    data.remove("type");
120    Ok(HookEventMessage {
121        subtype,
122        hook_event_name,
123        session_id,
124        uuid,
125        data,
126    })
127}
128
129fn strip_system_fields(value: serde_json::Value) -> Result<serde_json::Value> {
130    let mut data = value.as_object().cloned().ok_or_else(|| {
131        ClaudeSDKError::MessageParse(MessageParseError::new("System message must be an object"))
132    })?;
133    data.remove("type");
134    data.remove("subtype");
135    Ok(serde_json::Value::Object(data))
136}