fix: buffer tool stdout as well as stderr so that any tools that error to stdout are captured and included in the response to the model, enabling the model to see what went wrong and to reason about how to fix it.
CI / All (ubuntu-latest) (push) Failing after 25s
CI / All (macos-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled

This commit is contained in:
2026-06-16 15:07:55 -06:00
parent b927e2a200
commit 14969e35fa
+8 -1
View File
@@ -1292,11 +1292,13 @@ pub fn run_llm_function(
let mut buffer = [0; 1024]; let mut buffer = [0; 1024];
let mut reader = stdout; let mut reader = stdout;
let mut out = io::stdout(); let mut out = io::stdout();
let mut buf = Vec::new();
while let Ok(n) = reader.read(&mut buffer) { while let Ok(n) = reader.read(&mut buffer) {
if n == 0 { if n == 0 {
break; break;
} }
let chunk = &buffer[0..n]; let chunk = &buffer[0..n];
buf.extend_from_slice(chunk);
let mut last_pos = 0; let mut last_pos = 0;
for (i, &byte) in chunk.iter().enumerate() { for (i, &byte) in chunk.iter().enumerate() {
if byte == b'\n' { if byte == b'\n' {
@@ -1310,6 +1312,7 @@ pub fn run_llm_function(
} }
let _ = out.flush(); let _ = out.flush();
} }
buf
}); });
let stderr_thread = std::thread::spawn(move || { let stderr_thread = std::thread::spawn(move || {
@@ -1342,18 +1345,22 @@ pub fn run_llm_function(
let status = child let status = child
.wait() .wait()
.map_err(|err| anyhow!("Unable to run {command_name}, {err}"))?; .map_err(|err| anyhow!("Unable to run {command_name}, {err}"))?;
let _ = stdout_thread.join(); let stdout_bytes = stdout_thread.join().unwrap_or_default();
let stderr_bytes = stderr_thread.join().unwrap_or_default(); let stderr_bytes = stderr_thread.join().unwrap_or_default();
let exit_code = status.code().unwrap_or_default(); let exit_code = status.code().unwrap_or_default();
if exit_code != 0 { if exit_code != 0 {
let stderr = String::from_utf8_lossy(&stderr_bytes).trim().to_string(); let stderr = String::from_utf8_lossy(&stderr_bytes).trim().to_string();
let stdout = String::from_utf8_lossy(&stdout_bytes).trim().to_string();
let tool_error_message = format!("Tool call '{command_name}' exited with code {exit_code}"); let tool_error_message = format!("Tool call '{command_name}' exited with code {exit_code}");
eprintln!("{}", warning_text(&format!("⚠️ {tool_error_message} ⚠️"))); eprintln!("{}", warning_text(&format!("⚠️ {tool_error_message} ⚠️")));
let mut error_json = json!({"tool_call_error": tool_error_message}); let mut error_json = json!({"tool_call_error": tool_error_message});
if !stderr.is_empty() { if !stderr.is_empty() {
error_json["stderr"] = json!(stderr); error_json["stderr"] = json!(stderr);
} }
if !stdout.is_empty() {
error_json["stdout"] = json!(stdout);
}
debug!("Tool call error: {error_json:?}"); debug!("Tool call error: {error_json:?}");
return Ok(Some(error_json.to_string())); return Ok(Some(error_json.to_string()));
} }