use std::time::Duration;
pub trait Observer: Send + Sync {
fn record_event(&self, event: &ObserverEvent);
fn record_metric(&self, metric: &ObserverMetric);
fn flush(&self) {}
fn name(&self) -> &str;
}
#[derive(Debug, Clone)]
pub enum ObserverEvent {
AgentStart { provider: String, model: String },
LlmRequest {
provider: String,
model: String,
message_count: usize,
},
LlmResponse {
provider: String,
model: String,
duration: Duration,
success: bool,
error_message: Option<String>,
},
ToolCallStart { tool: String },
ToolCallEnd {
tool: String,
duration: Duration,
success: bool,
},
TurnComplete,
ChannelMessage { channel: String, direction: String },
HeartbeatTick,
AgentEnd {
duration: Duration,
tokens_used: Option<u64>,
},
Error { component: String, message: String },
}
#[derive(Debug, Clone)]
pub enum ObserverMetric {
RequestLatency(Duration),
TokensUsed(u64),
ActiveJobs(u64),
QueueDepth(u64),
}
#[cfg(test)]
mod tests {
use crate::observability::traits::*;
#[test]
fn event_variants_are_constructible() {
let _ = ObserverEvent::AgentStart {
provider: "nearai".into(),
model: "test".into(),
};
let _ = ObserverEvent::LlmRequest {
provider: "nearai".into(),
model: "test".into(),
message_count: 3,
};
let _ = ObserverEvent::LlmResponse {
provider: "nearai".into(),
model: "test".into(),
duration: Duration::from_millis(100),
success: true,
error_message: None,
};
let _ = ObserverEvent::ToolCallStart {
tool: "echo".into(),
};
let _ = ObserverEvent::ToolCallEnd {
tool: "echo".into(),
duration: Duration::from_millis(5),
success: true,
};
let _ = ObserverEvent::TurnComplete;
let _ = ObserverEvent::ChannelMessage {
channel: "tui".into(),
direction: "inbound".into(),
};
let _ = ObserverEvent::HeartbeatTick;
let _ = ObserverEvent::AgentEnd {
duration: Duration::from_secs(10),
tokens_used: Some(1500),
};
let _ = ObserverEvent::Error {
component: "llm".into(),
message: "timeout".into(),
};
}
#[test]
fn metric_variants_are_constructible() {
let _ = ObserverMetric::RequestLatency(Duration::from_millis(200));
let _ = ObserverMetric::TokensUsed(500);
let _ = ObserverMetric::ActiveJobs(3);
let _ = ObserverMetric::QueueDepth(10);
}
}