diff --git a/crates/vestige-mcp/src/tools/maintenance.rs b/crates/vestige-mcp/src/tools/maintenance.rs index fcd89d1..1ff3ab8 100644 --- a/crates/vestige-mcp/src/tools/maintenance.rs +++ b/crates/vestige-mcp/src/tools/maintenance.rs @@ -10,22 +10,12 @@ use std::sync::Arc; use tokio::sync::Mutex; use crate::cognitive::CognitiveEngine; -use vestige_core::advanced::compression::MemoryForCompression; -use vestige_core::{FSRSScheduler, MemoryLifecycle, MemoryState, Storage}; +use vestige_core::{FSRSScheduler, Storage}; // ============================================================================ // SCHEMAS // ============================================================================ -/// Deprecated in v1.7 — use system_status_schema() instead -#[allow(dead_code)] -pub fn health_check_schema() -> Value { - serde_json::json!({ - "type": "object", - "properties": {} - }) -} - pub fn consolidate_schema() -> Value { serde_json::json!({ "type": "object", @@ -33,15 +23,6 @@ pub fn consolidate_schema() -> Value { }) } -/// Deprecated in v1.7 — use system_status_schema() instead -#[allow(dead_code)] -pub fn stats_schema() -> Value { - serde_json::json!({ - "type": "object", - "properties": {} - }) -} - pub fn backup_schema() -> Value { serde_json::json!({ "type": "object", @@ -294,77 +275,6 @@ pub async fn execute_system_status( })) } -/// Health check tool — deprecated in v1.7, use execute_system_status() instead -#[allow(dead_code)] -pub async fn execute_health_check( - storage: &Arc, - _args: Option, -) -> Result { - let stats = storage.get_stats().map_err(|e| e.to_string())?; - - let status = if stats.total_nodes == 0 { - "empty" - } else if stats.average_retention < 0.3 { - "critical" - } else if stats.average_retention < 0.5 { - "degraded" - } else { - "healthy" - }; - - let embedding_coverage = if stats.total_nodes > 0 { - (stats.nodes_with_embeddings as f64 / stats.total_nodes as f64) * 100.0 - } else { - 0.0 - }; - - let embedding_ready = storage.is_embedding_ready(); - - let mut warnings = Vec::new(); - if stats.average_retention < 0.5 && stats.total_nodes > 0 { - warnings.push("Low average retention - consider running consolidation"); - } - if stats.nodes_due_for_review > 10 { - warnings.push("Many memories are due for review"); - } - if stats.total_nodes > 0 && stats.nodes_with_embeddings == 0 { - warnings.push("No embeddings generated - semantic search unavailable"); - } - if embedding_coverage < 50.0 && stats.total_nodes > 10 { - warnings.push("Low embedding coverage - run consolidate to improve semantic search"); - } - - let mut recommendations = Vec::new(); - if status == "critical" { - recommendations - .push("CRITICAL: Many memories have very low retention. Review important memories."); - } - if stats.nodes_due_for_review > 5 { - recommendations.push("Review due memories to strengthen retention."); - } - if stats.nodes_with_embeddings < stats.total_nodes { - recommendations.push("Run 'consolidate' to generate missing embeddings."); - } - if stats.total_nodes > 100 && stats.average_retention < 0.7 { - recommendations.push("Consider running periodic consolidation."); - } - if status == "healthy" && recommendations.is_empty() { - recommendations.push("Memory system is healthy!"); - } - - Ok(serde_json::json!({ - "tool": "health_check", - "status": status, - "totalMemories": stats.total_nodes, - "dueForReview": stats.nodes_due_for_review, - "averageRetention": stats.average_retention, - "embeddingCoverage": format!("{:.1}%", embedding_coverage), - "embeddingReady": embedding_ready, - "warnings": warnings, - "recommendations": recommendations, - })) -} - /// Consolidate tool pub async fn execute_consolidate( storage: &Arc, @@ -386,188 +296,6 @@ pub async fn execute_consolidate( })) } -/// Stats tool — deprecated in v1.7, use execute_system_status() instead -#[allow(dead_code)] -pub async fn execute_stats( - storage: &Arc, - cognitive: &Arc>, - _args: Option, -) -> Result { - let stats = storage.get_stats().map_err(|e| e.to_string())?; - - // Compute state distribution from a sample of nodes - let nodes = storage.get_all_nodes(500, 0).map_err(|e| e.to_string())?; - let total = nodes.len(); - let (active, dormant, silent, unavailable) = if total > 0 { - let mut a = 0usize; - let mut d = 0usize; - let mut s = 0usize; - let mut u = 0usize; - for node in &nodes { - let accessibility = node.retention_strength * 0.5 - + node.retrieval_strength * 0.3 - + node.storage_strength * 0.2; - if accessibility >= 0.7 { - a += 1; - } else if accessibility >= 0.4 { - d += 1; - } else if accessibility >= 0.1 { - s += 1; - } else { - u += 1; - } - } - (a, d, s, u) - } else { - (0, 0, 0, 0) - }; - - let embedding_coverage = if stats.total_nodes > 0 { - (stats.nodes_with_embeddings as f64 / stats.total_nodes as f64) * 100.0 - } else { - 0.0 - }; - - // ==================================================================== - // FSRS Preview: Show optimal intervals for a representative memory - // ==================================================================== - let scheduler = FSRSScheduler::default(); - let fsrs_preview = if let Some(representative) = nodes.first() { - let mut state = scheduler.new_card(); - state.difficulty = representative.difficulty; - state.stability = representative.stability; - state.reps = representative.reps; - state.lapses = representative.lapses; - state.last_review = representative.last_accessed; - let elapsed = scheduler.days_since_review(&state.last_review); - let preview = scheduler.preview_reviews(&state, elapsed); - Some(serde_json::json!({ - "representativeMemoryId": representative.id, - "elapsedDays": format!("{:.1}", elapsed), - "intervalIfGood": preview.good.interval, - "intervalIfEasy": preview.easy.interval, - "intervalIfHard": preview.hard.interval, - "currentRetrievability": format!("{:.3}", preview.good.retrievability), - })) - } else { - None - }; - - // ==================================================================== - // STATE SERVICE: Proper state transitions via Bjork model - // ==================================================================== - let state_distribution_precise = if let Ok(cog) = cognitive.try_lock() { - let mut lifecycles: Vec = nodes - .iter() - .take(100) // Sample 100 for performance - .map(|node| { - let mut lc = MemoryLifecycle::new(); - lc.last_access = node.last_accessed; - lc.access_count = node.reps as u32; - lc.state = if node.retention_strength > 0.7 { - MemoryState::Active - } else if node.retention_strength > 0.3 { - MemoryState::Dormant - } else if node.retention_strength > 0.1 { - MemoryState::Silent - } else { - MemoryState::Unavailable - }; - lc - }) - .collect(); - let batch_result = cog.state_service.batch_update(&mut lifecycles); - Some(serde_json::json!({ - "totalTransitions": batch_result.total_transitions, - "activeToDormant": batch_result.active_to_dormant, - "dormantToSilent": batch_result.dormant_to_silent, - "suppressionsResolved": batch_result.suppressions_resolved, - "sampled": lifecycles.len(), - })) - } else { - None - }; - - // ==================================================================== - // COMPRESSOR: Find compressible memory groups - // ==================================================================== - let compressible_groups = if let Ok(cog) = cognitive.try_lock() { - let memories_for_compression: Vec = nodes - .iter() - .filter(|n| n.retention_strength < 0.5) // Only consider low-retention memories - .take(50) // Cap for performance - .map(|n| MemoryForCompression { - id: n.id.clone(), - content: n.content.clone(), - tags: n.tags.clone(), - created_at: n.created_at, - last_accessed: Some(n.last_accessed), - embedding: None, - }) - .collect(); - if !memories_for_compression.is_empty() { - let groups = cog - .compressor - .find_compressible_groups(&memories_for_compression); - Some(serde_json::json!({ - "groupCount": groups.len(), - "totalCompressible": groups.iter().map(|g| g.len()).sum::(), - })) - } else { - None - } - } else { - None - }; - - // ==================================================================== - // COGNITIVE: Module health summary - // ==================================================================== - let cognitive_health = if let Ok(cog) = cognitive.try_lock() { - let activation_count = cog.activation_network.get_associations("_probe_").len(); - let prediction_accuracy = cog.predictive_memory.prediction_accuracy().unwrap_or(0.0); - let scheduler_stats = cog.consolidation_scheduler.get_activity_stats(); - Some(serde_json::json!({ - "activationNetworkSize": activation_count, - "predictionAccuracy": format!("{:.2}", prediction_accuracy), - "modulesActive": 28, - "schedulerStats": { - "totalEvents": scheduler_stats.total_events, - "eventsPerMinute": scheduler_stats.events_per_minute, - "isIdle": scheduler_stats.is_idle, - "timeUntilNextConsolidation": format!("{:?}", cog.consolidation_scheduler.time_until_next()), - }, - })) - } else { - None - }; - - Ok(serde_json::json!({ - "tool": "stats", - "totalMemories": stats.total_nodes, - "dueForReview": stats.nodes_due_for_review, - "averageRetention": stats.average_retention, - "averageStorageStrength": stats.average_storage_strength, - "averageRetrievalStrength": stats.average_retrieval_strength, - "withEmbeddings": stats.nodes_with_embeddings, - "embeddingCoverage": format!("{:.1}%", embedding_coverage), - "embeddingModel": stats.embedding_model, - "oldestMemory": stats.oldest_memory.map(|dt| dt.to_rfc3339()), - "newestMemory": stats.newest_memory.map(|dt| dt.to_rfc3339()), - "stateDistribution": { - "active": active, - "dormant": dormant, - "silent": silent, - "unavailable": unavailable, - "sampled": total, - }, - "fsrsPreview": fsrs_preview, - "cognitiveHealth": cognitive_health, - "stateTransitions": state_distribution_precise, - "compressibleMemories": compressible_groups, - })) -} - /// Backup tool pub async fn execute_backup(storage: &Arc, _args: Option) -> Result { // Determine backup path