use crate::{TokenUsage, ToolCall, ToolResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventKind {
ToolCall(ToolCall),
ToolResult(ToolResult),
AssistantMessage {
content: String,
#[serde(skip_serializing_if = "Option::is_none")]
usage: Option<TokenUsage>,
},
UserMessage { content: String },
TokenUsage(TokenUsage),
Thinking {
text: String,
#[serde(skip_serializing_if = "Option::is_none")]
signature: Option<String>,
},
#[serde(other)]
Unknown,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{ToolCall, ToolResult};
use serde_json::json;
#[test]
fn tool_call_round_trips() {
let kind = EventKind::ToolCall(ToolCall {
id: "id1".into(),
name: "Bash".into(),
input: json!({"command": "ls"}),
});
let json = serde_json::to_string(&kind).unwrap();
let back: EventKind = serde_json::from_str(&json).unwrap();
assert_eq!(kind, back);
}
#[test]
fn tool_result_round_trips() {
let kind = EventKind::ToolResult(ToolResult {
tool_use_id: "id1".into(),
content: "ok".into(),
is_error: false,
metadata: None,
});
let json = serde_json::to_string(&kind).unwrap();
let back: EventKind = serde_json::from_str(&json).unwrap();
assert_eq!(kind, back);
}
#[test]
fn assistant_message_without_usage_omits_field() {
let kind = EventKind::AssistantMessage {
content: "hi".into(),
usage: None,
};
let json = serde_json::to_string(&kind).unwrap();
assert!(!json.contains("usage"));
}
#[test]
fn unknown_variant_deserialises_from_unrecognised_type() {
let json = r#"{"type":"future_unknown_thing"}"#;
let kind: EventKind = serde_json::from_str(json).unwrap();
assert_eq!(kind, EventKind::Unknown);
}
}