From edd0d898204eba8397181deae8e4a238d1f7df27 Mon Sep 17 00:00:00 2001 From: oliverye-oai Date: Thu, 5 Nov 2026 07:47:19 +0000 Subject: [PATCH] Add a root-only option for background compaction (#59598) ## What changed Add the disabled-by-default `async_compaction_root_only` feature flag. When enabled, it restricts background compaction to root sessions, excluding non-root agents. Expose the flag in the configuration schema. ## Testing Add a parameterized test covering root session eligibility and eligibility for review subagents and guardian sessions with the flag enabled and disabled. GitOrigin-RevId: b4cce3f24f7f418ae61a82a7aef310f849cfd532 --- codex-rs/core/config.schema.json | 6 +++++ codex-rs/core/src/session/async_compaction.rs | 10 +++---- .../src/session/async_compaction_tests.rs | 26 ++++++++++++++++++- codex-rs/features/src/lib.rs | 8 ++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index d91dc91a9c..f4448d934d 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -895,6 +895,9 @@ "async_compaction": { "$ref": "#/definitions/FeatureToml_for_AsyncCompactionConfigToml" }, + "async_compaction_root_only": { + "type": "boolean" + }, "auth_elicitation": { "type": "boolean" }, @@ -7830,6 +7833,9 @@ "async_compaction": { "$ref": "#/definitions/FeatureToml_for_AsyncCompactionConfigToml" }, + "async_compaction_root_only": { + "type": "boolean" + }, "auth_elicitation": { "type": "boolean" }, diff --git a/codex-rs/core/src/session/async_compaction.rs b/codex-rs/core/src/session/async_compaction.rs index 8a1ec32327..cc263a4560 100644 --- a/codex-rs/core/src/session/async_compaction.rs +++ b/codex-rs/core/src/session/async_compaction.rs @@ -39,11 +39,11 @@ pub(crate) struct AsyncCompactionState { } pub(super) fn enabled(turn_context: &TurnContext) -> bool { - turn_context - .config - .features - .enabled(Feature::AsyncCompaction) - && !turn_context.config.features.enabled(Feature::TokenBudget) + let features = &turn_context.config.features; + features.enabled(Feature::AsyncCompaction) + && !(features.enabled(Feature::AsyncCompactionRootOnly) + && turn_context.session_source.is_non_root_agent()) + && !features.enabled(Feature::TokenBudget) && matches!( turn_context.provider.capabilities().remote_compaction, RemoteCompactionSupport::V2 diff --git a/codex-rs/core/src/session/async_compaction_tests.rs b/codex-rs/core/src/session/async_compaction_tests.rs index e6ad3dc549..f85b360d23 100644 --- a/codex-rs/core/src/session/async_compaction_tests.rs +++ b/codex-rs/core/src/session/async_compaction_tests.rs @@ -1,4 +1,4 @@ -//! Cancellation prevents new speculation without cancelling session-owned work. +//! Background compaction eligibility and cancellation. use super::*; use codex_analytics::CompactionReason; @@ -8,6 +8,9 @@ use codex_protocol::models::AudioReference; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::InputModality; +use codex_protocol::protocol::InternalSessionSource; +use codex_protocol::protocol::SessionSource; +use codex_protocol::protocol::SubAgentSource; use codex_protocol::protocol::TokenUsage; use core_test_support::responses; use pretty_assertions::assert_eq; @@ -218,3 +221,24 @@ async fn cancelled_turn_skips_launch_but_preserves_existing_work(trigger: Compac } shutdown(&sess).await; } + +#[test_case::test_case(false; "all agents")] +#[test_case::test_case(true; "root only")] +#[tokio::test] +async fn root_only_controls_child_eligibility(root_only: bool) { + let (_, mut turn) = crate::session::tests::make_session_and_context().await; + let features = &mut Arc::make_mut(&mut turn.config).features; + features.enable(Feature::AsyncCompaction).unwrap(); + features + .set_enabled(Feature::AsyncCompactionRootOnly, root_only) + .unwrap(); + + assert!(enabled(&turn)); + for source in [ + SessionSource::SubAgent(SubAgentSource::Review), + SessionSource::Internal(InternalSessionSource::Guardian), + ] { + turn.session_source = source; + assert_eq!(enabled(&turn), !root_only); + } +} diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index 65a43d8157..bbea25cf5c 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -492,6 +492,8 @@ pub enum Feature { RemoteCompactionV2, /// Prepare remote compaction in the background before the foreground limit is reached. AsyncCompaction, + /// Restrict background compaction to the root session. + AsyncCompactionRootOnly, /// Include retained images in the remote compaction context budget. CompactionImageBudget, /// Retain client-authored developer messages across compacted context windows. @@ -2347,6 +2349,12 @@ pub const FEATURES: &[FeatureSpec] = &[ stage: Stage::UnderDevelopment, default_enabled: false, }, + FeatureSpec { + id: Feature::AsyncCompactionRootOnly, + key: "async_compaction_root_only", + stage: Stage::UnderDevelopment, + default_enabled: false, + }, FeatureSpec { id: Feature::CompactionImageBudget, key: "compaction_image_budget",