Skip to main content

ainl_compression/
adaptive.rs

1//! Embedding-free content classifier for **adaptive eco** mode selection.
2//!
3//! Hosts may combine this with `CompressionProfile` defaults, telemetry, and user prefs.
4
5use crate::EfficientMode;
6
7/// Outcome of [`recommend_mode_for_content`].
8#[derive(Debug, Clone, PartialEq)]
9pub struct AdaptiveRecommendation {
10    pub mode: EfficientMode,
11    /// Heuristic confidence in \[0, 1\].
12    pub confidence: f32,
13    pub reasons: Vec<&'static str>,
14}
15
16fn est_tokens(text: &str) -> usize {
17    text.len() / 4 + 1
18}
19
20/// Rough signal for code / URL / opcode-heavy prompts (higher → keep safer mode).
21fn structure_density(text: &str) -> f32 {
22    let len = text.len().max(1) as f32;
23    let mut score = 0.0_f32;
24    score += text.matches("```").count() as f32 * 0.08;
25    score += text.matches("http://").count() as f32 * 0.04;
26    score += text.matches("https://").count() as f32 * 0.04;
27    score += text.matches("::").count() as f32 * 0.01;
28    score += text.matches("R ").count() as f32 * 0.02;
29    score += text.matches(".ainl").count() as f32 * 0.03;
30    (score / len * 600.0).clamp(0.0, 1.0)
31}
32
33/// Recommend an [`EfficientMode`] from raw prompt text (mirrors short-prompt passthrough threshold in [`crate::compress`]).
34#[must_use]
35pub fn recommend_mode_for_content(text: &str) -> AdaptiveRecommendation {
36    let tokens = est_tokens(text);
37    let density = structure_density(text);
38    let mut reasons: Vec<&'static str> = Vec::new();
39
40    if tokens < 80 {
41        reasons.push("below_compression_floor");
42        return AdaptiveRecommendation {
43            mode: EfficientMode::Off,
44            confidence: 0.88,
45            reasons,
46        };
47    }
48
49    if density > 0.32 {
50        reasons.push("structured_or_code_heavy");
51        return AdaptiveRecommendation {
52            mode: EfficientMode::Balanced,
53            confidence: 0.72,
54            reasons,
55        };
56    }
57
58    if tokens > 420 {
59        reasons.push("long_prose_budget_pressure");
60        return AdaptiveRecommendation {
61            mode: EfficientMode::Aggressive,
62            confidence: 0.58,
63            reasons,
64        };
65    }
66
67    reasons.push("general_prompt");
68    AdaptiveRecommendation {
69        mode: EfficientMode::Balanced,
70        confidence: 0.62,
71        reasons,
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn short_is_off() {
81        let r = recommend_mode_for_content("Hello.");
82        assert_eq!(r.mode, EfficientMode::Off);
83    }
84
85    #[test]
86    fn code_fence_prefers_balanced() {
87        let filler = "y".repeat(400);
88        let r = recommend_mode_for_content(&(filler + "\n```rust\nfn main(){}\n```"));
89        assert_eq!(r.mode, EfficientMode::Balanced);
90    }
91}