use lc_core::language_models::TokenUsage;
use std::time::Duration;
#[derive(Debug, Clone, Default)]
pub struct AgentMetrics {
pub trace_id: Option<String>,
pub llm_calls: usize,
pub cache_hits: usize,
pub tool_calls: usize,
pub total_tokens: Option<usize>,
pub duration: Duration,
}
impl AgentMetrics {
pub fn add_token_usage(&mut self, usage: &TokenUsage) {
self.total_tokens = Some(self.total_tokens.unwrap_or(0) + usage.total_tokens);
}
pub fn tokens_per_call(&self) -> Option<f64> {
if self.llm_calls == 0 {
return None;
}
self.total_tokens.map(|t| t as f64 / self.llm_calls as f64)
}
pub fn log_summary(&self) {
let trace = self.trace_id.as_deref().unwrap_or("-");
let duration_ms = self.duration.as_millis();
match self.total_tokens {
Some(tokens) => log::info!(
target: "lc_agents::metrics",
"agent_exec summary trace_id={} llm_calls={} tool_calls={} total_tokens={} duration_ms={}",
trace,
self.llm_calls,
self.tool_calls,
tokens,
duration_ms
),
None => log::info!(
target: "lc_agents::metrics",
"agent_exec summary trace_id={} llm_calls={} tool_calls={} total_tokens=n/a duration_ms={}",
trace,
self.llm_calls,
self.tool_calls,
duration_ms
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_metrics_default() {
let m = AgentMetrics::default();
assert_eq!(m.llm_calls, 0);
assert_eq!(m.tool_calls, 0);
assert_eq!(m.total_tokens, None);
assert_eq!(m.trace_id, None);
assert_eq!(m.duration, Duration::ZERO);
}
#[test]
fn test_add_token_usage() {
let mut m = AgentMetrics::default();
m.add_token_usage(&TokenUsage {
prompt_tokens: 10,
completion_tokens: 5,
total_tokens: 15,
});
m.add_token_usage(&TokenUsage {
prompt_tokens: 3,
completion_tokens: 2,
total_tokens: 5,
});
assert_eq!(m.total_tokens, Some(20));
}
#[test]
fn test_tokens_per_call() {
let mut m = AgentMetrics::default();
assert_eq!(m.tokens_per_call(), None);
m.llm_calls = 2;
m.total_tokens = Some(20);
assert_eq!(m.tokens_per_call(), Some(10.0));
}
#[test]
fn test_tokens_per_call_zero_calls() {
let m = AgentMetrics {
total_tokens: Some(10),
..Default::default()
};
assert_eq!(m.tokens_per_call(), None);
}
#[test]
fn test_log_summary_no_panic() {
let mut m = AgentMetrics::default();
m.trace_id = Some("trace-x".to_string());
m.log_summary();
m.total_tokens = Some(42);
m.log_summary();
}
}