use serde::{Deserialize, Serialize};
use std::time::SystemTime;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum MessageType {
Init,
User,
Assistant,
Result,
System,
Tool,
ToolResult,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageMeta {
pub session_id: String,
pub timestamp: Option<SystemTime>,
pub cost_usd: Option<f64>,
pub duration_ms: Option<u64>,
pub tokens_used: Option<TokenUsage>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenUsage {
pub input: u64,
pub output: u64,
pub total: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[allow(missing_docs)] pub enum Message {
Init {
#[serde(flatten)]
meta: MessageMeta,
},
User {
content: String,
#[serde(flatten)]
meta: MessageMeta,
},
Assistant {
content: String,
#[serde(flatten)]
meta: MessageMeta,
},
Result {
#[serde(flatten)]
meta: MessageMeta,
stats: ConversationStats,
},
System {
content: String,
#[serde(flatten)]
meta: MessageMeta,
},
Tool {
name: String,
parameters: serde_json::Value,
#[serde(flatten)]
meta: MessageMeta,
},
ToolResult {
tool_name: String,
result: serde_json::Value,
#[serde(flatten)]
meta: MessageMeta,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationStats {
pub total_messages: u64,
pub total_cost_usd: f64,
pub total_duration_ms: u64,
pub total_tokens: TokenUsage,
}
impl Message {
pub fn message_type(&self) -> MessageType {
match self {
Message::Init { .. } => MessageType::Init,
Message::User { .. } => MessageType::User,
Message::Assistant { .. } => MessageType::Assistant,
Message::Result { .. } => MessageType::Result,
Message::System { .. } => MessageType::System,
Message::Tool { .. } => MessageType::Tool,
Message::ToolResult { .. } => MessageType::ToolResult,
}
}
pub fn meta(&self) -> &MessageMeta {
match self {
Message::Init { meta, .. }
| Message::User { meta, .. }
| Message::Assistant { meta, .. }
| Message::Result { meta, .. }
| Message::System { meta, .. }
| Message::Tool { meta, .. }
| Message::ToolResult { meta, .. } => meta,
}
}
pub fn content(&self) -> String {
match self {
Message::User { content, .. }
| Message::Assistant { content, .. }
| Message::System { content, .. } => content.clone(),
Message::Tool {
name, parameters, ..
} => {
format!("Tool: {name} with parameters: {parameters}")
}
Message::ToolResult {
tool_name, result, ..
} => {
format!("Tool result from {tool_name}: {result}")
}
Message::Init { .. } => "Session initialized".to_string(),
Message::Result { stats, .. } => {
format!(
"Conversation stats: {} messages, ${:.6} total cost",
stats.total_messages, stats.total_cost_usd
)
}
}
}
}