Skip to main content

vtcode_core/code/code_completion/learning/
feedback.rs

1/// Feedback processor for analyzing user interactions
2pub struct FeedbackProcessor {
3    feedback_history: Vec<FeedbackEntry>,
4}
5
6#[derive(Debug, Clone)]
7struct FeedbackEntry {
8    suggestion: String,
9    accepted: bool,
10    context: String,
11    timestamp: std::time::SystemTime,
12}
13
14impl Default for FeedbackProcessor {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl FeedbackProcessor {
21    pub fn new() -> Self {
22        Self { feedback_history: Vec::new() }
23    }
24
25    /// Process user feedback
26    pub fn process(&mut self, suggestion: &str, accepted: bool, context: &str) {
27        let entry = FeedbackEntry {
28            suggestion: suggestion.into(),
29            accepted,
30            context: context.into(),
31            timestamp: std::time::SystemTime::now(),
32        };
33
34        self.feedback_history.push(entry);
35
36        // Keep only recent feedback (last 1000 entries)
37        if self.feedback_history.len() > 1000 {
38            self.feedback_history.remove(0);
39        }
40    }
41
42    /// Get acceptance rate for a specific pattern
43    pub fn get_acceptance_rate(&self, pattern: &str) -> f64 {
44        use std::time::{Duration, SystemTime};
45
46        let now = SystemTime::now();
47        let mut weighted_sum = 0.0;
48        let mut total_weight = 0.0;
49
50        for entry in &self.feedback_history {
51            if !entry.suggestion.contains(pattern) {
52                continue;
53            }
54
55            let age_weight = now
56                .duration_since(entry.timestamp)
57                .map(|duration| {
58                    // Recent feedback counts more. Anything older than 30 days is heavily down-weighted.
59                    let thirty_days = Duration::from_secs(60 * 60 * 24 * 30);
60                    1.0 - (duration.as_secs_f64() / thirty_days.as_secs_f64()).min(0.9)
61                })
62                .unwrap_or(1.0);
63
64            let context_weight = if entry.context.is_empty() {
65                0.8
66            } else {
67                // Prefer matches where the usage context was recorded.
68                1.0
69            };
70
71            let weight = age_weight * context_weight;
72            total_weight += weight;
73            if entry.accepted {
74                weighted_sum += weight;
75            }
76        }
77
78        if total_weight == 0.0 {
79            return 0.5;
80        }
81
82        weighted_sum / total_weight
83    }
84}