From 9d19c7426ecc3fe0a384be57a33bcb5909715387 Mon Sep 17 00:00:00 2001 From: Benjamin Carlsson Date: Mon, 31 Aug 2026 14:25:15 +0000 Subject: [PATCH] Box the session startup future at its API boundary (#41853) ## What changed - Make `Session::spawn` return a `BoxFuture` while preserving lazy session initialization. - Prevent the startup wrapper from being inlined so callers do not expose its concrete future. - Await the returned future directly at session creation call sites. GitOrigin-RevId: 5432745aae1c934b16202716a8d49a8553de2018 --- codex-rs/core/src/codex_delegate.rs | 4 +-- codex-rs/core/src/session/mod.rs | 44 ++++++++++++++++------------- codex-rs/core/src/thread_manager.rs | 4 +-- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/codex-rs/core/src/codex_delegate.rs b/codex-rs/core/src/codex_delegate.rs index 7733012007..969a6298ff 100644 --- a/codex-rs/core/src/codex_delegate.rs +++ b/codex-rs/core/src/codex_delegate.rs @@ -111,7 +111,7 @@ pub(crate) async fn run_codex_thread_interactive( } else { Arc::clone(&parent_session.services.extensions) }; - let (session, io) = Box::pin(Session::spawn(SessionSpawnArgs { + let (session, io) = Session::spawn(SessionSpawnArgs { config, allow_provider_model_fallback: false, user_instructions, @@ -158,7 +158,7 @@ pub(crate) async fn run_codex_thread_interactive( inherited_multi_agent_version: Some(MultiAgentVersion::Disabled), git_enrichment_policy, windows_sandbox_proxy_settings_mode, - })) + }) .or_cancel(&cancel_token) .await??; let thread_config = session.thread_config_snapshot().await; diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index ea0651cc02..c99599b7d6 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -478,28 +478,34 @@ const CYBER_SAFETY_URL: &str = "https://developers.openai.com/codex/concepts/cyb impl Session { /// Spawn and initialize a new session. - pub(crate) async fn spawn(args: SessionSpawnArgs) -> CodexResult<(Arc, SessionIo)> { - let parent_trace = match args.parent_trace { - Some(trace) => { - if codex_otel::context_from_w3c_trace_context(&trace).is_some() { - Some(trace) - } else { - warn!("ignoring invalid thread spawn trace carrier"); - None + /// Hide the concrete startup future from callers while keeping initialization lazy. + #[inline(never)] + pub(crate) fn spawn( + args: SessionSpawnArgs, + ) -> BoxFuture<'static, CodexResult<(Arc, SessionIo)>> { + Box::pin(async move { + let parent_trace = match args.parent_trace { + Some(trace) => { + if codex_otel::context_from_w3c_trace_context(&trace).is_some() { + Some(trace) + } else { + warn!("ignoring invalid thread spawn trace carrier"); + None + } } + None => None, + }; + let thread_spawn_span = info_span!("thread_spawn", otel.name = "thread_spawn"); + if let Some(trace) = parent_trace.as_ref() { + let _ = set_parent_from_w3c_trace_context(&thread_spawn_span, trace); } - None => None, - }; - let thread_spawn_span = info_span!("thread_spawn", otel.name = "thread_spawn"); - if let Some(trace) = parent_trace.as_ref() { - let _ = set_parent_from_w3c_trace_context(&thread_spawn_span, trace); - } - Self::spawn_internal(SessionSpawnArgs { - parent_trace, - ..args + Self::spawn_internal(SessionSpawnArgs { + parent_trace, + ..args + }) + .instrument(thread_spawn_span) + .await }) - .instrument(thread_spawn_span) - .await } async fn spawn_internal(args: SessionSpawnArgs) -> CodexResult<(Arc, SessionIo)> { diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index 90fe9e06f7..7f6648bcb8 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -1987,7 +1987,7 @@ impl ThreadManagerState { } else { codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile }; - let (session, io) = Box::pin(Session::spawn(SessionSpawnArgs { + let (session, io) = Session::spawn(SessionSpawnArgs { config, allow_provider_model_fallback, user_instructions, @@ -2027,7 +2027,7 @@ impl ThreadManagerState { inherited_multi_agent_version: multi_agent_version, git_enrichment_policy: GitEnrichmentPolicy::Fresh, windows_sandbox_proxy_settings_mode, - })) + }) .await?; // Enable Full Access form input only after session startup so a required MCP server cannot // block startup while waiting for form input.