llm 1.3.8

A Rust library unifying multiple LLM backends.
Documentation
use std::time::{Duration, Instant};

const BURST_WINDOW: Duration = Duration::from_millis(24);
const BURST_HOLD: Duration = Duration::from_millis(180);
const BURST_THRESHOLD: usize = 5;

#[derive(Debug, Default, Clone)]
pub struct PasteDetector {
    last_at: Option<Instant>,
    burst_len: usize,
    burst_until: Option<Instant>,
}

impl PasteDetector {
    pub fn record_char(&mut self, now: Instant) -> bool {
        let within_window = self
            .last_at
            .map(|at| now.saturating_duration_since(at) <= BURST_WINDOW)
            .unwrap_or(false);
        if within_window {
            self.burst_len = self.burst_len.saturating_add(1);
        } else {
            self.burst_len = 1;
        }
        self.last_at = Some(now);
        if self.burst_len >= BURST_THRESHOLD {
            self.burst_until = Some(now + BURST_HOLD);
        }
        self.is_burst(now)
    }

    pub fn record_paste(&mut self, now: Instant) {
        self.last_at = Some(now);
        self.burst_len = 0;
        self.burst_until = Some(now + BURST_HOLD);
    }

    pub fn is_burst(&self, now: Instant) -> bool {
        self.burst_until.map(|until| now <= until).unwrap_or(false)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn detects_burst_after_threshold() {
        let mut detector = PasteDetector::default();
        let start = Instant::now();
        for idx in 0..BURST_THRESHOLD {
            let now = start + BURST_WINDOW / 2 * idx as u32;
            detector.record_char(now);
        }
        assert!(detector.is_burst(start + BURST_WINDOW));
    }
}