1use std::time::Instant;
8
9#[derive(Debug, Default)]
11pub struct AgentMetrics {
12 pub tasks_started: u64,
13 pub tasks_completed: u64,
14 pub tasks_failed: u64,
15 pub tool_calls: u64,
16 pub total_input_tokens: u64,
17 pub total_output_tokens: u64,
18 pub errors: u64,
19 start_time: Option<Instant>,
20}
21
22impl AgentMetrics {
23 pub fn new() -> Self {
24 Self {
25 start_time: Some(Instant::now()),
26 ..Default::default()
27 }
28 }
29
30 pub fn record_task_start(&mut self) {
32 self.tasks_started += 1;
33 }
34
35 pub fn record_task_complete(&mut self) {
37 self.tasks_completed += 1;
38 }
39
40 pub fn record_task_failed(&mut self) {
42 self.tasks_failed += 1;
43 }
44
45 pub fn record_tool_call(&mut self) {
47 self.tool_calls += 1;
48 }
49
50 pub fn record_tokens(&mut self, input: u64, output: u64) {
52 self.total_input_tokens += input;
53 self.total_output_tokens += output;
54 }
55
56 pub fn record_error(&mut self) {
58 self.errors += 1;
59 }
60
61 pub fn uptime_secs(&self) -> u64 {
63 self.start_time.map(|s| s.elapsed().as_secs()).unwrap_or(0)
64 }
65
66 pub fn snapshot(&self) -> MetricsSnapshot {
68 MetricsSnapshot {
69 tasks_started: self.tasks_started,
70 tasks_completed: self.tasks_completed,
71 tasks_failed: self.tasks_failed,
72 tool_calls: self.tool_calls,
73 total_input_tokens: self.total_input_tokens,
74 total_output_tokens: self.total_output_tokens,
75 errors: self.errors,
76 uptime_secs: self.uptime_secs(),
77 }
78 }
79}
80
81#[derive(Debug, Clone, serde::Serialize)]
83pub struct MetricsSnapshot {
84 pub tasks_started: u64,
85 pub tasks_completed: u64,
86 pub tasks_failed: u64,
87 pub tool_calls: u64,
88 pub total_input_tokens: u64,
89 pub total_output_tokens: u64,
90 pub errors: u64,
91 pub uptime_secs: u64,
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_metrics_default() {
100 let m = AgentMetrics::new();
101 assert_eq!(m.tasks_started, 0);
102 assert_eq!(m.tasks_completed, 0);
103 assert_eq!(m.tool_calls, 0);
104 }
105
106 #[test]
107 fn test_record_task_lifecycle() {
108 let mut m = AgentMetrics::new();
109 m.record_task_start();
110 m.record_task_start();
111 m.record_task_complete();
112 m.record_task_failed();
113
114 assert_eq!(m.tasks_started, 2);
115 assert_eq!(m.tasks_completed, 1);
116 assert_eq!(m.tasks_failed, 1);
117 }
118
119 #[test]
120 fn test_record_tokens() {
121 let mut m = AgentMetrics::new();
122 m.record_tokens(100, 50);
123 m.record_tokens(200, 100);
124 assert_eq!(m.total_input_tokens, 300);
125 assert_eq!(m.total_output_tokens, 150);
126 }
127
128 #[test]
129 fn test_snapshot() {
130 let mut m = AgentMetrics::new();
131 m.record_task_start();
132 m.record_tool_call();
133 m.record_error();
134
135 let snap = m.snapshot();
136 assert_eq!(snap.tasks_started, 1);
137 assert_eq!(snap.tool_calls, 1);
138 assert_eq!(snap.errors, 1);
139 }
140
141 #[test]
142 fn test_uptime() {
143 let m = AgentMetrics::new();
144 assert!(m.uptime_secs() < 5);
146 }
147
148 #[test]
149 fn test_noop_when_default() {
150 let m = AgentMetrics::default();
151 assert_eq!(m.uptime_secs(), 0); }
153}