diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index da52c850c1..d08722966b 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -5623,6 +5623,7 @@ mod tests { None, SessionSource::Exec, base_instructions, + Vec::new(), ), None, None, diff --git a/codex-rs/core/src/rollout/truncation.rs b/codex-rs/core/src/rollout/truncation.rs index b1adf9cd80..f389d4ed81 100644 --- a/codex-rs/core/src/rollout/truncation.rs +++ b/codex-rs/core/src/rollout/truncation.rs @@ -210,6 +210,7 @@ pub(crate) fn apply_rollbacks_to_rollout(items: &[RolloutItem]) -> Vec ResponseItem { + ResponseItem::Message { + id: None, + role: "user".to_string(), + content: vec![ContentItem::InputText { + text: text.to_string(), + }], + end_turn: None, + } + } + #[test] fn truncates_rollout_from_start_before_nth_user_only() { let items = [ @@ -326,6 +338,55 @@ mod tests { ); } + #[test] + fn effective_user_turns_use_replacement_history_for_compaction() { + let rollout_items = vec![ + RolloutItem::ResponseItem(user_input_msg("u1")), + RolloutItem::ResponseItem(assistant_msg("a1")), + RolloutItem::Compacted(CompactedItem { + message: "ignored summary".to_string(), + replacement_history: Some(vec![ + user_input_msg("r1"), + assistant_msg("ra1"), + user_input_msg("r2"), + ]), + }), + RolloutItem::ResponseItem(user_input_msg("u2")), + ]; + + let turns = effective_user_turns(&rollout_items); + let texts: Vec = turns.iter().map(|turn| turn.text.clone()).collect(); + assert_eq!( + texts, + vec!["r1".to_string(), "r2".to_string(), "u2".to_string()] + ); + + let indices: Vec = turns.iter().map(|turn| turn.source_index).collect(); + assert_eq!(indices, vec![2, 2, 3]); + } + + #[test] + fn effective_user_turns_use_placeholder_when_summary_empty() { + let rollout_items = vec![ + RolloutItem::ResponseItem(user_input_msg("u1")), + RolloutItem::ResponseItem(assistant_msg("a1")), + RolloutItem::Compacted(CompactedItem { + message: String::new(), + replacement_history: None, + }), + ]; + + let turns = effective_user_turns(&rollout_items); + let texts: Vec = turns.iter().map(|turn| turn.text.clone()).collect(); + assert_eq!( + texts, + vec!["u1".to_string(), "(no summary available)".to_string()] + ); + + let indices: Vec = turns.iter().map(|turn| turn.source_index).collect(); + assert_eq!(indices, vec![0, 2]); + } + #[tokio::test] async fn ignores_session_prefix_messages_when_truncating_rollout_from_start() { let (session, turn_context) = make_session_and_context().await;