diff --git a/Cargo.lock b/Cargo.lock index 882f939..a2c0262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -559,7 +559,6 @@ dependencies = [ "tokenizers", "tokio", "tokio-rustls", - "tokio-scoped", "tokio-util", "tui-markdown", "tui-textarea-2", @@ -3160,27 +3159,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-scoped" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4beb8ba13bc53ac53ce1d52b42f02e5d8060f0f42138862869beb769722b256" -dependencies = [ - "tokio", - "tokio-stream", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.18" diff --git a/Cargo.toml b/Cargo.toml index 096c390..c97840f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,6 @@ rayon = "1" tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7", features = ["compat"] } -tokio-scoped = "0.2.0" futures = "0.3" capnp = "0.25" capnp-rpc = "0.25" diff --git a/src/user/mod.rs b/src/user/mod.rs index 9ec1de6..8904dcd 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -190,25 +190,30 @@ async fn start(cli: crate::user::CliArgs) -> Result<()> { let (turn_tx, turn_rx) = tokio::sync::mpsc::channel(1); let (mind_tx, mind_rx) = tokio::sync::mpsc::unbounded_channel(); - let mind = crate::mind::Mind::new(config, turn_tx).await; + let mind = std::sync::Arc::new(crate::mind::Mind::new(config, turn_tx).await); - let mut result = Ok(()); - tokio_scoped::scope(|s| { - // Mind event loop — init + run - s.spawn(async { - mind.init().await; - mind.run(mind_rx, turn_rx).await; - }); + // UI runs on a dedicated OS thread so CPU-intensive work on the + // main tokio runtime can't starve rendering. + let ui_mind = mind.clone(); + let ui_handle = std::thread::Builder::new() + .name("ui".into()) + .spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("UI tokio runtime"); + rt.block_on(run( + tui::App::new(String::new(), ui_mind.agent.clone()), + &ui_mind, mind_tx, + )) + }) + .expect("spawn UI thread"); - // UI event loop - s.spawn(async { - result = run( - tui::App::new(String::new(), mind.agent.clone()), - &mind, mind_tx, - ).await; - }); - }); - result + // Mind event loop — runs on the main tokio runtime + mind.init().await; + mind.run(mind_rx, turn_rx).await; + + ui_handle.join().unwrap_or_else(|_| Err(anyhow::anyhow!("UI thread panicked"))) } fn hotkey_cycle_reasoning(mind: &crate::mind::Mind) {