1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Heuristic retrieval implementation
use crate::types::TaskContext;
use tracing::{debug, info, instrument};
use super::super::SelfLearningMemory;
impl SelfLearningMemory {
/// Retrieve relevant heuristics for a given task context
///
/// Finds heuristics that match the given context and ranks them
/// by confidence weighted by relevance score.
///
/// # Algorithm
///
/// 1. Query heuristics from in-memory fallback
/// 2. Calculate relevance score based on context similarity:
/// - Domain exact match: +1.0
/// - Language exact match: +0.8
/// - Framework match: +0.5
/// - Tag overlap: +0.3 per matching tag
/// 3. Rank by: confidence × `relevance_score`
/// 4. Return top N heuristics sorted by score DESC
///
/// # Arguments
///
/// * `context` - Task context to match against
/// * `limit` - Maximum number of heuristics to return
///
/// # Returns
///
/// Vector of relevant heuristics, sorted by relevance and confidence
///
/// # Examples
///
/// ```
/// use do_memory_core::{SelfLearningMemory, TaskContext, ComplexityLevel};
///
/// # async fn example() {
/// let memory = SelfLearningMemory::new();
///
/// let context = TaskContext {
/// language: Some("rust".to_string()),
/// framework: Some("tokio".to_string()),
/// complexity: ComplexityLevel::Moderate,
/// domain: "async-processing".to_string(),
/// tags: vec!["concurrency".to_string()],
/// };
///
/// // Retrieve top 5 relevant heuristics
/// let heuristics = memory.retrieve_relevant_heuristics(&context, 5).await;
///
/// for heuristic in heuristics {
/// println!("Condition: {}", heuristic.condition);
/// println!("Action: {}", heuristic.action);
/// println!("Confidence: {}", heuristic.confidence);
/// }
/// # }
/// ```
#[instrument(skip(self))]
pub async fn retrieve_relevant_heuristics(
&self,
context: &TaskContext,
limit: usize,
) -> Vec<crate::patterns::Heuristic> {
let heuristics = self.heuristics_fallback.read().await;
debug!(
total_heuristics = heuristics.len(),
limit = limit,
"Retrieving relevant heuristics"
);
// Pre-calculate lowercased values for optimization
let domain_lower = context.domain.to_lowercase();
let language_lower = context.language.as_ref().map(|l| l.to_lowercase());
let framework_lower = context.framework.as_ref().map(|f| f.to_lowercase());
let tags_lower: Vec<String> = context.tags.iter().map(|t| t.to_lowercase()).collect();
// Calculate weighted score for each heuristic
let mut scored_heuristics: Vec<_> = heuristics
.values()
.map(|h| {
let relevance = self.calculate_heuristic_relevance(
h,
&domain_lower,
language_lower.as_deref(),
framework_lower.as_deref(),
&tags_lower,
);
let weighted_score = h.confidence * relevance;
(h.clone(), weighted_score)
})
.filter(|(_, score)| *score > 0.0) // Only include relevant heuristics
.collect();
// Sort by weighted score (descending)
// Optimization: Use sort_unstable_by for search results
scored_heuristics
.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
// Limit results
let result: Vec<_> = scored_heuristics
.into_iter()
.take(limit)
.map(|(h, _)| h)
.collect();
info!(
retrieved_count = result.len(),
"Retrieved relevant heuristics"
);
result
}
}