Skip to main content

agentic_evolve_mcp/
session.rs

1//! Session management — wraps all core state for the MCP server.
2
3use std::collections::HashMap;
4use std::path::Path;
5
6use agentic_evolve_core::collective::{
7    DecayManager, PromotionEngine, SuccessTracker, UsageTracker,
8};
9use agentic_evolve_core::composition::PatternComposer;
10use agentic_evolve_core::crystallization::PatternExtractor;
11use agentic_evolve_core::matching::CompositeMatcher;
12use agentic_evolve_core::optimization::{CacheManager, PatternOptimizer};
13use agentic_evolve_core::storage::{PatternIndex, PatternStore, PatternVersioner};
14use agentic_evolve_core::types::match_result::{MatchContext, MatchResult};
15use agentic_evolve_core::types::pattern::{FunctionSignature, Language, Pattern, PatternVariable};
16use agentic_evolve_core::types::skill::SuccessfulExecution;
17use agentic_evolve_core::EvolveResult;
18
19/// SessionManager wraps all core state for the MCP server.
20pub struct SessionManager {
21    store: PatternStore,
22    index: PatternIndex,
23    versioner: PatternVersioner,
24    matcher: CompositeMatcher,
25    extractor: PatternExtractor,
26    composer: PatternComposer,
27    usage_tracker: UsageTracker,
28    success_tracker: SuccessTracker,
29    decay_manager: DecayManager,
30    promotion_engine: PromotionEngine,
31    optimizer: PatternOptimizer,
32    cache: CacheManager,
33}
34
35impl SessionManager {
36    /// Create a new session manager with optional persistent data directory.
37    pub fn new(data_dir: &str) -> EvolveResult<Self> {
38        let path = Path::new(data_dir);
39        let store = PatternStore::with_data_dir(path)?;
40
41        let mut index = PatternIndex::new();
42        for pattern in store.list() {
43            index.add(pattern);
44        }
45
46        Ok(Self {
47            store,
48            index,
49            versioner: PatternVersioner::new(),
50            matcher: CompositeMatcher::new(),
51            extractor: PatternExtractor::new(),
52            composer: PatternComposer::new(),
53            usage_tracker: UsageTracker::new(),
54            success_tracker: SuccessTracker::new(),
55            decay_manager: DecayManager::default(),
56            promotion_engine: PromotionEngine::default(),
57            optimizer: PatternOptimizer::new(),
58            cache: CacheManager::default(),
59        })
60    }
61
62    // --- Storage operations ---
63
64    /// Store a new pattern.
65    #[allow(clippy::too_many_arguments)]
66    pub fn store_pattern(
67        &mut self,
68        name: &str,
69        domain: &str,
70        language: Language,
71        signature: FunctionSignature,
72        template: &str,
73        variables: Vec<PatternVariable>,
74        confidence: f64,
75        tags: Vec<String>,
76    ) -> EvolveResult<Pattern> {
77        let mut pattern = Pattern::new(
78            name, domain, language, signature, template, variables, confidence,
79        );
80        pattern.tags = tags;
81        self.store.save(&pattern)?;
82        self.index.add(&pattern);
83        self.versioner
84            .record_version(&pattern, "Initial creation")?;
85        Ok(pattern)
86    }
87
88    /// Get a pattern by ID.
89    pub fn get_pattern(&self, id: &str) -> EvolveResult<&Pattern> {
90        self.store.get(id)
91    }
92
93    /// Search patterns by query.
94    pub fn search_patterns(&self, query: &str) -> Vec<&Pattern> {
95        self.store.search(query)
96    }
97
98    /// List all patterns.
99    pub fn list_patterns(&self) -> Vec<&Pattern> {
100        self.store.list()
101    }
102
103    /// Delete a pattern by ID.
104    pub fn delete_pattern(&mut self, id: &str) -> EvolveResult<Pattern> {
105        let pattern = self.store.delete(id)?;
106        self.index.remove(&pattern);
107        self.cache.invalidate_pattern(id);
108        Ok(pattern)
109    }
110
111    // --- Matching operations ---
112
113    /// Match a function signature against stored patterns.
114    pub fn match_signature(
115        &self,
116        signature: &FunctionSignature,
117        context: &MatchContext,
118        limit: usize,
119    ) -> EvolveResult<Vec<MatchResult>> {
120        let patterns: Vec<&Pattern> = self.store.list();
121        self.matcher
122            .find_matches(signature, &patterns, context, limit)
123    }
124
125    /// Match patterns with surrounding context.
126    pub fn match_context(
127        &self,
128        signature: &FunctionSignature,
129        context: &MatchContext,
130        limit: usize,
131    ) -> EvolveResult<Vec<MatchResult>> {
132        let patterns: Vec<&Pattern> = self.store.list();
133        self.matcher
134            .find_matches(signature, &patterns, context, limit)
135    }
136
137    // --- Crystallization ---
138
139    /// Crystallize successful code into patterns.
140    pub fn crystallize(&mut self, execution: &SuccessfulExecution) -> EvolveResult<Vec<Pattern>> {
141        let patterns = self.extractor.extract(execution)?;
142        let mut stored = Vec::new();
143        for pattern in patterns {
144            self.store.save(&pattern)?;
145            self.index.add(&pattern);
146            self.versioner
147                .record_version(&pattern, "Crystallized from successful execution")?;
148            stored.push(pattern);
149        }
150        Ok(stored)
151    }
152
153    // --- Composition ---
154
155    /// Compose multiple patterns together.
156    pub fn compose(
157        &self,
158        pattern_ids: &[String],
159        bindings: &HashMap<String, String>,
160    ) -> EvolveResult<agentic_evolve_core::composition::composer::CompositionResult> {
161        let mut patterns = Vec::new();
162        for id in pattern_ids {
163            patterns.push(self.store.get(id)?);
164        }
165        self.composer.compose(&patterns, bindings, None)
166    }
167
168    // --- Coverage ---
169
170    /// Get pattern coverage for a set of function signatures.
171    pub fn coverage(&self, signatures: &[FunctionSignature], threshold: f64) -> CoverageReport {
172        let all_patterns: Vec<&Pattern> = self.store.list();
173        let context = MatchContext::new();
174        let mut matched = 0;
175        let mut details = Vec::new();
176
177        for sig in signatures {
178            let results = self.matcher.find_matches(sig, &all_patterns, &context, 1);
179            let best_score = results
180                .as_ref()
181                .ok()
182                .and_then(|r| r.first())
183                .map(|r| r.score.combined)
184                .unwrap_or(0.0);
185            let covered = best_score >= threshold;
186            if covered {
187                matched += 1;
188            }
189            details.push(CoverageDetail {
190                function_name: sig.name.clone(),
191                best_match_score: best_score,
192                covered,
193            });
194        }
195
196        let total = signatures.len();
197        CoverageReport {
198            total,
199            covered: matched,
200            coverage: if total == 0 {
201                1.0
202            } else {
203                matched as f64 / total as f64
204            },
205            details,
206        }
207    }
208
209    // --- Confidence ---
210
211    /// Get confidence score for a pattern.
212    pub fn confidence(&self, pattern_id: &str) -> EvolveResult<ConfidenceReport> {
213        let pattern = self.store.get(pattern_id)?;
214        let usage_rate = self.usage_tracker.success_rate(pattern_id);
215        let success_rate = self.success_tracker.success_rate(pattern_id);
216        let promotion = self.promotion_engine.evaluate(pattern);
217
218        Ok(ConfidenceReport {
219            pattern_id: pattern_id.to_string(),
220            base_confidence: pattern.confidence,
221            usage_success_rate: usage_rate,
222            tracker_success_rate: success_rate,
223            promotion_decision: format!("{promotion:?}"),
224            usage_count: pattern.usage_count,
225            success_count: pattern.success_count,
226        })
227    }
228
229    // --- Usage tracking ---
230
231    /// Update usage statistics for a pattern.
232    pub fn update_usage(
233        &mut self,
234        pattern_id: &str,
235        domain: &str,
236        success: bool,
237    ) -> EvolveResult<()> {
238        let pattern = self.store.get_mut(pattern_id)?;
239        pattern.record_use(success);
240        self.decay_manager.apply_usage_boost(pattern, success);
241
242        // Persist updates
243        let pattern_clone = pattern.clone();
244        self.store.save(&pattern_clone)?;
245
246        self.usage_tracker.record_use(pattern_id, domain, success);
247        self.success_tracker.record(pattern_id, success);
248        self.cache.invalidate_pattern(pattern_id);
249        Ok(())
250    }
251
252    // --- Optimization ---
253
254    /// Optimize pattern storage.
255    pub fn optimize(&mut self) -> EvolveResult<OptimizationSummary> {
256        let patterns: Vec<&Pattern> = self.store.list();
257        let report = self.optimizer.optimize_report(&patterns);
258        let decay_report = self.decay_manager.decay_report(&patterns);
259
260        // Apply decay to all patterns
261        let ids: Vec<String> = self
262            .store
263            .list()
264            .iter()
265            .map(|p| p.id.as_str().to_string())
266            .collect();
267        let mut decayed = 0;
268        for id in &ids {
269            if let Ok(pattern) = self.store.get_mut(id) {
270                let old = pattern.confidence;
271                self.decay_manager.apply_decay(pattern);
272                if (old - pattern.confidence).abs() > f64::EPSILON {
273                    decayed += 1;
274                }
275            }
276        }
277
278        // Apply promotions
279        let mut promoted = 0;
280        let mut demoted = 0;
281        for id in &ids {
282            if let Ok(pattern) = self.store.get_mut(id) {
283                let decision = self.promotion_engine.apply_promotion(pattern);
284                match decision {
285                    agentic_evolve_core::collective::promotion::PromotionDecision::Promote => {
286                        promoted += 1
287                    }
288                    agentic_evolve_core::collective::promotion::PromotionDecision::Demote => {
289                        demoted += 1
290                    }
291                    _ => {}
292                }
293            }
294        }
295
296        self.cache.clear();
297
298        Ok(OptimizationSummary {
299            patterns_total: report.patterns_before,
300            duplicates_found: report.duplicates_removed,
301            prunable: report.pruned,
302            decay_healthy: decay_report.healthy,
303            decay_decaying: decay_report.decaying,
304            decay_critical: decay_report.critical,
305            patterns_decayed: decayed,
306            patterns_promoted: promoted,
307            patterns_demoted: demoted,
308            cache_cleared: true,
309        })
310    }
311
312    /// Get the function body from the best matching pattern.
313    pub fn get_body(
314        &self,
315        signature: &FunctionSignature,
316        context: &MatchContext,
317    ) -> EvolveResult<Option<(String, String, f64)>> {
318        let patterns: Vec<&Pattern> = self.store.list();
319        let results = self
320            .matcher
321            .find_matches(signature, &patterns, context, 1)?;
322        match results.into_iter().next() {
323            Some(result) => Ok(Some((
324                result.pattern.template.clone(),
325                result.pattern_id.as_str().to_string(),
326                result.score.combined,
327            ))),
328            None => Ok(None),
329        }
330    }
331
332    /// Total pattern count.
333    pub fn pattern_count(&self) -> usize {
334        self.store.count()
335    }
336}
337
338/// Coverage report for a set of function signatures.
339#[derive(Debug, Clone, serde::Serialize)]
340pub struct CoverageReport {
341    pub total: usize,
342    pub covered: usize,
343    pub coverage: f64,
344    pub details: Vec<CoverageDetail>,
345}
346
347/// Coverage detail for a single function.
348#[derive(Debug, Clone, serde::Serialize)]
349pub struct CoverageDetail {
350    pub function_name: String,
351    pub best_match_score: f64,
352    pub covered: bool,
353}
354
355/// Confidence report for a pattern.
356#[derive(Debug, Clone, serde::Serialize)]
357pub struct ConfidenceReport {
358    pub pattern_id: String,
359    pub base_confidence: f64,
360    pub usage_success_rate: f64,
361    pub tracker_success_rate: f64,
362    pub promotion_decision: String,
363    pub usage_count: u64,
364    pub success_count: u64,
365}
366
367/// Optimization summary.
368#[derive(Debug, Clone, serde::Serialize)]
369pub struct OptimizationSummary {
370    pub patterns_total: usize,
371    pub duplicates_found: usize,
372    pub prunable: usize,
373    pub decay_healthy: usize,
374    pub decay_decaying: usize,
375    pub decay_critical: usize,
376    pub patterns_decayed: usize,
377    pub patterns_promoted: usize,
378    pub patterns_demoted: usize,
379    pub cache_cleared: bool,
380}