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