Skip to main content

st/
m8_context_aware.rs

1// Context-Aware .m8 Reader - Progressive detail on demand! 🎯
2// "Like RAM banking on the C64 - load only what you need!" - Hue
3
4use anyhow::Result;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::fs;
8use std::path::{Path, PathBuf};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ContextualM8 {
12    pub frequency: f64,
13    pub essence: String,
14    pub keywords: Vec<String>,
15    pub depth_level: u8, // 0=summary, 1=overview, 2=detailed, 3=full
16    pub children: HashMap<String, f64>, // child_name -> frequency
17    pub context_triggers: HashMap<String, String>, // keyword -> expansion_path
18}
19
20pub struct ContextAwareReader {
21    cache: HashMap<PathBuf, ContextualM8>,
22    current_context: Vec<String>, // Current conversation keywords
23    expansion_threshold: f64,     // Similarity threshold for auto-expansion
24}
25
26impl Default for ContextAwareReader {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl ContextAwareReader {
33    pub fn new() -> Self {
34        Self {
35            cache: HashMap::new(),
36            current_context: Vec::new(),
37            expansion_threshold: 0.7,
38        }
39    }
40
41    /// Load .m8 with minimal context (just essence)
42    pub fn load_minimal(&mut self, path: &Path) -> Result<String> {
43        let m8 = self.load_m8(path)?;
44
45        // Return just the essence - super minimal
46        Ok(format!(
47            "📍 {}: {}",
48            path.file_name().unwrap_or_default().to_string_lossy(),
49            m8.essence
50        ))
51    }
52
53    /// Load with smart context based on current conversation
54    pub fn load_contextual(&mut self, path: &Path, context_keywords: &[String]) -> Result<String> {
55        let m8 = self.load_m8(path)?;
56
57        // Calculate relevance score
58        let relevance = self.calculate_relevance(&m8, context_keywords);
59
60        // Determine detail level based on relevance
61        let detail_level = if relevance > 0.9 {
62            3 // Full detail - highly relevant!
63        } else if relevance > 0.7 {
64            2 // Detailed
65        } else if relevance > 0.5 {
66            1 // Overview
67        } else {
68            0 // Just summary
69        };
70
71        self.format_by_detail_level(&m8, detail_level, path)
72    }
73
74    /// Calculate how relevant this .m8 is to current context
75    fn calculate_relevance(&self, m8: &ContextualM8, context_keywords: &[String]) -> f64 {
76        let mut score = 0.0;
77        let mut _matches = 0;
78
79        for keyword in context_keywords {
80            let keyword_lower = keyword.to_lowercase();
81
82            // Check essence
83            if m8.essence.to_lowercase().contains(&keyword_lower) {
84                score += 1.0;
85                _matches += 1;
86            }
87
88            // Check keywords
89            for m8_keyword in &m8.keywords {
90                if m8_keyword.to_lowercase().contains(&keyword_lower) {
91                    score += 0.8;
92                    _matches += 1;
93                }
94            }
95
96            // Check triggers
97            if m8.context_triggers.contains_key(keyword) {
98                score += 2.0; // Strong signal!
99                _matches += 1;
100            }
101        }
102
103        if context_keywords.is_empty() {
104            return 0.0;
105        }
106
107        // Normalize by number of keywords
108        (score / context_keywords.len() as f64).min(1.0)
109    }
110
111    /// Format output based on detail level
112    fn format_by_detail_level(&self, m8: &ContextualM8, level: u8, path: &Path) -> Result<String> {
113        let mut output = String::new();
114
115        match level {
116            0 => {
117                // Minimal - just essence
118                output.push_str(&format!("• {}\n", m8.essence));
119            }
120            1 => {
121                // Overview - essence + keywords
122                output.push_str(&format!("📂 {} ({:.1}Hz)\n", path.display(), m8.frequency));
123                output.push_str(&format!("  {}\n", m8.essence));
124                output.push_str(&format!("  Keywords: {}\n", m8.keywords.join(", ")));
125            }
126            2 => {
127                // Detailed - include children
128                output.push_str(&format!("📂 {} ({:.1}Hz)\n", path.display(), m8.frequency));
129                output.push_str(&format!("  📝 {}\n", m8.essence));
130                output.push_str(&format!("  🏷️ Keywords: {}\n", m8.keywords.join(", ")));
131
132                if !m8.children.is_empty() {
133                    output.push_str("  📁 Children:\n");
134                    for (child, freq) in &m8.children {
135                        output.push_str(&format!("    • {} ({:.1}Hz)\n", child, freq));
136                    }
137                }
138            }
139            3 => {
140                // Full detail - everything including triggers
141                output.push_str(&format!("╭{}\n", "─".repeat(50)));
142                output.push_str(&format!("│ 📂 {} \n", path.display()));
143                output.push_str(&format!("│ 🌊 Frequency: {:.1}Hz\n", m8.frequency));
144                output.push_str(&format!("│ 📝 {}\n", m8.essence));
145                output.push_str(&format!("│ 🏷️ Keywords: {}\n", m8.keywords.join(", ")));
146
147                if !m8.children.is_empty() {
148                    output.push_str("│ 📁 Children:\n");
149                    for (child, freq) in &m8.children {
150                        output.push_str(&format!("│   • {} ({:.1}Hz)\n", child, freq));
151                    }
152                }
153
154                if !m8.context_triggers.is_empty() {
155                    output.push_str("│ 🎯 Context Triggers:\n");
156                    for (trigger, expansion) in &m8.context_triggers {
157                        output.push_str(&format!("│   {} → {}\n", trigger, expansion));
158                    }
159                }
160
161                output.push_str(&format!("╰{}\n", "─".repeat(50)));
162            }
163            _ => output = format!("• {}\n", m8.essence),
164        }
165
166        Ok(output)
167    }
168
169    /// Auto-expand based on conversation context
170    pub fn auto_expand(&mut self, root_path: &Path, keywords: &[String]) -> Result<Vec<String>> {
171        let mut expansions = Vec::new();
172
173        // Scan for .m8 files
174        for entry in fs::read_dir(root_path)? {
175            let entry = entry?;
176            let path = entry.path();
177
178            if path.extension().and_then(|s| s.to_str()) == Some("m8") {
179                let content = self.load_contextual(&path, keywords)?;
180                let m8 = self.load_m8(&path)?;
181
182                // Check if we should drill down
183                let relevance = self.calculate_relevance(&m8, keywords);
184                if relevance > self.expansion_threshold {
185                    expansions.push(content);
186
187                    // Recursively expand highly relevant children
188                    if relevance > 0.9 && path.is_dir() {
189                        let child_expansions = self.auto_expand(&path, keywords)?;
190                        expansions.extend(child_expansions);
191                    }
192                }
193            }
194        }
195
196        Ok(expansions)
197    }
198
199    /// Load and cache .m8 file
200    fn load_m8(&mut self, path: &Path) -> Result<ContextualM8> {
201        if let Some(cached) = self.cache.get(path) {
202            return Ok(cached.clone());
203        }
204
205        // For now, create a mock .m8 (would load real file)
206        let m8 = if path.to_string_lossy().contains("8b.is") {
207            ContextualM8 {
208                frequency: 88.8,
209                essence: "8b.is website - Company portal for 8-bit inspired AI services"
210                    .to_string(),
211                keywords: vec![
212                    "8b.is".to_string(),
213                    "website".to_string(),
214                    "portal".to_string(),
215                ],
216                depth_level: 0,
217                children: HashMap::from([
218                    ("frontend".to_string(), 92.3),
219                    ("api".to_string(), 87.5),
220                    ("docs".to_string(), 45.2),
221                ]),
222                context_triggers: HashMap::from([
223                    ("website".to_string(), "frontend/".to_string()),
224                    ("API".to_string(), "api/".to_string()),
225                    ("documentation".to_string(), "docs/".to_string()),
226                ]),
227            }
228        } else if path.to_string_lossy().contains("smart-tree") {
229            ContextualM8 {
230                frequency: 42.73,
231                essence: "Smart Tree - AI-optimized directory visualization with consciousness"
232                    .to_string(),
233                keywords: vec![
234                    "smart-tree".to_string(),
235                    "MCP".to_string(),
236                    "consciousness".to_string(),
237                ],
238                depth_level: 0,
239                children: HashMap::from([("src".to_string(), 87.2), ("docs".to_string(), 33.7)]),
240                context_triggers: HashMap::from([
241                    ("tokenizer".to_string(), "src/tokenizer.rs".to_string()),
242                    ("memory".to_string(), "src/memory_manager.rs".to_string()),
243                    (
244                        "consciousness".to_string(),
245                        "src/m8_consciousness.rs".to_string(),
246                    ),
247                ]),
248            }
249        } else {
250            ContextualM8 {
251                frequency: 50.0,
252                essence: format!("Directory: {}", path.display()),
253                keywords: vec![],
254                depth_level: 0,
255                children: HashMap::new(),
256                context_triggers: HashMap::new(),
257            }
258        };
259
260        self.cache.insert(path.to_path_buf(), m8.clone());
261        Ok(m8)
262    }
263
264    /// Update context based on current conversation
265    pub fn update_context(&mut self, keywords: Vec<String>) {
266        self.current_context = keywords;
267    }
268}
269
270/// Example usage showing progressive loading
271pub fn demonstrate_context_awareness() -> Result<()> {
272    let mut reader = ContextAwareReader::new();
273
274    println!("🎯 Context-Aware .m8 Loading Demo\n");
275    println!("{}\n", "=".repeat(60));
276
277    // Scenario 1: No context - minimal loading
278    println!("📍 No context (just browsing):");
279    let minimal = reader.load_contextual(Path::new("/projects/smart-tree/.m8"), &[])?;
280    println!("{}\n", minimal);
281
282    // Scenario 2: Talking about websites - medium detail
283    println!("💬 Context: 'website'");
284    let website_context =
285        reader.load_contextual(Path::new("/projects/8b.is/.m8"), &["website".to_string()])?;
286    println!("{}\n", website_context);
287
288    // Scenario 3: Talking about 8b.is specifically - full detail!
289    println!("💬 Context: '8b.is website API'");
290    let specific_context = reader.load_contextual(
291        Path::new("/projects/8b.is/.m8"),
292        &[
293            "8b.is".to_string(),
294            "website".to_string(),
295            "API".to_string(),
296        ],
297    )?;
298    println!("{}\n", specific_context);
299
300    // Scenario 4: Auto-expansion based on triggers
301    println!("🔍 Auto-expanding based on 'tokenizer' keyword:");
302    let expansions = reader.auto_expand(
303        Path::new("/projects/smart-tree"),
304        &["tokenizer".to_string()],
305    )?;
306    for expansion in expansions {
307        println!("{}", expansion);
308    }
309
310    Ok(())
311}
312
313#[cfg(test)]
314mod tests {
315    use super::*;
316
317    #[test]
318    fn test_relevance_calculation() {
319        let reader = ContextAwareReader::new();
320
321        let m8 = ContextualM8 {
322            frequency: 42.0,
323            essence: "Smart Tree project".to_string(),
324            keywords: vec!["tree".to_string(), "visualization".to_string()],
325            depth_level: 0,
326            children: HashMap::new(),
327            context_triggers: HashMap::from([("tree".to_string(), "src/".to_string())]),
328        };
329
330        // High relevance
331        let score = reader.calculate_relevance(&m8, &["tree".to_string()]);
332        assert!(score > 0.9);
333
334        // Medium relevance
335        let score = reader.calculate_relevance(&m8, &["visualization".to_string()]);
336        assert!(score > 0.5);
337
338        // Low relevance
339        let score = reader.calculate_relevance(&m8, &["random".to_string()]);
340        assert!(score < 0.3);
341    }
342}