1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
//! Claude Code JSON protocol types for stdin communication.
//!
//! When using `--input-format=stream-json`, Claude Code expects
//! newline-delimited JSON messages on stdin.
use serde::Serialize;
/// Message sent to Claude Code via stdin.
///
/// Format based on Claude Code's stream-json input protocol.
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ClaudeInputMessage {
/// A user message to send to Claude.
User { message: UserMessage },
}
/// The inner user message structure.
#[derive(Debug, Clone, Serialize)]
pub struct UserMessage {
/// Always "user" for user messages.
pub role: String,
/// The message content.
pub content: String,
}
impl ClaudeInputMessage {
/// Create a new user message.
pub fn user(content: impl Into<String>) -> Self {
Self::User {
message: UserMessage {
role: "user".to_string(),
content: content.into(),
},
}
}
/// Serialize to a JSON string with trailing newline (NDJSON format).
pub fn to_json_line(&self) -> Result<String, serde_json::Error> {
let mut json = serde_json::to_string(self)?;
json.push('\n');
Ok(json)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_message_serialization() {
let msg = ClaudeInputMessage::user("Hello, Claude!");
let json = msg.to_json_line().unwrap();
// Should produce: {"type":"user","message":{"role":"user","content":"Hello, Claude!"}}\n
assert!(json.starts_with(r#"{"type":"user","message":{"role":"user","content":"Hello, Claude!"}}"#));
assert!(json.ends_with('\n'));
}
}
|