use crate::episode::Episode;
use crate::types::TaskOutcome;
use super::helpers;
const MIN_STEPS_FOR_REFLECTION: usize = 2;
pub(super) fn generate_insights(episode: &Episode, max_items: usize) -> Vec<String> {
let mut insights = Vec::new();
if episode.steps.len() < MIN_STEPS_FOR_REFLECTION {
return insights;
}
if let Some(pattern_insight) = analyze_step_patterns(episode) {
insights.push(pattern_insight);
}
if let Some(recovery_insight) = identify_error_recovery_pattern(episode) {
insights.push(recovery_insight);
}
let context_insight = format!(
"Task in {} domain with {:?} complexity",
episode.context.domain, episode.context.complexity
);
insights.push(context_insight);
let unique_tools = helpers::count_unique_tools(episode);
if unique_tools > 5 {
insights.push(format!(
"Task required diverse toolset ({unique_tools} different tools)"
));
} else if unique_tools == 1 && episode.steps.len() > 3 {
insights.push("Task accomplished with single tool - potential for automation".to_string());
}
if let Some(avg_latency) = helpers::calculate_average_latency(episode) {
if avg_latency > 5000 {
insights.push(format!(
"High average step latency: {avg_latency}ms - consider optimization"
));
}
}
insights.truncate(max_items);
insights
}
pub(super) fn generate_contextual_insights(episode: &Episode) -> Vec<String> {
let mut insights = Vec::new();
if let Some(complexity_insight) = analyze_complexity_alignment(episode) {
insights.push(complexity_insight);
}
if let Some(learning_insight) = analyze_learning_indicators(episode) {
insights.push(learning_insight);
}
if let Some(strategy_insight) = analyze_strategy_effectiveness(episode) {
insights.push(strategy_insight);
}
if let Some(recommendation) = generate_recommendations_for_similar_tasks(episode) {
insights.push(recommendation);
}
insights
}
fn analyze_step_patterns(episode: &Episode) -> Option<String> {
let total_steps = episode.steps.len();
let successful_steps = episode.successful_steps_count();
if total_steps == 0 {
return None;
}
let success_rate = successful_steps as f32 / total_steps as f32;
if success_rate == 1.0 {
Some("All steps executed successfully - reliable execution pattern".to_string())
} else if success_rate >= 0.8 {
Some(format!(
"High reliability pattern with {:.0}% step success rate",
success_rate * 100.0
))
} else if success_rate < 0.5 {
Some(format!(
"Low reliability pattern ({:.0}% success) - review approach",
success_rate * 100.0
))
} else {
None
}
}
fn identify_error_recovery_pattern(episode: &Episode) -> Option<String> {
for i in 0..episode.steps.len().saturating_sub(1) {
let current = &episode.steps[i];
let next = &episode.steps[i + 1];
if !current.is_success() && next.is_success() {
return Some(format!(
"Successfully recovered from error using '{}'",
next.tool
));
}
}
None
}
fn analyze_complexity_alignment(episode: &Episode) -> Option<String> {
let step_count = episode.steps.len();
let complexity = &episode.context.complexity;
let expected_steps = match complexity {
crate::types::ComplexityLevel::Simple => 5,
crate::types::ComplexityLevel::Moderate => 15,
crate::types::ComplexityLevel::Complex => 30,
};
if step_count < expected_steps / 2 {
Some(format!(
"Task complexity ({complexity:?}) handled more efficiently than expected ({step_count} vs ~{expected_steps} steps)"
))
} else if step_count > expected_steps * 2 {
Some(format!(
"Task required more steps than typical for {complexity:?} complexity - may need approach refinement"
))
} else {
None
}
}
fn analyze_learning_indicators(episode: &Episode) -> Option<String> {
let pattern_count = episode.patterns.len();
if pattern_count >= 3 {
Some(format!(
"Strong learning episode: discovered {pattern_count} reusable patterns for future tasks"
))
} else if pattern_count > 0 && episode.successful_steps_count() > 0 {
Some(format!(
"Learning opportunity: {pattern_count} pattern(s) identified - build on this for similar tasks"
))
} else if helpers::detect_error_recovery(episode) {
Some(
"Valuable learning from error recovery - demonstrates adaptability and problem-solving"
.to_string(),
)
} else {
None
}
}
fn analyze_strategy_effectiveness(episode: &Episode) -> Option<String> {
if episode.steps.is_empty() {
return None;
}
let success_rate = episode.successful_steps_count() as f32 / episode.steps.len() as f32;
let duration = episode.duration()?;
if success_rate > 0.8 && duration.num_seconds() < 120 {
Some(
"Highly effective strategy: high success rate with quick execution - replicate for similar tasks"
.to_string(),
)
} else if success_rate < 0.5 {
Some(format!(
"Strategy needs refinement: {:.0}% success rate indicates need for different approach",
success_rate * 100.0
))
} else {
None
}
}
fn generate_recommendations_for_similar_tasks(episode: &Episode) -> Option<String> {
if let Some(TaskOutcome::Success { .. }) = &episode.outcome {
let key_tools: Vec<_> = episode
.steps
.iter()
.filter(|s| s.is_success())
.map(|s| s.tool.as_str())
.collect::<std::collections::HashSet<_>>()
.into_iter()
.take(3)
.collect();
if key_tools.is_empty() {
None
} else {
Some(format!(
"For similar {} tasks in {}, prioritize: {}",
episode.context.domain,
episode
.context
.language
.as_deref()
.unwrap_or("any language"),
key_tools.join(", ")
))
}
} else {
None
}
}