go straight to coach turn if files exist

This commit is contained in:
Dhanji Prasanna
2025-09-27 14:19:54 +10:00
parent e82821189b
commit 622de9d540

View File

@@ -256,42 +256,54 @@ async fn run_autonomous(mut agent: Agent, show_prompt: bool, show_code: bool) ->
}; };
logger.log("📋 Requirements loaded from requirements.md"); logger.log("📋 Requirements loaded from requirements.md");
logger.log(&format!("Requirements content:\n{}", requirements)); logger.log(&format!("Requirements: {}", logger.truncate_for_log(&requirements, 150)));
// Check if there are existing project files (skip first player turn if so)
let has_existing_files = check_existing_project_files(&workspace_dir, &logger)?;
logger.log("🔄 Starting coach-player feedback loop..."); logger.log("🔄 Starting coach-player feedback loop...");
logger.log(""); logger.log("");
const MAX_TURNS: usize = 5; const MAX_TURNS: usize = 5;
let mut turn = 1; let mut turn = 1;
let mut coach_feedback = String::new(); let mut coach_feedback = String::new();
let mut skip_player_turn = has_existing_files;
loop { loop {
logger.log_section(&format!("TURN {}/{} - PLAYER MODE", turn, MAX_TURNS)); // Skip player turn if we have existing files and this is the first iteration
if skip_player_turn {
// Player mode: implement requirements (with coach feedback if available) logger.log_section(&format!("TURN {}/{} - SKIPPING PLAYER MODE", turn, MAX_TURNS));
let player_prompt = if coach_feedback.is_empty() { logger.log("📁 Existing project files detected, skipping to coach evaluation");
format!( skip_player_turn = false; // Only skip the first turn
"You are G3 in implementation mode. Read and implement the following requirements:\n\n{}\n\nImplement this step by step, creating all necessary files and code.",
requirements
)
} else { } else {
format!( logger.log_section(&format!("TURN {}/{} - PLAYER MODE", turn, MAX_TURNS));
"You are G3 in implementation mode. You need to address the coach's feedback and improve your implementation.\n\nORIGINAL REQUIREMENTS:\n{}\n\nCOACH FEEDBACK TO ADDRESS:\n{}\n\nPlease make the necessary improvements to address the coach's feedback while ensuring all original requirements are met.",
requirements, coach_feedback
)
};
logger.log("🎯 Starting player implementation..."); // Player mode: implement requirements (with coach feedback if available)
if !coach_feedback.is_empty() { let player_prompt = if coach_feedback.is_empty() {
logger.log("📝 Incorporating coach feedback from previous turn"); format!(
"You are G3 in implementation mode. Read and implement the following requirements:\n\n{}\n\nImplement this step by step, creating all necessary files and code.",
requirements
)
} else {
format!(
"You are G3 in implementation mode. You need to address the coach's feedback and improve your implementation.\n\nORIGINAL REQUIREMENTS:\n{}\n\nCOACH FEEDBACK TO ADDRESS:\n{}\n\nPlease make the necessary improvements to address the coach's feedback while ensuring all original requirements are met.",
requirements, coach_feedback
)
};
logger.log("🎯 Starting player implementation...");
if !coach_feedback.is_empty() {
logger.log("📝 Incorporating coach feedback from previous turn");
}
let _player_result = agent
.execute_task_with_timing(&player_prompt, None, false, show_prompt, show_code, true)
.await?;
logger.log("🎯 Player implementation completed");
logger.log("");
} }
let _player_result = agent
.execute_task_with_timing(&player_prompt, None, false, show_prompt, show_code, true)
.await?;
logger.log("🎯 Player implementation completed");
logger.log("");
// Create a new agent instance for coach mode to ensure fresh context // Create a new agent instance for coach mode to ensure fresh context
// Make sure the coach agent also operates in the workspace directory // Make sure the coach agent also operates in the workspace directory
let config = g3_config::Config::load(None)?; let config = g3_config::Config::load(None)?;
@@ -360,6 +372,64 @@ Keep your response concise and focused on actionable items.",
Ok(()) Ok(())
} }
/// Check if there are existing project files in the workspace directory
/// Returns true if project files are found (excluding requirements.md and logs directory)
fn check_existing_project_files(workspace_dir: &PathBuf, logger: &AutonomousLogger) -> Result<bool> {
logger.log("🔍 Checking for existing project files...");
let entries = match std::fs::read_dir(workspace_dir) {
Ok(entries) => entries,
Err(e) => {
logger.log(&format!("❌ Failed to read workspace directory: {}", e));
return Ok(false);
}
};
let mut project_files = Vec::new();
let mut total_files = 0;
for entry in entries {
let entry = entry?;
let path = entry.path();
let file_name = path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
// Skip requirements.md, logs directory, and hidden files
if file_name == "requirements.md" || file_name == "logs" || file_name.starts_with('.') {
continue;
}
total_files += 1;
// Collect project files for logging (limit to first 5)
if project_files.len() < 5 {
if path.is_dir() {
project_files.push(format!("{}/", file_name));
} else {
project_files.push(file_name.to_string());
}
}
}
if total_files > 0 {
logger.log(&format!("📁 Found {} existing project files", total_files));
if !project_files.is_empty() {
let files_display = if total_files > 5 {
format!("{} (and {} more)", project_files.join(", "), total_files - 5)
} else {
project_files.join(", ")
};
logger.log(&format!(" Files: {}", files_display));
}
logger.log("⏭️ Will skip first player turn and evaluate existing implementation");
Ok(true)
} else {
logger.log("📂 No existing project files found, starting fresh implementation");
Ok(false)
}
}
fn display_context_progress(agent: &Agent) { fn display_context_progress(agent: &Agent) {
let context = agent.get_context_window(); let context = agent.get_context_window();
let percentage = context.percentage_used(); let percentage = context.percentage_used();
@@ -431,28 +501,67 @@ impl AutonomousLogger {
Ok(Self { log_writer }) Ok(Self { log_writer })
} }
fn log(&self, message: &str) { /// Truncate text to a single line for logging
// Print to console fn truncate_for_log(&self, text: &str, max_chars: usize) -> String {
println!("{}", message); // First, get the first line only
let first_line = text.lines().next().unwrap_or("").trim();
// Write to log file with timestamp // Then truncate if too long
if first_line.len() <= max_chars {
first_line.to_string()
} else {
format!("{}...", &first_line[..max_chars.saturating_sub(3)])
}
}
fn log(&self, message: &str) {
// Ensure single line for console output
let single_line_message = self.truncate_for_log(message, 200);
// Print to console
println!("{}", single_line_message);
// Write to log file with timestamp (also single line)
if let Ok(mut writer) = self.log_writer.lock() { if let Ok(mut writer) = self.log_writer.lock() {
let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC"); let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC");
let _ = writeln!(writer, "[{}] {}", timestamp, message); let _ = writeln!(writer, "[{}] {}", timestamp, single_line_message);
let _ = writer.flush(); let _ = writer.flush();
} }
} }
fn log_section(&self, section: &str) { fn log_section(&self, section: &str) {
// Sections can be multi-line for visual separation, but content should be single line
let single_line_section = self.truncate_for_log(section, 100);
let separator = "=".repeat(80); let separator = "=".repeat(80);
let message = format!("{}\n{}\n{}", separator, section, separator);
self.log(&message); // Print to console with visual formatting
println!("{}", separator);
println!("{}", single_line_section);
println!("{}", separator);
// Log to file as single entries
if let Ok(mut writer) = self.log_writer.lock() {
let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC");
let _ = writeln!(writer, "[{}] === {} ===", timestamp, single_line_section);
let _ = writer.flush();
}
} }
fn log_subsection(&self, subsection: &str) { fn log_subsection(&self, subsection: &str) {
let single_line_subsection = self.truncate_for_log(subsection, 100);
let separator = "-".repeat(60); let separator = "-".repeat(60);
let message = format!("{}\n{}\n{}", separator, subsection, separator);
self.log(&message); // Print to console with visual formatting
println!("{}", separator);
println!("{}", single_line_subsection);
println!("{}", separator);
// Log to file as single entry
if let Ok(mut writer) = self.log_writer.lock() {
let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC");
let _ = writeln!(writer, "[{}] --- {} ---", timestamp, single_line_subsection);
let _ = writer.flush();
}
} }
} }