mirror of
https://github.com/openai/codex.git
synced 2026-05-17 17:53:06 +00:00
Reinject context for summary-only mid-turn compaction
This commit is contained in:
@@ -300,7 +300,7 @@ async fn run_compact_task_inner(
|
||||
// These callsites do not get a later post-compaction canonical-context write in
|
||||
// `run_turn`, so replacement history must carry canonical context directly.
|
||||
let initial_context = sess.build_initial_context(turn_context.as_ref()).await;
|
||||
insert_initial_context_before_last_real_user(&mut new_history, initial_context);
|
||||
insert_initial_context_before_last_user_anchor(&mut new_history, initial_context);
|
||||
}
|
||||
CompactCallsite::ManualCompact => {
|
||||
// Manual `/compact` intentionally rewrites transcript history without reseeding turn
|
||||
@@ -389,15 +389,27 @@ pub(crate) fn process_compacted_history(
|
||||
compacted_history
|
||||
}
|
||||
|
||||
pub(crate) fn insert_initial_context_before_last_real_user(
|
||||
pub(crate) fn insert_initial_context_before_last_user_anchor(
|
||||
compacted_history: &mut Vec<ResponseItem>,
|
||||
initial_context: Vec<ResponseItem>,
|
||||
) {
|
||||
if initial_context.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let Some(last_real_user_index) = compacted_history.iter().rposition(is_real_user_message) {
|
||||
compacted_history.splice(last_real_user_index..last_real_user_index, initial_context);
|
||||
let insertion_index = compacted_history
|
||||
.iter()
|
||||
.rposition(is_real_user_message)
|
||||
.or_else(|| {
|
||||
compacted_history.iter().rposition(|item| {
|
||||
matches!(
|
||||
crate::event_mapping::parse_turn_item(item),
|
||||
Some(TurnItem::UserMessage(user_message))
|
||||
if is_summary_message(&user_message.message())
|
||||
)
|
||||
})
|
||||
});
|
||||
if let Some(index) = insertion_index {
|
||||
compacted_history.splice(index..index, initial_context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1268,4 +1280,70 @@ keep me updated
|
||||
}];
|
||||
assert_eq!(refreshed, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_initial_context_before_last_user_anchor_falls_back_to_last_summary() {
|
||||
let mut compacted_history = vec![
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: format!("{SUMMARY_PREFIX}\nolder summary"),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: format!("{SUMMARY_PREFIX}\nlatest summary"),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
];
|
||||
let initial_context = vec![ResponseItem::Message {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: "fresh permissions".to_string(),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
}];
|
||||
|
||||
insert_initial_context_before_last_user_anchor(&mut compacted_history, initial_context);
|
||||
|
||||
let expected = vec![
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: format!("{SUMMARY_PREFIX}\nolder summary"),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: "fresh permissions".to_string(),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: format!("{SUMMARY_PREFIX}\nlatest summary"),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
];
|
||||
assert_eq!(compacted_history, expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::codex::TurnContext;
|
||||
use crate::compact::CompactCallsite;
|
||||
use crate::compact::extract_latest_model_switch_update_from_items;
|
||||
use crate::compact::extract_trailing_model_switch_update_for_compaction_request;
|
||||
use crate::compact::insert_initial_context_before_last_real_user;
|
||||
use crate::compact::insert_initial_context_before_last_user_anchor;
|
||||
use crate::compact::process_compacted_history;
|
||||
use crate::compact::should_keep_compacted_history_item;
|
||||
use crate::context_manager::ContextManager;
|
||||
@@ -162,7 +162,7 @@ async fn run_remote_compact_task_inner_impl(
|
||||
// These callsites do not get a later post-compaction canonical-context write in
|
||||
// `run_turn`, so replacement history must carry canonical context directly.
|
||||
let initial_context = sess.build_initial_context(turn_context.as_ref()).await;
|
||||
insert_initial_context_before_last_real_user(&mut new_history, initial_context);
|
||||
insert_initial_context_before_last_user_anchor(&mut new_history, initial_context);
|
||||
}
|
||||
CompactCallsite::ManualCompact => {
|
||||
// Manual `/compact` intentionally rewrites transcript history without reseeding turn
|
||||
|
||||
@@ -1790,7 +1790,7 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_summary_only_layout()
|
||||
insta::assert_snapshot!(
|
||||
"remote_mid_turn_compaction_summary_only_shapes",
|
||||
format_labeled_requests_snapshot(
|
||||
"Remote mid-turn compaction where compact output has only summary user content: continuation layout keeps the summary-only compact output without inserting extra context items.",
|
||||
"Remote mid-turn compaction where compact output has only summary user content: continuation layout reinjects canonical context before the latest summary.",
|
||||
&[
|
||||
("Remote Compaction Request", &compact_request),
|
||||
(
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
source: core/tests/suite/compact_remote.rs
|
||||
assertion_line: 1790
|
||||
expression: "format_labeled_requests_snapshot(\"Remote mid-turn compaction where compact output has only summary user content: continuation layout keeps the summary-only compact output without inserting extra context items.\",\n&[(\"Remote Compaction Request\", &compact_request),\n(\"Remote Post-Compaction History Layout\", &post_compact_turn_request),])"
|
||||
expression: "format_labeled_requests_snapshot(\"Remote mid-turn compaction where compact output has only summary user content: continuation layout reinjects canonical context before the latest summary.\",\n&[(\"Remote Compaction Request\", &compact_request),\n(\"Remote Post-Compaction History Layout\", &post_compact_turn_request),])"
|
||||
---
|
||||
Scenario: Remote mid-turn compaction where compact output has only summary user content: continuation layout keeps the summary-only compact output without inserting extra context items.
|
||||
Scenario: Remote mid-turn compaction where compact output has only summary user content: continuation layout reinjects canonical context before the latest summary.
|
||||
|
||||
## Remote Compaction Request
|
||||
00:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
@@ -14,4 +13,7 @@ Scenario: Remote mid-turn compaction where compact output has only summary user
|
||||
05:function_call_output:unsupported call: test_tool
|
||||
|
||||
## Remote Post-Compaction History Layout
|
||||
00:message/user:<COMPACTION_SUMMARY>\nREMOTE_SUMMARY_ONLY
|
||||
00:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
01:message/user:<AGENTS_MD>
|
||||
02:message/user:<ENVIRONMENT_CONTEXT:cwd=<CWD>>
|
||||
03:message/user:<COMPACTION_SUMMARY>\nREMOTE_SUMMARY_ONLY
|
||||
|
||||
Reference in New Issue
Block a user