diff --git a/crates/g3-cli/src/lib.rs b/crates/g3-cli/src/lib.rs index 03b4578..0d493b2 100644 --- a/crates/g3-cli/src/lib.rs +++ b/crates/g3-cli/src/lib.rs @@ -39,6 +39,10 @@ pub struct Cli { /// Enable autonomous mode with coach-player feedback loop #[arg(long)] pub autonomous: bool, + + /// Maximum number of turns in autonomous mode (default: 5) + #[arg(long, default_value = "5")] + pub max_turns: usize, } pub async fn run() -> Result<()> { @@ -83,7 +87,7 @@ pub async fn run() -> Result<()> { if cli.autonomous { // Autonomous mode with coach-player feedback loop info!("Starting autonomous mode"); - run_autonomous(agent, cli.show_prompt, cli.show_code).await?; + run_autonomous(agent, cli.show_prompt, cli.show_code, cli.max_turns).await?; } else if let Some(task) = cli.task { // Single-shot mode info!("Executing task: {}", task); @@ -515,7 +519,7 @@ fn format_duration(duration: Duration) -> String { } } -async fn run_autonomous(mut agent: Agent, show_prompt: bool, show_code: bool) -> Result<()> { +async fn run_autonomous(mut agent: Agent, show_prompt: bool, show_code: bool, max_turns: usize) -> Result<()> { // Set up workspace directory let workspace_dir = setup_workspace_directory()?; @@ -581,12 +585,12 @@ async fn run_autonomous(mut agent: Agent, show_prompt: bool, show_code: bool) -> if skip_player_turn { logger.log_section(&format!( "TURN {}/{} - SKIPPING PLAYER MODE", - turn, MAX_TURNS + turn, max_turns )); logger.log("📁 Existing project files detected, skipping to coach evaluation"); skip_player_turn = false; // Only skip the first turn } else { - logger.log_section(&format!("TURN {}/{} - PLAYER MODE", turn, MAX_TURNS)); + logger.log_section(&format!("TURN {}/{} - PLAYER MODE", turn, max_turns)); // Player mode: implement requirements (with coach feedback if available) let player_prompt = if coach_feedback.is_empty() { @@ -659,7 +663,7 @@ async fn run_autonomous(mut agent: Agent, show_prompt: bool, show_code: bool) -> // Ensure coach agent is also in the workspace directory std::env::set_current_dir(&workspace_dir)?; - logger.log_section(&format!("TURN {}/{} - COACH MODE", turn, MAX_TURNS)); + logger.log_section(&format!("TURN {}/{} - COACH MODE", turn, max_turns)); // Coach mode: critique the implementation let coach_prompt = format!( @@ -732,9 +736,9 @@ Keep your response concise and focused on actionable items.", } // Check if we've reached max turns - if turn >= MAX_TURNS { + if turn >= max_turns { logger.log_section("SESSION COMPLETED - MAX TURNS REACHED"); - logger.log(&format!("⏰ Maximum turns ({}) reached", MAX_TURNS)); + logger.log(&format!("⏰ Maximum turns ({}) reached", max_turns)); logger.log("🔄 Autonomous mode completed (max iterations)"); break; } diff --git a/crates/g3-core/src/lib.rs b/crates/g3-core/src/lib.rs index eb9a62d..8142926 100644 --- a/crates/g3-core/src/lib.rs +++ b/crates/g3-core/src/lib.rs @@ -958,12 +958,14 @@ The tool will execute immediately and you'll receive the result (success or erro // Tool call header println!("┌─ {}", tool_call.tool); + debug!("Tool call args object: {:?}", tool_call.args.as_object()); if let Some(args_obj) = tool_call.args.as_object() { - for (_key, value) in args_obj { + for (key, value) in args_obj { + debug!("Processing arg: {} = {:?}", key, value); let value_str = match value { serde_json::Value::String(s) => { // For shell commands, truncate at newlines to keep display clean - if tool_call.tool == "shell" && _key == "command" { + if tool_call.tool == "shell" && key == "command" { if let Some(first_line) = s.lines().next() { if s.lines().count() > 1 { format!("{}...", first_line) @@ -974,13 +976,20 @@ The tool will execute immediately and you'll receive the result (success or erro s.clone() } } else { - s.clone() + // For other tools, show first 100 chars to avoid huge displays + if s.len() > 100 { + format!("{}...", &s[..100]) + } else { + s.clone() + } } } _ => value.to_string(), }; - println!("│ {}", value_str); + println!("│ {}: {}", key, value_str); } + } else { + debug!("No args object found in tool call"); } println!("├─ output:"); @@ -1216,9 +1225,15 @@ The tool will execute immediately and you'll receive the result (success or erro } "write_file" => { debug!("Processing write_file tool call"); + debug!("Raw tool_call.args: {:?}", tool_call.args); + debug!("Args as JSON: {}", serde_json::to_string(&tool_call.args).unwrap_or_else(|_| "failed to serialize".to_string())); + let file_path = tool_call.args.get("file_path"); let content = tool_call.args.get("content"); + debug!("file_path: {:?}", file_path); + debug!("content: {:?}", content); + if let (Some(path_val), Some(content_val)) = (file_path, content) { if let (Some(path_str), Some(content_str)) = (path_val.as_str(), content_val.as_str())