mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
[codex-core] Preserve ghost snapshots in compaction fallback [ci changed_files]
Keep same-turn ghost snapshots when pre-turn inline compaction downgrades to the legacy client-side path so undo state survives compatibility fallback. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -5990,6 +5990,20 @@ struct PreTurnInlineCompactionState {
|
||||
turn_context_item: TurnContextItem,
|
||||
}
|
||||
|
||||
fn collect_new_ghost_snapshots_since(
|
||||
history_before_turn: &[ResponseItem],
|
||||
current_history: &[ResponseItem],
|
||||
) -> Vec<ResponseItem> {
|
||||
current_history
|
||||
.iter()
|
||||
.filter(|item| {
|
||||
matches!(item, ResponseItem::GhostSnapshot { .. })
|
||||
&& !history_before_turn.contains(item)
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn record_compaction_metric(
|
||||
sess: &Session,
|
||||
mode: &'static str,
|
||||
@@ -6127,8 +6141,17 @@ async fn downgrade_known_inline_compaction_error(
|
||||
let Some(preturn_state) = preturn_state else {
|
||||
return Ok(false);
|
||||
};
|
||||
// Preserve same-turn ghost snapshots that may have completed after
|
||||
// the pre-turn baseline was captured so `/undo` still works after
|
||||
// we downgrade to the legacy compaction path.
|
||||
let current_history = sess.clone_history().await;
|
||||
let mut restored_history = preturn_state.history_before_turn.clone();
|
||||
restored_history.extend(collect_new_ghost_snapshots_since(
|
||||
&preturn_state.history_before_turn,
|
||||
current_history.raw_items(),
|
||||
));
|
||||
sess.replace_history(
|
||||
preturn_state.history_before_turn.clone(),
|
||||
restored_history,
|
||||
preturn_state.reference_context_before_turn.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -55,6 +55,7 @@ use crate::tools::registry::ToolHandler;
|
||||
use crate::tools::router::ToolCallSource;
|
||||
use crate::turn_diff_tracker::TurnDiffTracker;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_git::GhostCommit;
|
||||
use codex_otel::TelemetryAuthMode;
|
||||
use codex_protocol::models::BaseInstructions;
|
||||
use codex_protocol::models::ContentItem;
|
||||
@@ -136,6 +137,12 @@ fn skill_message(text: &str) -> ResponseItem {
|
||||
}
|
||||
}
|
||||
|
||||
fn ghost_snapshot(id: &str) -> ResponseItem {
|
||||
ResponseItem::GhostSnapshot {
|
||||
ghost_commit: GhostCommit::new(id.to_string(), None, Vec::new(), Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn developer_input_texts(items: &[ResponseItem]) -> Vec<&str> {
|
||||
items
|
||||
.iter()
|
||||
@@ -253,6 +260,24 @@ fn assistant_message_stream_parsers_seed_plan_parser_across_added_and_delta_boun
|
||||
assert!(tail.plan_segments.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_new_ghost_snapshots_since_returns_only_snapshots_added_after_turn_start() {
|
||||
let prior_snapshot = ghost_snapshot("ghost-before");
|
||||
let same_turn_snapshot = ghost_snapshot("ghost-during");
|
||||
let history_before_turn = vec![user_message("earlier"), prior_snapshot.clone()];
|
||||
let current_history = vec![
|
||||
user_message("earlier"),
|
||||
prior_snapshot,
|
||||
user_message("current turn"),
|
||||
assistant_message("in progress"),
|
||||
same_turn_snapshot.clone(),
|
||||
];
|
||||
|
||||
let new_snapshots = collect_new_ghost_snapshots_since(&history_before_turn, ¤t_history);
|
||||
|
||||
assert_eq!(new_snapshots, vec![same_turn_snapshot]);
|
||||
}
|
||||
|
||||
fn make_mcp_tool(
|
||||
server_name: &str,
|
||||
tool_name: &str,
|
||||
|
||||
Reference in New Issue
Block a user