From e45226e771add9f87a47b6d24c1ff61d62588846 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 31 Aug 2026 13:31:09 +0000 Subject: [PATCH] Use the async stack budget for approval reviews (#41840) ## What changed - Define the shared 16 MiB thread stack budget in `codex-async-utils`. - Use it for both the async main/runtime threads and the dedicated approval-review thread. GitOrigin-RevId: c825669e1545bcfaeaaaa07066dc63874f46630f --- codex-rs/Cargo.lock | 1 + codex-rs/arg0/Cargo.toml | 1 + codex-rs/arg0/src/lib.rs | 6 +++--- codex-rs/async-utils/src/lib.rs | 3 +++ codex-rs/core/src/guardian/review.rs | 2 ++ 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 2b0bda2a7e..1abd9df623 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2271,6 +2271,7 @@ version = "0.0.0" dependencies = [ "anyhow", "codex-apply-patch", + "codex-async-utils", "codex-exec-server", "codex-install-context", "codex-linux-sandbox", diff --git a/codex-rs/arg0/Cargo.toml b/codex-rs/arg0/Cargo.toml index d797197997..4619d6203b 100644 --- a/codex-rs/arg0/Cargo.toml +++ b/codex-rs/arg0/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] anyhow = { workspace = true } codex-apply-patch = { workspace = true } +codex-async-utils = { workspace = true } codex-exec-server = { workspace = true } codex-install-context = { workspace = true } codex-linux-sandbox = { workspace = true } diff --git a/codex-rs/arg0/src/lib.rs b/codex-rs/arg0/src/lib.rs index 90c5804690..4673f84e42 100644 --- a/codex-rs/arg0/src/lib.rs +++ b/codex-rs/arg0/src/lib.rs @@ -5,6 +5,7 @@ use std::path::Path; use std::path::PathBuf; use codex_apply_patch::CODEX_CORE_APPLY_PATCH_ARG1; +use codex_async_utils::THREAD_STACK_SIZE_BYTES; #[cfg(unix)] use codex_exec_server::CODEX_ARG0_EXEC_HELPER_ARG1; use codex_exec_server::CODEX_FS_HELPER_ARG1; @@ -22,7 +23,6 @@ const MISSPELLED_APPLY_PATCH_ARG0: &str = "applypatch"; #[cfg(unix)] const EXECVE_WRAPPER_ARG0: &str = "codex-execve-wrapper"; const LOCK_FILENAME: &str = ".lock"; -const TOKIO_WORKER_STACK_SIZE_BYTES: usize = 16 * 1024 * 1024; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Arg0DispatchPaths { @@ -232,7 +232,7 @@ where // top-level future on the caller's OS stack. let handle = std::thread::Builder::new() .name("codex-main".to_string()) - .stack_size(TOKIO_WORKER_STACK_SIZE_BYTES) + .stack_size(THREAD_STACK_SIZE_BYTES) .spawn(move || { let runtime = build_runtime()?; runtime.block_on(run_main_with_arg0_guard( @@ -290,7 +290,7 @@ fn linux_sandbox_exe_path( fn build_runtime() -> anyhow::Result { let mut builder = tokio::runtime::Builder::new_multi_thread(); builder.enable_all(); - builder.thread_stack_size(TOKIO_WORKER_STACK_SIZE_BYTES); + builder.thread_stack_size(THREAD_STACK_SIZE_BYTES); Ok(builder.build()?) } diff --git a/codex-rs/async-utils/src/lib.rs b/codex-rs/async-utils/src/lib.rs index caa3479a67..16a86229ee 100644 --- a/codex-rs/async-utils/src/lib.rs +++ b/codex-rs/async-utils/src/lib.rs @@ -1,6 +1,9 @@ use std::future::Future; use tokio_util::sync::CancellationToken; +/// Stack budget for threads that poll Codex async work. +pub const THREAD_STACK_SIZE_BYTES: usize = 16 * 1024 * 1024; + #[derive(Debug, PartialEq, Eq)] pub enum CancelErr { Cancelled, diff --git a/codex-rs/core/src/guardian/review.rs b/codex-rs/core/src/guardian/review.rs index cd6c2ccfec..2882cb799f 100644 --- a/codex-rs/core/src/guardian/review.rs +++ b/codex-rs/core/src/guardian/review.rs @@ -5,6 +5,7 @@ use codex_analytics::GuardianReviewFailureReason; use codex_analytics::GuardianReviewTerminalStatus; use codex_analytics::GuardianReviewTrackContext; use codex_analytics::GuardianReviewedAction; +use codex_async_utils::THREAD_STACK_SIZE_BYTES; use codex_core_plugins::PluginCommandAttribution; use codex_extension_api::ThreadIdleCause; use codex_features::Feature; @@ -806,6 +807,7 @@ pub(crate) fn spawn_approval_request_review( let runtime = session.services.runtime_handle.clone(); let spawn_result = std::thread::Builder::new() .name("codex-approval-review".to_string()) + .stack_size(THREAD_STACK_SIZE_BYTES) .spawn(move || { let decision = runtime.block_on(run_guardian_review( session, context, review_id, request, reasons, options,