From 2661d8577ee17885f63f3a7c95dc96f5b3c67593 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 20 Jul 2026 14:18:22 +0000 Subject: [PATCH] Parallelize TUI bootstrap requests (#34355) ## Why During TUI startup, `hooks/list` holds the global config queue while an uncached `model/list` request may also take time. Waiting for `configRequirements/read` before submitting the model request prevents these operations from overlapping. ## What changed Submit `model/list` and `configRequirements/read` together during bootstrap so the model fetch can overlap the config requests. Preserve the request-specific error context and update the session state after both requests succeed. GitOrigin-RevId: 69a866e6d2fd4798b914dd000456194f49fcfef6 --- codex-rs/tui/src/app_server_session.rs | 61 +++++++++++++++----------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs index 02ccd9619494..825103ce0c99 100644 --- a/codex-rs/tui/src/app_server_session.rs +++ b/codex-rs/tui/src/app_server_session.rs @@ -302,36 +302,47 @@ impl AppServerSession { pub(crate) async fn bootstrap(&mut self, config: &Config) -> Result { let started_at = Instant::now(); let account = self.read_account().await?; + // `hooks/list` holds the global config queue during startup. Submit models and config + // requirements together so an uncached model fetch can overlap both config requests. + let model_request_id = self.next_request_id(); let requirements_request_id = self.next_request_id(); - let requirements: ConfigRequirementsReadResponse = self - .client - .request_typed(ClientRequest::ConfigRequirementsRead { - request_id: requirements_request_id, - params: None, - }) - .await - .map_err(|err| { - bootstrap_request_error("configRequirements/read failed during TUI bootstrap", err) - })?; + let (models, requirements) = tokio::try_join!( + async { + self.client + .request_typed::(ClientRequest::ModelList { + request_id: model_request_id, + params: ModelListParams { + cursor: None, + limit: None, + include_hidden: Some(true), + }, + }) + .await + .map_err(|err| { + bootstrap_request_error("model/list failed during TUI bootstrap", err) + }) + }, + async { + self.client + .request_typed::( + ClientRequest::ConfigRequirementsRead { + request_id: requirements_request_id, + params: None, + }, + ) + .await + .map_err(|err| { + bootstrap_request_error( + "configRequirements/read failed during TUI bootstrap", + err, + ) + }) + }, + )?; self.managed_new_thread_defaults = requirements .requirements .and_then(|requirements| requirements.models) .and_then(|models| models.new_thread); - let model_request_id = self.next_request_id(); - let models: ModelListResponse = self - .client - .request_typed(ClientRequest::ModelList { - request_id: model_request_id, - params: ModelListParams { - cursor: None, - limit: None, - include_hidden: Some(true), - }, - }) - .await - .map_err(|err| { - bootstrap_request_error("model/list failed during TUI bootstrap", err) - })?; let available_models = models .data .into_iter()