diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index a63b0a91f..b3dcf504e 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -625,7 +625,7 @@ impl Codex { let session_source_clone = session_configuration.session_source.clone(); let (agent_status_tx, agent_status_rx) = watch::channel(AgentStatus::PendingInit); - let session = Session::new( + let session = Box::pin(Session::new( session_configuration, config.clone(), installation_id, @@ -647,7 +647,7 @@ impl Codex { parent_rollout_thread_trace, attestation_provider, multi_agent_version, - ) + )) .await .map_err(|e| { error!("Failed to create session: {e:#}"); diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index 0b8ebaa14..d130a3581 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -1308,7 +1308,7 @@ impl ThreadManagerState { .await; let CodexSpawnOk { codex, thread_id, .. - } = Codex::spawn(CodexSpawnArgs { + } = Box::pin(Codex::spawn(CodexSpawnArgs { config, installation_id: self.installation_id.clone(), auth_manager, @@ -1336,7 +1336,7 @@ impl ThreadManagerState { thread_store: Arc::clone(&self.thread_store), attestation_provider: self.attestation_provider.clone(), inherited_multi_agent_version: multi_agent_version, - }) + })) .await?; let new_thread = self .finalize_thread_spawn(codex, thread_id, tracked_session_source) diff --git a/codex-rs/tui/src/app/config_persistence.rs b/codex-rs/tui/src/app/config_persistence.rs index 92ed5d470..ec72c5974 100644 --- a/codex-rs/tui/src/app/config_persistence.rs +++ b/codex-rs/tui/src/app/config_persistence.rs @@ -14,19 +14,32 @@ pub(super) struct WindowsSetupPermissions { pub(super) workspace_roots: Vec, } +async fn build_config_on_runtime_worker( + builder: ConfigBuilder, + error_context: String, +) -> Result { + match tokio::spawn(async move { builder.build().await }).await { + Ok(build_result) => build_result.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")), + } +} + impl App { pub(super) async fn rebuild_config_for_cwd(&self, cwd: PathBuf) -> Result { let mut overrides = self.harness_overrides.clone(); overrides.cwd = Some(cwd.clone()); let cwd_display = cwd.display().to_string(); - ConfigBuilder::default() + let builder = ConfigBuilder::default() .codex_home(self.config.codex_home.to_path_buf()) .cli_overrides(self.cli_kv_overrides.clone()) .harness_overrides(overrides) - .loader_overrides(self.loader_overrides.clone()) - .build() - .await - .wrap_err_with(|| format!("Failed to rebuild config for cwd {cwd_display}")) + .loader_overrides(self.loader_overrides.clone()); + build_config_on_runtime_worker( + builder, + format!("Failed to rebuild config for cwd {cwd_display}"), + ) + .await } pub(super) async fn rebuild_config_for_permission_profile( @@ -38,16 +51,16 @@ impl App { overrides.sandbox_mode = None; overrides.permission_profile = None; overrides.default_permissions = Some(profile_id.to_string()); - ConfigBuilder::default() + let builder = ConfigBuilder::default() .codex_home(self.config.codex_home.to_path_buf()) .cli_overrides(self.cli_kv_overrides.clone()) .harness_overrides(overrides) - .loader_overrides(self.loader_overrides.clone()) - .build() - .await - .wrap_err_with(|| { - format!("Failed to rebuild config for permission profile {profile_id}") - }) + .loader_overrides(self.loader_overrides.clone()); + build_config_on_runtime_worker( + builder, + format!("Failed to rebuild config for permission profile {profile_id}"), + ) + .await } #[cfg(target_os = "windows")]