Skip to main content

memory_core/autonomous/
adaptive.rs

1/// Query complexity level for adaptive retrieval depth.
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum Complexity {
4    Simple,
5    Moderate,
6    Complex,
7}
8
9const QUESTION_WORDS: &[&str] = &["how", "why", "what", "when", "where", "which"];
10const MULTI_CONCEPT_MARKERS: &[&str] = &[" and ", " with ", " across ", " between "];
11const ABSTRACTION_WORDS: &[&str] = &[
12    "architecture",
13    "design",
14    "pattern",
15    "flow",
16    "system",
17    "structure",
18    "approach",
19    "strategy",
20    "overview",
21];
22
23/// Estimate the complexity of a search query.
24pub fn estimate_complexity(query: &str) -> Complexity {
25    let words: Vec<&str> = query.split_whitespace().collect();
26    let word_count = words.len();
27
28    let has_question = query.contains('?')
29        || words
30            .first()
31            .map(|w| QUESTION_WORDS.contains(&w.to_lowercase().as_str()))
32            .unwrap_or(false);
33
34    let lower = query.to_lowercase();
35    let has_multi_concept = MULTI_CONCEPT_MARKERS.iter().any(|m| lower.contains(m));
36    let has_abstraction = ABSTRACTION_WORDS.iter().any(|w| lower.contains(w));
37
38    if has_multi_concept || has_abstraction || (has_question && word_count > 8) {
39        Complexity::Complex
40    } else if word_count <= 3 && !has_question {
41        Complexity::Simple
42    } else {
43        Complexity::Moderate
44    }
45}
46
47/// Return an adaptive result limit based on query complexity.
48pub fn adaptive_limit(query: &str, base_limit: i32) -> i32 {
49    match estimate_complexity(query) {
50        Complexity::Simple => (base_limit as f64 * 0.5).max(3.0) as i32,
51        Complexity::Moderate => base_limit,
52        Complexity::Complex => (base_limit as f64 * 2.0).min(20.0) as i32,
53    }
54}
55
56/// Estimate token count from text (rough: 1 token ≈ 4 chars).
57pub fn estimate_tokens(text: &str) -> i32 {
58    (text.len() as f64 / 4.0).ceil() as i32
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn simple_query() {
67        assert_eq!(estimate_complexity("test command"), Complexity::Simple);
68        assert_eq!(estimate_complexity("auth"), Complexity::Simple);
69    }
70
71    #[test]
72    fn moderate_query() {
73        assert_eq!(
74            estimate_complexity("how does auth work"),
75            Complexity::Moderate
76        );
77        assert_eq!(
78            estimate_complexity("database connection setup guide"),
79            Complexity::Moderate
80        );
81    }
82
83    #[test]
84    fn complex_query() {
85        assert_eq!(
86            estimate_complexity("how does the authentication flow work across services"),
87            Complexity::Complex
88        );
89        assert_eq!(
90            estimate_complexity("system architecture overview"),
91            Complexity::Complex
92        );
93        assert_eq!(
94            estimate_complexity("design pattern for user auth and session management"),
95            Complexity::Complex
96        );
97    }
98
99    #[test]
100    fn adaptive_limit_scales() {
101        let base = 10;
102        assert_eq!(adaptive_limit("test", base), 5);
103        assert_eq!(adaptive_limit("how does auth work", base), 10);
104        assert_eq!(
105            adaptive_limit("how does the authentication flow work across services", base),
106            20
107        );
108    }
109
110    #[test]
111    fn adaptive_limit_respects_cap() {
112        assert!(adaptive_limit("complex architecture design overview", 15) <= 20);
113    }
114
115    #[test]
116    fn token_estimate() {
117        assert_eq!(estimate_tokens("hello world"), 3); // 11 chars / 4 = 2.75 -> 3
118        assert_eq!(estimate_tokens(""), 0);
119    }
120}