diff --git a/crates/g3-cli/src/commands.rs b/crates/g3-cli/src/commands.rs index 71b0600..86fece1 100644 --- a/crates/g3-cli/src/commands.rs +++ b/crates/g3-cli/src/commands.rs @@ -156,7 +156,10 @@ pub async fn handle_command( } else { G3Status::progress(&format!("loading {}", file_path)); G3Status::done(); - execute_task_with_retry(agent, prompt, show_prompt, show_code, output).await; + let completed = execute_task_with_retry(agent, prompt, show_prompt, show_code, output).await; + if !completed { + return Ok(false); + } } } Err(e) => { @@ -383,7 +386,10 @@ pub async fn handle_command( // Auto-submit the project status prompt let prompt = "what is the current state of the project? and what is your suggested next best step?"; - execute_task_with_retry(agent, prompt, show_prompt, show_code, output).await; + let completed = execute_task_with_retry(agent, prompt, show_prompt, show_code, output).await; + if !completed { + return Ok(false); + } } else { output.print("❌ Failed to set project content in agent context."); } diff --git a/crates/g3-cli/src/interactive.rs b/crates/g3-cli/src/interactive.rs index 6feb226..6e5530f 100644 --- a/crates/g3-cli/src/interactive.rs +++ b/crates/g3-cli/src/interactive.rs @@ -210,7 +210,7 @@ pub async fn run_interactive( } // Process the multiline input - execute_task_with_retry( + let completed = execute_task_with_retry( &mut agent, &input, show_prompt, @@ -218,6 +218,9 @@ pub async fn run_interactive( &output, ) .await; + if !completed { + break; + } // Send auto-memory reminder if enabled and tools were called // Skip per-turn reminders when from_agent_mode - we'll send once on exit @@ -243,13 +246,16 @@ pub async fn run_interactive( // Check for control commands if input.starts_with('/') { - if handle_command(&input, &mut agent, workspace_path, &output, &mut active_project, &mut rl, show_prompt, show_code).await? { + let should_continue = handle_command(&input, &mut agent, workspace_path, &output, &mut active_project, &mut rl, show_prompt, show_code).await?; + if should_continue { continue; + } else { + break; } } // Process the single line input - execute_task_with_retry( + let completed = execute_task_with_retry( &mut agent, &input, show_prompt, @@ -257,6 +263,9 @@ pub async fn run_interactive( &output, ) .await; + if !completed { + break; + } // Send auto-memory reminder if enabled and tools were called // Skip per-turn reminders when from_agent_mode - we'll send once on exit @@ -269,15 +278,8 @@ pub async fn run_interactive( } Err(ReadlineError::Interrupted) => { // Ctrl-C pressed - if in_multiline { - // Cancel multiline input - output.print("Multi-line input cancelled"); - multiline_buffer.clear(); - in_multiline = false; - } else { - output.print("CTRL-C"); - } - continue; + output.print(""); + break; } Err(ReadlineError::Eof) => { output.print("CTRL-D"); diff --git a/crates/g3-cli/src/task_execution.rs b/crates/g3-cli/src/task_execution.rs index 6cd069e..5cc04d9 100644 --- a/crates/g3-cli/src/task_execution.rs +++ b/crates/g3-cli/src/task_execution.rs @@ -26,13 +26,14 @@ fn recoverable_error_name(err: &RecoverableError) -> &'static str { } /// Execute a task with retry logic for recoverable errors. +/// Returns `true` if the task completed normally, `false` if cancelled by Ctrl+C. pub async fn execute_task_with_retry( agent: &mut Agent, input: &str, show_prompt: bool, show_code: bool, output: &SimpleOutput, -) { +) -> bool { let mut attempt = 0; output.print("🤔 Thinking..."); @@ -54,7 +55,7 @@ pub async fn execute_task_with_retry( _ = tokio::signal::ctrl_c() => { cancel_token_clone.cancel(); output.print("\n⚠️ Operation cancelled by user (Ctrl+C)"); - return; + return false; } }; @@ -64,12 +65,12 @@ pub async fn execute_task_with_retry( output.print(&format!("✅ Request succeeded after {} attempts", attempt)); } // Response was already displayed during streaming - don't print again - return; + return true; } Err(e) => { if e.to_string().contains("cancelled") { output.print("⚠️ Operation cancelled by user"); - return; + return false; } // Check if this is a recoverable error that we should retry @@ -99,7 +100,7 @@ pub async fn execute_task_with_retry( // For non-recoverable errors or after max retries handle_execution_error(&e, input, output, attempt); - return; + return true; } } }