diff --git a/src-tauri/src/models/agent.rs b/src-tauri/src/models/agent.rs index c199f8a..1e4c5e6 100644 --- a/src-tauri/src/models/agent.rs +++ b/src-tauri/src/models/agent.rs @@ -67,7 +67,13 @@ impl AgentTool { pub fn to_non_interactive_args(&self) -> Vec { match self { - AgentTool::Codex => vec!["exec".to_string(), "-".to_string()], + AgentTool::Codex => vec![ + "exec".to_string(), + "--ephemeral".to_string(), + "-c".to_string(), + "mcp_servers.tuleap.enabled=false".to_string(), + "-".to_string(), + ], AgentTool::ClaudeCode => vec!["-p".to_string()], } } @@ -299,7 +305,13 @@ mod tests { fn test_non_interactive_args_match_cli_expectations() { assert_eq!( AgentTool::Codex.to_non_interactive_args(), - vec!["exec".to_string(), "-".to_string()] + vec![ + "exec".to_string(), + "--ephemeral".to_string(), + "-c".to_string(), + "mcp_servers.tuleap.enabled=false".to_string(), + "-".to_string() + ] ); assert_eq!( AgentTool::ClaudeCode.to_non_interactive_args(), diff --git a/src-tauri/src/services/agent_runtime.rs b/src-tauri/src/services/agent_runtime.rs index b4dc58c..63e6903 100644 --- a/src-tauri/src/services/agent_runtime.rs +++ b/src-tauri/src/services/agent_runtime.rs @@ -2,6 +2,19 @@ use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}; use tokio::process::Command; use tokio::time::{timeout, Duration}; +fn normalize_process_stderr(stderr: &str) -> String { + let trimmed = stderr.trim(); + if trimmed.is_empty() { + return String::new(); + } + + if trimmed.contains("Cannot start a runtime from within a runtime") { + return "Le processus agent a plante avec un conflit de runtime Tokio. Orchai desactive MCP Tuleap sur les executions automatisees Codex ; relancez la tache. Si l'erreur persiste, mettez a jour ou desactivez le binaire local tuleap-mcp.".to_string(); + } + + trimmed.to_string() +} + pub async fn run_agent_command( command: &str, args: &[String], @@ -31,7 +44,7 @@ pub async fn run_agent_command( .map_err(|e| format!("Failed to wait process output: {}", e))?; if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); + let stderr = normalize_process_stderr(&String::from_utf8_lossy(&output.stderr)); let code = output.status.code().unwrap_or(-1); if stderr.is_empty() { return Err(format!("CLI command exited with code {}", code)); @@ -118,7 +131,7 @@ where .map_err(|_| format!("CLI command timed out after {}s", timeout_secs))??; if !status.success() { - let stderr = stderr_output.trim().to_string(); + let stderr = normalize_process_stderr(&stderr_output); let code = status.code().unwrap_or(-1); if stderr.is_empty() { return Err(format!("CLI command exited with code {}", code)); @@ -138,6 +151,19 @@ where mod tests { use super::*; + #[test] + fn test_normalize_process_stderr_runtime_panic() { + let raw = "thread 'tokio-rt-worker' panicked\nCannot start a runtime from within a runtime"; + let normalized = normalize_process_stderr(raw); + assert!(normalized.contains("conflit de runtime Tokio")); + } + + #[test] + fn test_normalize_process_stderr_passthrough() { + let raw = "some other stderr"; + assert_eq!(normalize_process_stderr(raw), "some other stderr"); + } + #[tokio::test] async fn test_run_agent_command_streaming_collects_chunks() { let args = vec!["-c".to_string(), "cat".to_string()];