diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 5458f4267..e3e4959f0 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -433,9 +433,6 @@ "auth_elicitation": { "type": "boolean" }, - "auto_compaction": { - "type": "boolean" - }, "browser_use": { "type": "boolean" }, @@ -4744,9 +4741,6 @@ "auth_elicitation": { "type": "boolean" }, - "auto_compaction": { - "type": "boolean" - }, "browser_use": { "type": "boolean" }, diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 42c072dd0..3094bc77a 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -332,13 +332,8 @@ pub(crate) async fn run_turn( .await; // as long as compaction works well in getting us way below the token limit, we shouldn't worry about being in an infinite loop. - let auto_compact_needed = turn_context - .config - .features - .enabled(Feature::AutoCompaction) - && token_limit_reached; if needs_follow_up - && (sess.take_new_context_window_request().await || auto_compact_needed) + && (sess.take_new_context_window_request().await || token_limit_reached) { if let Err(err) = run_auto_compact( &sess, @@ -792,14 +787,6 @@ async fn run_pre_sampling_compact( turn_context: &Arc, client_session: &mut ModelClientSession, ) -> CodexResult<()> { - if !turn_context - .config - .features - .enabled(Feature::AutoCompaction) - { - return Ok(()); - } - maybe_run_previous_model_inline_compact(sess, turn_context, client_session).await?; let token_status = super::context_window::context_window_token_status(sess.as_ref(), turn_context.as_ref()) diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index bc4066cd2..78926f5f0 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -738,9 +738,7 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut } if features.enabled(Feature::TokenBudget) { - if features.enabled(Feature::AutoCompaction) { - planned_tools.add_with_exposure(NewContextWindowHandler, ToolExposure::DirectModelOnly); - } + planned_tools.add_with_exposure(NewContextWindowHandler, ToolExposure::DirectModelOnly); planned_tools.add(GetContextRemainingHandler); } diff --git a/codex-rs/core/tests/suite/compact.rs b/codex-rs/core/tests/suite/compact.rs index dec106d0d..17c101bd0 100644 --- a/codex-rs/core/tests/suite/compact.rs +++ b/codex-rs/core/tests/suite/compact.rs @@ -1,6 +1,5 @@ use anyhow::Result; use anyhow::anyhow; -use codex_core::CodexThread; use codex_core::compact::SUMMARIZATION_PROMPT; use codex_core::compact::SUMMARY_PREFIX; use codex_core::config::Config; @@ -36,7 +35,6 @@ use core_test_support::responses; use core_test_support::responses::ev_reasoning_item; use core_test_support::responses::mount_models_once; use core_test_support::skip_if_no_network; -use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::local_selections; use core_test_support::test_codex::test_codex; use core_test_support::test_codex::turn_permission_fields; @@ -94,48 +92,6 @@ const REMOTE_V2_SUMMARY: &str = "global-instructions-remote-v2-summary"; pub(super) const COMPACT_WARNING_MESSAGE: &str = "Heads up: Long threads and multiple compactions can cause the model to be less accurate. Start a new thread when possible to keep threads small and targeted."; -async fn build_auto_compaction_disabled_codex(server: &MockServer) -> TestCodex { - let mut model_provider = non_openai_model_provider(server); - model_provider.stream_max_retries = Some(0); - test_codex() - .with_config(move |config| { - config.model_provider = model_provider; - set_test_compact_prompt(config); - config.model_context_window = Some(100); - config.model_auto_compact_token_limit = Some(90); - let _ = config.features.disable(Feature::AutoCompaction); - }) - .build(server) - .await - .expect("build codex") -} - -async fn submit_context_window_exceeded_turn(codex: &Arc, text: &str) { - codex - .submit(Op::UserInput { - items: vec![UserInput::Text { - text: text.to_string(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - responsesapi_client_metadata: None, - additional_context: Default::default(), - thread_settings: Default::default(), - }) - .await - .expect("submit context window exceeded turn"); - let error_message = wait_for_event_match(codex, |event| match event { - EventMsg::Error(err) => Some(err.message.clone()), - _ => None, - }) - .await; - wait_for_event(codex, |event| matches!(event, EventMsg::TurnComplete(_))).await; - assert!( - error_message.contains("ran out of room in the model's context window"), - "expected context window exceeded message, got {error_message}" - ); -} - fn ev_shell_command_call(call_id: &str, command: &str) -> serde_json::Value { ev_function_call( call_id, @@ -2320,93 +2276,6 @@ async fn pre_sampling_compact_runs_when_comp_hash_changes() { ); } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn auto_compaction_feature_disabled_skips_comp_hash_model_switch_compaction() { - skip_if_no_network!(); - - let server = MockServer::start().await; - let previous_model = "gpt-5.3-codex"; - let next_model = "gpt-5.2"; - - let models_mock = mount_models_once( - &server, - ModelsResponse { - models: vec![ - model_info_with_optional_comp_hash(previous_model, Some("hash-a")), - model_info_with_optional_comp_hash(next_model, Some("hash-b")), - ], - }, - ) - .await; - let request_log = mount_sse_sequence( - &server, - vec![ - sse(vec![ - ev_assistant_message("m1", "before switch"), - ev_completed_with_tokens("r1", /*total_tokens*/ 100), - ]), - sse(vec![ - ev_assistant_message("m2", "after switch"), - ev_completed_with_tokens("r2", /*total_tokens*/ 100), - ]), - ], - ) - .await; - let model_provider = non_openai_model_provider(&server); - let mut builder = test_codex() - .with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing()) - .with_model(previous_model) - .with_config(move |config| { - config.model_provider = model_provider; - set_test_compact_prompt(config); - let _ = config.features.disable(Feature::AutoCompaction); - }); - let test = builder.build(&server).await.expect("build test codex"); - - test.codex - .submit(disabled_permission_user_turn( - "before switch", - test.cwd.path().to_path_buf(), - previous_model.to_string(), - )) - .await - .expect("submit first user turn"); - wait_for_event(&test.codex, |event| { - matches!(event, EventMsg::TurnComplete(_)) - }) - .await; - test.codex - .submit(disabled_permission_user_turn( - "after switch", - test.cwd.path().to_path_buf(), - next_model.to_string(), - )) - .await - .expect("submit second user turn"); - wait_for_event(&test.codex, |event| { - matches!(event, EventMsg::TurnComplete(_)) - }) - .await; - - let requests = request_log.requests(); - assert_eq!(models_mock.requests().len(), 1); - assert_eq!( - requests.len(), - 2, - "disabled auto-compaction should skip compaction on a comp-hash model switch" - ); - let first = requests[0].body_json(); - let second = requests[1].body_json(); - assert_eq!(first["model"].as_str(), Some(previous_model)); - assert_eq!(second["model"].as_str(), Some(next_model)); - assert!(second.to_string().contains("before switch")); - assert!(second.to_string().contains("after switch")); - assert!( - !body_contains_text(&second.to_string(), SUMMARIZATION_PROMPT), - "disabled auto-compaction should preserve history instead of requesting a summary" - ); -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pre_sampling_compact_skips_when_either_comp_hash_is_missing() { skip_if_no_network!(); @@ -3786,45 +3655,6 @@ async fn snapshot_request_shape_mid_turn_continuation_compaction() { ); } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn auto_compaction_feature_disabled_skips_mid_turn_compaction() { - skip_if_no_network!(); - - let server = start_mock_server().await; - let over_limit_tokens = 100 * 95 / 100 + 1; - let first_turn = sse(vec![ - ev_function_call(DUMMY_CALL_ID, DUMMY_FUNCTION_NAME, "{}"), - ev_completed_with_tokens("r1", over_limit_tokens), - ]); - let request_log = mount_sse_sequence( - &server, - vec![ - first_turn, - sse_failed( - "response-failed", - "context_length_exceeded", - CONTEXT_LIMIT_MESSAGE, - ), - ], - ) - .await; - let test = build_auto_compaction_disabled_codex(&server).await; - - submit_context_window_exceeded_turn(&test.codex, FUNCTION_CALL_LIMIT_MSG).await; - - let requests = request_log.requests(); - assert_eq!(requests.len(), 2); - let continuation_request = &requests[1]; - continuation_request.function_call_output(DUMMY_CALL_ID); - assert!( - !body_contains_text( - &continuation_request.body_json().to_string(), - SUMMARIZATION_PROMPT - ), - "disabled auto-compaction should continue without a compaction request" - ); -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn auto_compact_clamps_config_limit_to_context_window() { skip_if_no_network!(); @@ -4658,44 +4488,6 @@ async fn snapshot_request_shape_pre_turn_compaction_context_window_exceeded() { ); } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn auto_compaction_feature_disabled_skips_pre_turn_compaction() { - skip_if_no_network!(); - - let server = start_mock_server().await; - let first_turn = sse(vec![ - ev_assistant_message("m1", FIRST_REPLY), - ev_completed_with_tokens("r1", /*total_tokens*/ 500), - ]); - let request_log = mount_sse_sequence( - &server, - vec![ - first_turn, - sse_failed( - "response-failed", - "context_length_exceeded", - CONTEXT_LIMIT_MESSAGE, - ), - ], - ) - .await; - let test = build_auto_compaction_disabled_codex(&server).await; - - test.submit_turn("USER_ONE") - .await - .expect("submit first turn"); - submit_context_window_exceeded_turn(&test.codex, "USER_TWO").await; - - let requests = request_log.requests(); - assert_eq!(requests.len(), 2); - let second_request_body = requests[1].body_json().to_string(); - assert!(second_request_body.contains("USER_TWO")); - assert!( - !body_contains_text(&second_request_body, SUMMARIZATION_PROMPT), - "disabled auto-compaction should sample without a pre-turn compaction request" - ); -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn snapshot_request_shape_manual_compact_without_previous_user_messages() { skip_if_no_network!(); diff --git a/codex-rs/core/tests/suite/token_budget.rs b/codex-rs/core/tests/suite/token_budget.rs index a4aac9d93..6d43b9037 100644 --- a/codex-rs/core/tests/suite/token_budget.rs +++ b/codex-rs/core/tests/suite/token_budget.rs @@ -903,51 +903,3 @@ async fn new_context_tool_starts_new_window_before_follow_up() -> Result<()> { Ok(()) } - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn auto_compaction_feature_disabled_hides_new_context_tool() -> Result<()> { - skip_if_no_network!(Ok(())); - - let server = start_mock_server().await; - let responses = mount_sse_sequence( - &server, - vec![sse(vec![ - ev_response_created("resp-1"), - ev_completed("resp-1"), - ])], - ) - .await; - let test = test_codex() - .with_config(|config| { - config.model_context_window = Some(CONFIGURED_CONTEXT_WINDOW); - config - .features - .enable(Feature::TokenBudget) - .expect("test config should allow token budget"); - config - .features - .disable(Feature::AutoCompaction) - .expect("test config should allow disabling auto-compaction"); - }) - .build(&server) - .await?; - - test.submit_turn("preserve the current context window") - .await?; - - let requests = responses.requests(); - assert_eq!(requests.len(), 1); - let tool_names = tool_names(&requests[0]); - assert!( - tool_names - .iter() - .any(|name| name == "get_context_remaining"), - "token budget should continue to expose get_context_remaining" - ); - assert!( - !tool_names.iter().any(|name| name == "new_context"), - "disabled auto-compaction should hide new_context" - ); - - Ok(()) -} diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index 86fdd2e29..9d3d3e1b4 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -235,8 +235,6 @@ pub enum Feature { RealtimeConversation, /// Prevent idle system sleep while a turn is actively running. PreventIdleSleep, - /// Enable automatic context compaction before or during a turn. - AutoCompaction, /// Enable remote compaction v2 over the normal Responses API. RemoteCompactionV2, /// Use Agent Identity for ChatGPT-authenticated sessions. @@ -1347,12 +1345,6 @@ pub const FEATURES: &[FeatureSpec] = &[ stage: Stage::Removed, default_enabled: false, }, - FeatureSpec { - id: Feature::AutoCompaction, - key: "auto_compaction", - stage: Stage::Stable, - default_enabled: true, - }, FeatureSpec { id: Feature::RemoteCompactionV2, key: "remote_compaction_v2",