From 80947c18182d7d6c9fcc3f20f5409dbdd4ef02ac Mon Sep 17 00:00:00 2001 From: Rohit Arunachalam Date: Thu, 16 Apr 2026 11:57:36 -0700 Subject: [PATCH] Simplify prefix compaction history handling --- codex-rs/core/src/codex.rs | 8 +- codex-rs/core/src/compact.rs | 16 ---- codex-rs/core/src/compact_tests.rs | 86 --------------------- codex-rs/core/tests/suite/compact_remote.rs | 31 +------- 4 files changed, 5 insertions(+), 136 deletions(-) diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index a49c13cbff..04f14c3293 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -6832,11 +6832,9 @@ async fn apply_prefix_compact_candidate( .reference_context_item() .await .or(candidate.captured_reference_context_item); - let mut new_history = compact::build_prefix_compacted_history( - candidate.replacement_prefix, - candidate.captured_context, - retained_suffix, - ); + let mut new_history = candidate.replacement_prefix; + new_history.extend(candidate.captured_context); + new_history.extend(retained_suffix); new_history.extend( current_items diff --git a/codex-rs/core/src/compact.rs b/codex-rs/core/src/compact.rs index a104a3075c..580713ab4d 100644 --- a/codex-rs/core/src/compact.rs +++ b/codex-rs/core/src/compact.rs @@ -481,22 +481,6 @@ pub(crate) fn insert_initial_context_before_last_real_user_or_summary( compacted_history } -/// Builds prefix-compaction replacement history from a processed compacted prefix, the context -/// captured when that prefix snapshot was taken, and the live retained suffix. -/// -/// The prefix has already gone through the same retention filtering as classic remote compaction. -/// The captured context is inserted immediately after the prefix so the untouched suffix remains -/// under the same chronological context state that existed when the suffix began. -pub(crate) fn build_prefix_compacted_history( - mut processed_prefix: Vec, - captured_context: Vec, - retained_suffix: Vec, -) -> Vec { - processed_prefix.extend(captured_context); - processed_prefix.extend(retained_suffix); - processed_prefix -} - pub(crate) fn build_compacted_history( initial_context: Vec, user_messages: &[String], diff --git a/codex-rs/core/src/compact_tests.rs b/codex-rs/core/src/compact_tests.rs index b93fe7d17f..74154f6d3d 100644 --- a/codex-rs/core/src/compact_tests.rs +++ b/codex-rs/core/src/compact_tests.rs @@ -23,30 +23,6 @@ async fn process_compacted_history_with_test_session( (refreshed, initial_context) } -fn input_message(role: &str, text: &str) -> ResponseItem { - ResponseItem::Message { - id: None, - role: role.to_string(), - content: vec![ContentItem::InputText { - text: text.to_string(), - }], - end_turn: None, - phase: None, - } -} - -fn output_message(text: &str) -> ResponseItem { - ResponseItem::Message { - id: None, - role: "assistant".to_string(), - content: vec![ContentItem::OutputText { - text: text.to_string(), - }], - end_turn: None, - phase: None, - } -} - #[test] fn remote_compact_task_supports_openai_provider() { let provider = ModelProviderInfo::create_openai_provider(/*base_url*/ None); @@ -621,65 +597,3 @@ fn insert_initial_context_before_last_real_user_or_summary_keeps_compaction_last ]; assert_eq!(refreshed, expected); } - -#[test] -fn build_prefix_compacted_history_inserts_captured_context_after_prefix() { - let prefix_user = input_message("user", "older user in compacted prefix"); - let captured_developer = input_message("developer", "captured permissions"); - let captured_user = input_message("user", "captured environment"); - let suffix_assistant = output_message("working through suffix"); - let suffix_user = input_message("user", "latest user in retained suffix"); - - let refreshed = build_prefix_compacted_history( - vec![prefix_user.clone()], - vec![captured_developer.clone(), captured_user.clone()], - vec![suffix_assistant.clone(), suffix_user.clone()], - ); - - assert_eq!( - refreshed, - vec![ - prefix_user, - captured_developer, - captured_user, - suffix_assistant, - suffix_user, - ] - ); -} - -#[test] -fn build_prefix_compacted_history_preserves_suffix_context_items() { - let prefix_user = input_message("user", "older user in compacted prefix"); - let captured_context = input_message("developer", "captured permissions"); - let suffix_developer = input_message("developer", "\nnew sandbox"); - let suffix_user_context = input_message( - "user", - r#" - /repo - zsh -"#, - ); - let suffix_assistant = output_message("continuing after context change"); - - let refreshed = build_prefix_compacted_history( - vec![prefix_user.clone()], - vec![captured_context.clone()], - vec![ - suffix_developer.clone(), - suffix_user_context.clone(), - suffix_assistant.clone(), - ], - ); - - assert_eq!( - refreshed, - vec![ - prefix_user, - captured_context, - suffix_developer, - suffix_user_context, - suffix_assistant, - ] - ); -} diff --git a/codex-rs/core/tests/suite/compact_remote.rs b/codex-rs/core/tests/suite/compact_remote.rs index 3f68e7ea9f..08e64b8ed4 100644 --- a/codex-rs/core/tests/suite/compact_remote.rs +++ b/codex-rs/core/tests/suite/compact_remote.rs @@ -156,33 +156,6 @@ impl Respond for PrefixRaceCompactResponder { } } -#[derive(Clone, Debug)] -struct ModeAwareCompactResponder { - requests: StdArc>>, -} - -impl Respond for ModeAwareCompactResponder { - fn respond(&self, request: &wiremock::Request) -> ResponseTemplate { - let body = request - .body_json::() - .expect("compact request body should be JSON"); - let prefix_mode = body.get("mode").and_then(serde_json::Value::as_str) == Some("prefix"); - self.requests - .lock() - .expect("request lock poisoned") - .push(body); - - let summary = if prefix_mode { - "PREFIX_SUMMARY" - } else { - "NORMAL_FALLBACK_SUMMARY" - }; - ResponseTemplate::new(200) - .insert_header("content-type", "application/json") - .set_body_json(json!({ "output": compacted_summary_only_output(summary) })) - } -} - fn remote_realtime_test_codex_builder( realtime_server: &responses::WebSocketTestServer, ) -> TestCodexBuilder { @@ -1330,7 +1303,7 @@ async fn oversized_prefix_snapshot_skips_prefix_compact_request() -> Result<()> let compact_requests = StdArc::new(StdMutex::new(Vec::new())); Mock::given(method("POST")) .and(path_regex(".*/responses/compact$")) - .respond_with(ModeAwareCompactResponder { + .respond_with(PrefixRaceCompactResponder { requests: StdArc::clone(&compact_requests), }) .up_to_n_times(1) @@ -1385,7 +1358,7 @@ async fn oversized_prefix_snapshot_skips_prefix_compact_request() -> Result<()> assert_eq!(requests.len(), 3); let third_request_body = requests[2].body_json().to_string(); assert!(third_request_body.contains("NORMAL_FALLBACK_SUMMARY")); - assert!(!third_request_body.contains("PREFIX_SUMMARY")); + assert!(!third_request_body.contains("PREFIX_STALE_SUMMARY")); Ok(()) }