use super::AgentEvent;
pub(super) struct PerfTracker {
tool_latency_sum: u64,
tool_latency_max: u64,
tool_call_count: u32,
api_latency_sum: u64,
api_latency_max: u64,
api_call_count: u32,
tool_successes: u32,
tool_failures: u32,
tool_freq: std::collections::HashMap<String, u32>,
total_tokens: u64,
iterations: u32,
top_tools_cache: Vec<(String, u32)>,
top_tools_dirty: bool,
}
impl PerfTracker {
pub(super) fn new() -> Self {
Self {
tool_latency_sum: 0,
tool_latency_max: 0,
tool_call_count: 0,
api_latency_sum: 0,
api_latency_max: 0,
api_call_count: 0,
tool_successes: 0,
tool_failures: 0,
tool_freq: std::collections::HashMap::new(),
total_tokens: 0,
iterations: 0,
top_tools_cache: Vec::new(),
top_tools_dirty: false,
}
}
pub(super) fn record_tool_call(&mut self, name: &str, elapsed_ms: u64, success: bool) {
self.tool_latency_sum += elapsed_ms;
if elapsed_ms > self.tool_latency_max {
self.tool_latency_max = elapsed_ms;
}
self.tool_call_count += 1;
*self.tool_freq.entry(name.to_string()).or_insert(0) += 1;
self.top_tools_dirty = true;
if success {
self.tool_successes += 1;
} else {
self.tool_failures += 1;
}
}
pub(super) fn record_api_latency(&mut self, elapsed_ms: u64) {
self.api_latency_sum += elapsed_ms;
if elapsed_ms > self.api_latency_max {
self.api_latency_max = elapsed_ms;
}
self.api_call_count += 1;
}
pub(super) fn record_iteration(&mut self, tokens: u64) {
self.iterations += 1;
self.total_tokens += tokens;
}
pub(super) fn build_event(&mut self) -> AgentEvent {
let tool_latency_avg_ms = if self.tool_call_count == 0 {
0.0
} else {
self.tool_latency_sum as f64 / self.tool_call_count as f64
};
let api_latency_avg_ms = if self.api_call_count == 0 {
0.0
} else {
self.api_latency_sum as f64 / self.api_call_count as f64
};
if self.top_tools_dirty {
let mut sorted: Vec<(String, u32)> = self
.tool_freq
.iter()
.map(|(k, v)| (k.clone(), *v))
.collect();
sorted.sort_unstable_by(|a, b| b.1.cmp(&a.1));
sorted.truncate(3);
self.top_tools_cache = sorted;
self.top_tools_dirty = false;
}
AgentEvent::PerformanceUpdate {
tool_latency_avg_ms,
tool_latency_max_ms: self.tool_latency_max,
api_latency_avg_ms,
api_latency_max_ms: self.api_latency_max,
tool_success_count: self.tool_successes,
tool_failure_count: self.tool_failures,
total_iterations: self.iterations,
total_tokens_used: self.total_tokens,
total_tool_calls_made: self.tool_call_count,
top_tools: self.top_tools_cache.clone(),
}
}
}