fix: harden codex runs against tuleap mcp runtime panic
This commit is contained in:
parent
33439e11c8
commit
906c44ef22
2 changed files with 42 additions and 4 deletions
|
|
@ -67,7 +67,13 @@ impl AgentTool {
|
||||||
|
|
||||||
pub fn to_non_interactive_args(&self) -> Vec<String> {
|
pub fn to_non_interactive_args(&self) -> Vec<String> {
|
||||||
match self {
|
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()],
|
AgentTool::ClaudeCode => vec!["-p".to_string()],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -299,7 +305,13 @@ mod tests {
|
||||||
fn test_non_interactive_args_match_cli_expectations() {
|
fn test_non_interactive_args_match_cli_expectations() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AgentTool::Codex.to_non_interactive_args(),
|
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!(
|
assert_eq!(
|
||||||
AgentTool::ClaudeCode.to_non_interactive_args(),
|
AgentTool::ClaudeCode.to_non_interactive_args(),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,19 @@ use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::time::{timeout, Duration};
|
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(
|
pub async fn run_agent_command(
|
||||||
command: &str,
|
command: &str,
|
||||||
args: &[String],
|
args: &[String],
|
||||||
|
|
@ -31,7 +44,7 @@ pub async fn run_agent_command(
|
||||||
.map_err(|e| format!("Failed to wait process output: {}", e))?;
|
.map_err(|e| format!("Failed to wait process output: {}", e))?;
|
||||||
|
|
||||||
if !output.status.success() {
|
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);
|
let code = output.status.code().unwrap_or(-1);
|
||||||
if stderr.is_empty() {
|
if stderr.is_empty() {
|
||||||
return Err(format!("CLI command exited with code {}", code));
|
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))??;
|
.map_err(|_| format!("CLI command timed out after {}s", timeout_secs))??;
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
let stderr = stderr_output.trim().to_string();
|
let stderr = normalize_process_stderr(&stderr_output);
|
||||||
let code = status.code().unwrap_or(-1);
|
let code = status.code().unwrap_or(-1);
|
||||||
if stderr.is_empty() {
|
if stderr.is_empty() {
|
||||||
return Err(format!("CLI command exited with code {}", code));
|
return Err(format!("CLI command exited with code {}", code));
|
||||||
|
|
@ -138,6 +151,19 @@ where
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[tokio::test]
|
||||||
async fn test_run_agent_command_streaming_collects_chunks() {
|
async fn test_run_agent_command_streaming_collects_chunks() {
|
||||||
let args = vec!["-c".to_string(), "cat".to_string()];
|
let args = vec!["-c".to_string(), "cat".to_string()];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue