diff --git a/deep_research/src/core.rs b/deep_research/src/core.rs index fcfbc9d..e1e0dcb 100644 --- a/deep_research/src/core.rs +++ b/deep_research/src/core.rs @@ -178,6 +178,11 @@ async fn write_report( drop(spinner); let mut report = String::new(); + // Locked once for the whole stream rather than per chunk (as print! + // would do internally) — chunks arrive in a tight loop, so re-acquiring + // the lock on every one adds up. + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); while let Some(chunk) = response_stream.next().await { match chunk? { @@ -189,13 +194,16 @@ async fn write_report( // Terminal stdout is line-buffered, so a flush is needed here — // otherwise a chunk without a trailing newline sits in the // buffer instead of appearing as it streams in. - print!("{text}"); - std::io::stdout().flush()?; + write!(handle, "{text}")?; + handle.flush()?; } _ => continue, } } - println!(); + // `handle` still holds stdout's lock here, so this must go through it + // rather than `println!` — reacquiring the same lock from this thread + // would deadlock. + writeln!(handle)?; Ok(report) }