use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::session_status::SessionStatus;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EventTopic {
Tool,
Llm,
Agent,
Session,
Cost,
System,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RuntimeEvent {
ToolCallStart {
tool_name: String,
call_id: String,
timestamp_ms: u64,
},
ToolCallEnd {
tool_name: String,
call_id: String,
duration_ms: u64,
success: bool,
timestamp_ms: u64,
},
LlmRequestStart {
model: String,
request_id: String,
timestamp_ms: u64,
},
LlmResponseEnd {
model: String,
request_id: String,
input_tokens: u64,
output_tokens: u64,
duration_ms: u64,
timestamp_ms: u64,
},
AgentStart {
agent_id: String,
task: String,
timestamp_ms: u64,
},
AgentEnd {
agent_id: String,
success: bool,
timestamp_ms: u64,
},
AgentError {
agent_id: String,
error: String,
timestamp_ms: u64,
},
SessionStart {
session_id: String,
timestamp_ms: u64,
},
SessionEnd {
session_id: String,
timestamp_ms: u64,
},
SessionStatusChanged {
session_id: String,
status: SessionStatus,
timestamp_ms: u64,
},
TokenUsage {
model: String,
input_tokens: u64,
output_tokens: u64,
cost_usd: f64,
timestamp_ms: u64,
},
BudgetExhausted {
budget_usd: f64,
total_cost_usd: f64,
timestamp_ms: u64,
},
ConfigReloaded { timestamp_ms: u64 },
ShutdownRequested { reason: String, timestamp_ms: u64 },
Custom {
event_type: String,
source: String,
data: Value,
timestamp_ms: u64,
},
}
impl RuntimeEvent {
pub fn topic(&self) -> EventTopic {
match self {
Self::ToolCallStart { .. } | Self::ToolCallEnd { .. } => EventTopic::Tool,
Self::LlmRequestStart { .. } | Self::LlmResponseEnd { .. } => EventTopic::Llm,
Self::AgentStart { .. } | Self::AgentEnd { .. } | Self::AgentError { .. } => {
EventTopic::Agent
}
Self::SessionStart { .. }
| Self::SessionEnd { .. }
| Self::SessionStatusChanged { .. } => EventTopic::Session,
Self::TokenUsage { .. } | Self::BudgetExhausted { .. } => EventTopic::Cost,
Self::ConfigReloaded { .. } | Self::ShutdownRequested { .. } => EventTopic::System,
Self::Custom { .. } => EventTopic::Custom,
}
}
pub fn timestamp_ms(&self) -> u64 {
match self {
Self::ToolCallStart { timestamp_ms, .. }
| Self::ToolCallEnd { timestamp_ms, .. }
| Self::LlmRequestStart { timestamp_ms, .. }
| Self::LlmResponseEnd { timestamp_ms, .. }
| Self::AgentStart { timestamp_ms, .. }
| Self::AgentEnd { timestamp_ms, .. }
| Self::AgentError { timestamp_ms, .. }
| Self::SessionStart { timestamp_ms, .. }
| Self::SessionEnd { timestamp_ms, .. }
| Self::SessionStatusChanged { timestamp_ms, .. }
| Self::TokenUsage { timestamp_ms, .. }
| Self::BudgetExhausted { timestamp_ms, .. }
| Self::ConfigReloaded { timestamp_ms, .. }
| Self::ShutdownRequested { timestamp_ms, .. }
| Self::Custom { timestamp_ms, .. } => *timestamp_ms,
}
}
}
pub fn now_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
#[derive(Debug, Clone)]
pub struct Event {
pub event_type: String,
pub source: String,
pub data: Value,
pub timestamp_ms: u64,
}
impl Event {
pub fn new(event_type: impl Into<String>, source: impl Into<String>, data: Value) -> Self {
Self {
event_type: event_type.into(),
source: source.into(),
data,
timestamp_ms: now_ms(),
}
}
pub fn into_runtime_event(self) -> RuntimeEvent {
RuntimeEvent::Custom {
event_type: self.event_type,
source: self.source,
data: self.data,
timestamp_ms: self.timestamp_ms,
}
}
}