Preserve empty user turns during contextual stripping

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charles Cunningham
2026-03-13 13:43:16 -07:00
co-authored by Codex
parent 85deecbd58
commit 55b9ad1490
3 changed files with 49 additions and 2 deletions
+29
View File
@@ -150,6 +150,35 @@ fn collect_user_messages_filters_ephemeral_context_entries() {
assert_eq!(vec!["real user message".to_string()], collected);
}
#[test]
fn collect_user_messages_preserves_empty_user_turns() {
let items = vec![
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: Vec::new(),
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: "real user message".to_string(),
}],
end_turn: None,
phase: None,
},
];
let collected = collect_user_messages(&items);
assert_eq!(
vec![String::new(), "real user message".to_string()],
collected
);
}
#[test]
fn build_token_limited_compacted_history_truncates_overlong_user_messages() {
// Use a small truncation limit so the test remains fast while still validating
+3 -2
View File
@@ -32,14 +32,15 @@ fn strip_ephemeral_context_prefix(message: &[ContentItem]) -> &[ContentItem] {
pub(crate) fn is_contextual_user_message_content(message: &[ContentItem]) -> bool {
let stripped = strip_ephemeral_context_prefix(message);
stripped.is_empty() || stripped.iter().any(is_contextual_user_fragment)
(stripped.len() != message.len() && stripped.is_empty())
|| stripped.iter().any(is_contextual_user_fragment)
}
fn parse_user_message(message: &[ContentItem]) -> Option<UserMessageItem> {
let message = strip_ephemeral_context_prefix(message);
if is_contextual_user_message_content(message) {
return None;
}
let message = strip_ephemeral_context_prefix(message);
let mut content: Vec<UserInput> = Vec::new();
+17
View File
@@ -263,6 +263,23 @@ fn drops_user_message_when_only_ephemeral_context_prefix_is_present() {
assert!(parse_turn_item(&item).is_none());
}
#[test]
fn parses_empty_user_message_as_user_turn() {
let item = ResponseItem::Message {
id: None,
role: "user".to_string(),
content: Vec::new(),
end_turn: None,
phase: None,
};
let turn_item = parse_turn_item(&item).expect("expected empty user message turn item");
let TurnItem::UserMessage(user_message) = turn_item else {
panic!("expected TurnItem::UserMessage");
};
assert_eq!(user_message.content, Vec::<UserInput>::new());
}
#[test]
fn parses_agent_message() {
let item = ResponseItem::Message {