Reduce TUI stack usage during session transitions (#44176)

## Why

Session transitions need stack headroom to rebuild configuration and the chat widget. Tokio stores task outputs inline even when it boxes the task future, so returning a large `Config` adds stack pressure during task allocation.

## What changed

Box the configuration build result inside the runtime worker and unbox it after joining. Box the `App::run` future to keep the large event loop out of enclosing startup futures.

## Testing

Extend the production-stack TUI integration test to enter `/side`, verify the process remains running, and return to the saved conversation with Ctrl+C.

GitOrigin-RevId: 44975300bb837bf3645ff762cf7bcdc44a277f41
This commit is contained in:
Eric Traut
2026-09-09 15:20:47 +00:00
committed by copyberry
parent 0df1daf526
commit c77c34ed33
3 changed files with 15 additions and 5 deletions
+4 -2
View File
@@ -19,8 +19,10 @@ async fn build_config_on_runtime_worker(
builder: ConfigBuilder,
error_context: String,
) -> Result<Config> {
match tokio::spawn(async move { builder.build().await }).await {
Ok(build_result) => build_result.wrap_err(error_context),
// Tokio stores the task output inline even when it boxes the future. Keep the large
// Config off the caller's stack while Tokio allocates the task during session switches.
match tokio::spawn(async move { builder.build().await.map(Box::new) }).await {
Ok(build_result) => build_result.map(|config| *config).wrap_err(error_context),
Err(err) if err.is_panic() => std::panic::resume_unwind(err.into_panic()),
Err(err) => Err(err).wrap_err_with(|| format!("{error_context} task failed")),
}
+4 -2
View File
@@ -1811,7 +1811,9 @@ async fn run_ratatui_app(
Ok(StartupHooksReviewOutcome::OpenHooksBrowser(data)) => Some(data),
};
let app_result = App::run(
// Keep the large event-loop future out of the enclosing startup futures so session
// transitions have enough stack headroom to rebuild configuration and the chat widget.
let app_result = Box::pin(App::run(
&mut tui,
app_server,
config,
@@ -1834,7 +1836,7 @@ async fn run_ratatui_app(
startup_hooks_browser,
startup_draft,
managed_worktree,
)
))
.await;
terminal_restore_guard.restore_silently();
+7 -1
View File
@@ -16,7 +16,7 @@ use std::time::Instant;
use wiremock::matchers::body_string_contains;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn picker_worktree_fork_and_cd_run_on_the_production_stack() -> Result<()> {
async fn picker_side_worktree_fork_and_cd_run_on_the_production_stack() -> Result<()> {
let repository = tempfile::tempdir_in("/tmp")?;
let root = repository.path().canonicalize()?;
let status = Command::new("git")
@@ -93,6 +93,12 @@ async fn picker_worktree_fork_and_cd_run_on_the_production_stack() -> Result<()>
terminal.wait_for_screen("STACK_SAVED_HISTORY")?;
terminal.wait_for_screen("Ask Codex to do anything")?;
submit(&mut terminal, "/side")?;
terminal.wait_for_screen("Side from main thread")?;
terminal.ensure_running()?;
terminal.write_input(b"\x03")?;
terminal.wait_for_screen("STACK_SAVED_HISTORY")?;
submit(&mut terminal, "/resume")?;
terminal.wait_for_screen("Resume a previous session")?;
terminal.ensure_running()?;