Simplify prefix compaction history handling

This commit is contained in:
Rohit Arunachalam
2026-04-16 11:57:36 -07:00
parent bdd4370c21
commit 80947c1818
4 changed files with 5 additions and 136 deletions

View File

@@ -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

View File

@@ -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<ResponseItem>,
captured_context: Vec<ResponseItem>,
retained_suffix: Vec<ResponseItem>,
) -> Vec<ResponseItem> {
processed_prefix.extend(captured_context);
processed_prefix.extend(retained_suffix);
processed_prefix
}
pub(crate) fn build_compacted_history(
initial_context: Vec<ResponseItem>,
user_messages: &[String],

View File

@@ -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", "<permissions instructions>\nnew sandbox");
let suffix_user_context = input_message(
"user",
r#"<environment_context>
<cwd>/repo</cwd>
<shell>zsh</shell>
</environment_context>"#,
);
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,
]
);
}

View File

@@ -156,33 +156,6 @@ impl Respond for PrefixRaceCompactResponder {
}
}
#[derive(Clone, Debug)]
struct ModeAwareCompactResponder {
requests: StdArc<StdMutex<Vec<serde_json::Value>>>,
}
impl Respond for ModeAwareCompactResponder {
fn respond(&self, request: &wiremock::Request) -> ResponseTemplate {
let body = request
.body_json::<serde_json::Value>()
.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(())
}