Skip to main content

agentic_evolve_core/collective/
usage.rs

1//! UsageTracker — tracks pattern usage statistics.
2
3use std::collections::HashMap;
4
5/// Usage record for a pattern.
6#[derive(Debug, Clone, Default)]
7pub struct UsageRecord {
8    pub total_uses: u64,
9    pub successful_uses: u64,
10    pub failed_uses: u64,
11    pub last_used: i64,
12    pub first_used: i64,
13    pub domains: HashMap<String, u64>,
14}
15
16/// Tracks how often patterns are used.
17#[derive(Debug, Default)]
18pub struct UsageTracker {
19    records: HashMap<String, UsageRecord>,
20}
21
22impl UsageTracker {
23    pub fn new() -> Self {
24        Self::default()
25    }
26
27    pub fn record_use(&mut self, pattern_id: &str, domain: &str, success: bool) {
28        let now = chrono::Utc::now().timestamp();
29        let record = self
30            .records
31            .entry(pattern_id.to_string())
32            .or_insert_with(|| UsageRecord {
33                first_used: now,
34                ..Default::default()
35            });
36        record.total_uses += 1;
37        if success {
38            record.successful_uses += 1;
39        } else {
40            record.failed_uses += 1;
41        }
42        record.last_used = now;
43        *record.domains.entry(domain.to_string()).or_insert(0) += 1;
44    }
45
46    pub fn get_usage(&self, pattern_id: &str) -> Option<&UsageRecord> {
47        self.records.get(pattern_id)
48    }
49
50    pub fn success_rate(&self, pattern_id: &str) -> f64 {
51        self.records.get(pattern_id).map_or(0.0, |r| {
52            if r.total_uses == 0 {
53                0.0
54            } else {
55                r.successful_uses as f64 / r.total_uses as f64
56            }
57        })
58    }
59
60    pub fn most_used(&self, limit: usize) -> Vec<(&str, &UsageRecord)> {
61        let mut entries: Vec<_> = self.records.iter().map(|(k, v)| (k.as_str(), v)).collect();
62        entries.sort_by(|a, b| b.1.total_uses.cmp(&a.1.total_uses));
63        entries.truncate(limit);
64        entries
65    }
66
67    pub fn least_used(&self, limit: usize) -> Vec<(&str, &UsageRecord)> {
68        let mut entries: Vec<_> = self.records.iter().map(|(k, v)| (k.as_str(), v)).collect();
69        entries.sort_by(|a, b| a.1.total_uses.cmp(&b.1.total_uses));
70        entries.truncate(limit);
71        entries
72    }
73
74    pub fn total_patterns_tracked(&self) -> usize {
75        self.records.len()
76    }
77
78    pub fn clear(&mut self) {
79        self.records.clear();
80    }
81}