pub mod analyzer;
pub mod background_review;
pub mod curator;
pub mod evolution;
pub mod generator;
pub mod r#loop;
pub mod store;
pub mod trajectory;
pub use analyzer::Analyzer;
pub use background_review::{BackgroundReviewConfig, BackgroundReviewer, ReviewOutcome};
pub use curator::{Curator, CuratorConfig, CuratorState, CuratorStatus, SkillLifecycle};
pub use evolution::SelfEvolution;
pub use generator::PromptGenerator;
pub use r#loop::{ImprovementLoop, LoopResult};
pub use store::CritiqueStore;
pub use trajectory::{TrajectoryEntry, TrajectorySaver, TrajectoryStats};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CritiqueIssue {
WriteWithoutRead { tool: String, count: usize },
ExcessiveRetries { tool: String, count: usize },
ToolErrorPattern { tool: String, message: String },
ContextOverflow {
tokens_before: usize,
tokens_after: usize,
},
MissingTool { needed: String },
ExcessiveToolCalls { total: usize },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ImprovementSuggestion {
PromptChange {
section: String,
suggestion: String,
},
PolicyChange {
rule: String,
reason: String,
},
EvalGeneration {
case_id: String,
json: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunCritique {
pub run_id: String,
pub success: bool,
pub score: f64,
pub issues: Vec<CritiqueIssue>,
pub suggestions: Vec<ImprovementSuggestion>,
}
impl RunCritique {
pub fn new(run_id: &str, success: bool) -> Self {
Self {
run_id: run_id.to_string(),
success,
score: if success { 1.0 } else { 0.0 },
issues: Vec::new(),
suggestions: Vec::new(),
}
}
pub fn with_issue(mut self, issue: CritiqueIssue) -> Self {
self.issues.push(issue);
self
}
pub fn with_suggestion(mut self, suggestion: ImprovementSuggestion) -> Self {
self.suggestions.push(suggestion);
self
}
pub fn format_report(&self) -> String {
let mut lines = vec![
format!("Run: {}", self.run_id),
format!("Success: {} (score: {:.2})", self.success, self.score),
String::new(),
];
if !self.issues.is_empty() {
lines.push("Issues Found:".into());
for issue in &self.issues {
lines.push(match issue {
CritiqueIssue::WriteWithoutRead { tool, count } => {
format!(" - Write without read: {tool} was called {count} time(s) without prior read_file")
}
CritiqueIssue::ExcessiveRetries { tool, count } => {
format!(" - Excessive retries: {tool} was retried {count} time(s)")
}
CritiqueIssue::ToolErrorPattern { tool, message } => {
format!(" - Tool error: {tool} — {message}")
}
CritiqueIssue::ContextOverflow { tokens_before, tokens_after } => {
format!(" - Context overflow: compressed from {tokens_before} to {tokens_after} tokens")
}
CritiqueIssue::MissingTool { needed } => {
format!(" - Missing tool: {needed} might have helped")
}
CritiqueIssue::ExcessiveToolCalls { total } => {
format!(" - Excessive tool calls: {total} total")
}
});
}
lines.push(String::new());
}
if !self.suggestions.is_empty() {
lines.push("Suggestions:".into());
for suggestion in &self.suggestions {
match suggestion {
ImprovementSuggestion::PromptChange {
section,
suggestion,
} => {
lines.push(format!(" [Prompt] {section}: {suggestion}"));
}
ImprovementSuggestion::PolicyChange { rule, reason } => {
lines.push(format!(" [Policy] {rule} — Reason: {reason}"));
}
ImprovementSuggestion::EvalGeneration { case_id, .. } => {
lines.push(format!(" [Eval] Generate case: {case_id}"));
}
}
}
}
if self.issues.is_empty() && self.suggestions.is_empty() {
lines.push("No issues or suggestions. The run looks clean.".into());
}
lines.join("\n")
}
}