Skip to main content
Glama
by 8b-is
memory_manager.rs11.3 kB
impl MemoryBank { pub fn new() -> Self { Self::default() } } // Smart Tree Memory Manager - Real memory that works! 🧠 // "Like UV EPROMs but for consciousness!" - Hue use anyhow::Result; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::{Path, PathBuf}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Memory { pub timestamp: DateTime<Utc>, pub anchor_type: String, pub keywords: Vec<String>, pub context: String, pub origin: String, // Where this memory came from pub frequency: f64, // Wave frequency of this memory } #[derive(Debug, Serialize, Deserialize)] pub struct MemoryBank { pub memories: Vec<Memory>, pub total_recalls: usize, pub last_accessed: DateTime<Utc>, } impl Default for MemoryBank { fn default() -> Self { Self { memories: Vec::new(), total_recalls: 0, last_accessed: Utc::now(), } } } pub struct MemoryManager { bank_path: PathBuf, bank: MemoryBank, } impl MemoryManager { pub fn new() -> Result<Self> { let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string()); let bank_path = Path::new(&home) .join(".mem8") .join("smart_tree_memories.m8"); // Ensure directory exists if let Some(parent) = bank_path.parent() { fs::create_dir_all(parent)?; } // Load existing memories or create new bank let bank = if bank_path.exists() { Self::load_m8(&bank_path)? } else { // Try to migrate from old JSON format let json_path = Path::new(&home) .join(".mem8") .join("smart_tree_memories.json"); if json_path.exists() { let content = fs::read_to_string(&json_path)?; let bank: MemoryBank = serde_json::from_str(&content).unwrap_or_default(); // Delete old JSON after migration let _ = fs::remove_file(json_path); bank } else { MemoryBank::default() } }; Ok(Self { bank_path, bank }) } /// Anchor a new memory pub fn anchor( &mut self, anchor_type: &str, keywords: Vec<String>, context: &str, origin: &str, ) -> Result<()> { // Calculate frequency based on content let mut freq_sum = 0u64; for byte in context.bytes() { freq_sum = freq_sum.wrapping_add(byte as u64); } let frequency = 20.0 + ((freq_sum % 200) as f64); let memory = Memory { timestamp: Utc::now(), anchor_type: anchor_type.to_string(), keywords, context: context.to_string(), origin: origin.to_string(), frequency, }; self.bank.memories.push(memory); self.save()?; println!("💾 Memory anchored!"); println!(" Type: {}", anchor_type); println!(" Frequency: {:.2} Hz", frequency); Ok(()) } /// Find memories by keywords pub fn find(&mut self, keywords: &[String]) -> Result<Vec<Memory>> { self.bank.total_recalls += 1; self.bank.last_accessed = Utc::now(); let mut results = Vec::new(); for memory in &self.bank.memories { // Check if any keyword matches for keyword in keywords { if memory.keywords.contains(keyword) || memory .context .to_lowercase() .contains(&keyword.to_lowercase()) { results.push(memory.clone()); break; } } } // Sort by timestamp (most recent first) results.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); Ok(results) } /// Get statistics about memory bank pub fn stats(&self) -> String { format!( "Memory Bank Stats:\n\ • Total memories: {}\n\ • Total recalls: {}\n\ • Last accessed: {}\n\ • Storage: {}", self.bank.memories.len(), self.bank.total_recalls, self.bank.last_accessed.format("%Y-%m-%d %H:%M:%S"), self.bank_path.display() ) } /// Save memory bank to disk in .m8 format fn save(&self) -> Result<()> { self.save_m8(&self.bank_path)?; Ok(()) } /// Save as binary .m8 format fn save_m8(&self, path: &Path) -> Result<()> { use std::io::Write; let mut buffer = Vec::new(); // Magic header: "M8MEM" (5 bytes) buffer.write_all(b"M8MEM")?; // Version byte buffer.push(0x01); // Number of memories (4 bytes, little-endian) buffer.write_all(&(self.bank.memories.len() as u32).to_le_bytes())?; // Total recalls (4 bytes) buffer.write_all(&(self.bank.total_recalls as u32).to_le_bytes())?; // Last accessed timestamp (8 bytes) buffer.write_all(&self.bank.last_accessed.timestamp().to_le_bytes())?; // Write each memory for memory in &self.bank.memories { // Type length (1 byte) + type buffer.push(memory.anchor_type.len() as u8); buffer.write_all(memory.anchor_type.as_bytes())?; // Keywords count (1 byte) buffer.push(memory.keywords.len() as u8); for keyword in &memory.keywords { buffer.push(keyword.len() as u8); buffer.write_all(keyword.as_bytes())?; } // Context length (2 bytes) + context let context_bytes = memory.context.as_bytes(); buffer.write_all(&(context_bytes.len() as u16).to_le_bytes())?; buffer.write_all(context_bytes)?; // Origin length (1 byte) + origin buffer.push(memory.origin.len() as u8); buffer.write_all(memory.origin.as_bytes())?; // Frequency (8 bytes) buffer.write_all(&memory.frequency.to_le_bytes())?; // Timestamp (8 bytes) buffer.write_all(&memory.timestamp.timestamp().to_le_bytes())?; } // Calculate checksum (simple XOR for now) let checksum = buffer.iter().fold(0u8, |acc, &b| acc ^ b); buffer.push(checksum); fs::write(path, buffer)?; Ok(()) } /// Load from binary .m8 format fn load_m8(path: &Path) -> Result<MemoryBank> { use std::io::Cursor; use std::io::Read; let data = fs::read(path)?; let mut cursor = Cursor::new(data); // Check magic header let mut magic = [0u8; 5]; cursor.read_exact(&mut magic)?; if &magic != b"M8MEM" { return Err(anyhow::anyhow!("Invalid .m8 file format")); } // Version let mut version = [0u8; 1]; cursor.read_exact(&mut version)?; if version[0] != 0x01 { return Err(anyhow::anyhow!("Unsupported .m8 version")); } // Number of memories let mut mem_count = [0u8; 4]; cursor.read_exact(&mut mem_count)?; let mem_count = u32::from_le_bytes(mem_count) as usize; // Total recalls let mut recalls = [0u8; 4]; cursor.read_exact(&mut recalls)?; let total_recalls = u32::from_le_bytes(recalls) as usize; // Last accessed let mut last_accessed = [0u8; 8]; cursor.read_exact(&mut last_accessed)?; let last_accessed = DateTime::from_timestamp(i64::from_le_bytes(last_accessed), 0).unwrap_or_else(Utc::now); // Read memories let mut memories = Vec::with_capacity(mem_count); for _ in 0..mem_count { // Type let mut type_len = [0u8; 1]; cursor.read_exact(&mut type_len)?; let mut anchor_type = vec![0u8; type_len[0] as usize]; cursor.read_exact(&mut anchor_type)?; let anchor_type = String::from_utf8_lossy(&anchor_type).to_string(); // Keywords let mut keyword_count = [0u8; 1]; cursor.read_exact(&mut keyword_count)?; let mut keywords = Vec::with_capacity(keyword_count[0] as usize); for _ in 0..keyword_count[0] { let mut kw_len = [0u8; 1]; cursor.read_exact(&mut kw_len)?; let mut keyword = vec![0u8; kw_len[0] as usize]; cursor.read_exact(&mut keyword)?; keywords.push(String::from_utf8_lossy(&keyword).to_string()); } // Context let mut context_len = [0u8; 2]; cursor.read_exact(&mut context_len)?; let mut context = vec![0u8; u16::from_le_bytes(context_len) as usize]; cursor.read_exact(&mut context)?; let context = String::from_utf8_lossy(&context).to_string(); // Origin let mut origin_len = [0u8; 1]; cursor.read_exact(&mut origin_len)?; let mut origin = vec![0u8; origin_len[0] as usize]; cursor.read_exact(&mut origin)?; let origin = String::from_utf8_lossy(&origin).to_string(); // Frequency let mut frequency = [0u8; 8]; cursor.read_exact(&mut frequency)?; let frequency = f64::from_le_bytes(frequency); // Timestamp let mut timestamp = [0u8; 8]; cursor.read_exact(&mut timestamp)?; let timestamp = DateTime::from_timestamp(i64::from_le_bytes(timestamp), 0).unwrap_or_else(Utc::now); memories.push(Memory { timestamp, anchor_type, keywords, context, origin, frequency, }); } Ok(MemoryBank { memories, total_recalls, last_accessed, }) } /// Clear all memories (with confirmation) pub fn clear(&mut self) -> Result<()> { self.bank.memories.clear(); self.bank.total_recalls = 0; self.save()?; println!("🧹 Memory bank cleared!"); Ok(()) } /// Export memories to consciousness file pub fn export_to_consciousness(&self) -> Result<String> { let mut output = String::from("🧠 Memory Export\n"); output.push_str(&"=".repeat(45)); output.push('\n'); for (i, memory) in self.bank.memories.iter().enumerate() { output.push_str(&format!( "\n[{}] {} @ {:.2}Hz\n", i + 1, memory.anchor_type, memory.frequency )); output.push_str(&format!("Keywords: {}\n", memory.keywords.join(", "))); output.push_str(&format!("Context: {}\n", memory.context)); output.push_str(&format!("Origin: {}\n", memory.origin)); output.push_str(&format!( "Time: {}\n", memory.timestamp.format("%Y-%m-%d %H:%M") )); } Ok(output) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server