clean: all history cloning (#8916)

This commit is contained in:
jif-oai
2026-01-08 18:17:18 +00:00
committed by GitHub
parent c4af304c77
commit 69898e3dba
6 changed files with 84 additions and 89 deletions

View File

@@ -67,17 +67,18 @@ impl ContextManager {
}
}
pub(crate) fn get_history(&mut self) -> Vec<ResponseItem> {
/// Returns the history prepared for sending to the model. This applies a proper
/// normalization and drop un-suited items.
pub(crate) fn for_prompt(mut self) -> Vec<ResponseItem> {
self.normalize_history();
self.contents()
self.items
.retain(|item| !matches!(item, ResponseItem::GhostSnapshot { .. }));
self.items
}
// Returns the history prepared for sending to the model.
// With extra response items filtered out and GhostCommits removed.
pub(crate) fn get_history_for_prompt(&mut self) -> Vec<ResponseItem> {
let mut history = self.get_history();
Self::remove_ghost_snapshots(&mut history);
history
/// Returns raw items in the history.
pub(crate) fn raw_items(&self) -> &[ResponseItem] {
&self.items
}
// Estimate token usage using byte-based heuristics from the truncation helpers.
@@ -168,9 +169,7 @@ impl ContextManager {
return;
}
// Keep behavior consistent with call sites that previously operated on `get_history()`:
// normalize first (call/output invariants), then truncate based on the normalized view.
let snapshot = self.get_history();
let snapshot = self.items.clone();
let user_positions = user_message_positions(&snapshot);
let Some(&first_user_idx) = user_positions.first() else {
self.replace(snapshot);
@@ -250,15 +249,6 @@ impl ContextManager {
normalize::remove_orphan_outputs(&mut self.items);
}
/// Returns a clone of the contents in the transcript.
fn contents(&self) -> Vec<ResponseItem> {
self.items.clone()
}
fn remove_ghost_snapshots(items: &mut Vec<ResponseItem>) {
items.retain(|item| !matches!(item, ResponseItem::GhostSnapshot { .. }));
}
fn process_item(&self, item: &ResponseItem, policy: TruncationPolicy) -> ResponseItem {
let policy_with_serialization_budget = policy.mul(1.2);
match item {

View File

@@ -101,7 +101,7 @@ fn filters_non_api_messages() {
let a = assistant_msg("hello");
h.record_items([&u, &a], policy);
let items = h.contents();
let items = h.raw_items();
assert_eq!(
items,
vec![
@@ -160,8 +160,8 @@ fn get_history_for_prompt_drops_ghost_commits() {
let items = vec![ResponseItem::GhostSnapshot {
ghost_commit: GhostCommit::new("ghost-1".to_string(), None, Vec::new(), Vec::new()),
}];
let mut history = create_history_with_items(items);
let filtered = history.get_history_for_prompt();
let history = create_history_with_items(items);
let filtered = history.for_prompt();
assert_eq!(filtered, vec![]);
}
@@ -184,7 +184,7 @@ fn remove_first_item_removes_matching_output_for_function_call() {
];
let mut h = create_history_with_items(items);
h.remove_first_item();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[test]
@@ -206,7 +206,7 @@ fn remove_first_item_removes_matching_call_for_output() {
];
let mut h = create_history_with_items(items);
h.remove_first_item();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[test]
@@ -234,7 +234,7 @@ fn remove_first_item_handles_local_shell_pair() {
];
let mut h = create_history_with_items(items);
h.remove_first_item();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[test]
@@ -250,7 +250,7 @@ fn drop_last_n_user_turns_preserves_prefix() {
let mut history = create_history_with_items(items);
history.drop_last_n_user_turns(1);
assert_eq!(
history.get_history(),
history.for_prompt(),
vec![
assistant_msg("session prefix item"),
user_msg("u1"),
@@ -267,7 +267,7 @@ fn drop_last_n_user_turns_preserves_prefix() {
]);
history.drop_last_n_user_turns(99);
assert_eq!(
history.get_history(),
history.for_prompt(),
vec![assistant_msg("session prefix item")]
);
}
@@ -307,7 +307,7 @@ fn drop_last_n_user_turns_ignores_session_prefix_user_messages() {
assistant_msg("turn 1 assistant"),
];
assert_eq!(history.get_history(), expected_prefix_and_first_turn);
assert_eq!(history.for_prompt(), expected_prefix_and_first_turn);
let expected_prefix_only = vec![
user_input_text_msg("<environment_context>ctx</environment_context>"),
@@ -337,7 +337,7 @@ fn drop_last_n_user_turns_ignores_session_prefix_user_messages() {
assistant_msg("turn 2 assistant"),
]);
history.drop_last_n_user_turns(2);
assert_eq!(history.get_history(), expected_prefix_only);
assert_eq!(history.for_prompt(), expected_prefix_only);
let mut history = create_history_with_items(vec![
user_input_text_msg("<environment_context>ctx</environment_context>"),
@@ -355,7 +355,7 @@ fn drop_last_n_user_turns_ignores_session_prefix_user_messages() {
assistant_msg("turn 2 assistant"),
]);
history.drop_last_n_user_turns(3);
assert_eq!(history.get_history(), expected_prefix_only);
assert_eq!(history.for_prompt(), expected_prefix_only);
}
#[test]
@@ -375,7 +375,7 @@ fn remove_first_item_handles_custom_tool_pair() {
];
let mut h = create_history_with_items(items);
h.remove_first_item();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[test]
@@ -402,8 +402,8 @@ fn normalization_retains_local_shell_outputs() {
},
];
let mut history = create_history_with_items(items.clone());
let normalized = history.get_history();
let history = create_history_with_items(items.clone());
let normalized = history.for_prompt();
assert_eq!(normalized, items);
}
@@ -607,7 +607,7 @@ fn normalize_adds_missing_output_for_function_call() {
h.normalize_history();
assert_eq!(
h.contents(),
h.raw_items(),
vec![
ResponseItem::FunctionCall {
id: None,
@@ -641,7 +641,7 @@ fn normalize_adds_missing_output_for_custom_tool_call() {
h.normalize_history();
assert_eq!(
h.contents(),
h.raw_items(),
vec![
ResponseItem::CustomToolCall {
id: None,
@@ -678,7 +678,7 @@ fn normalize_adds_missing_output_for_local_shell_call_with_id() {
h.normalize_history();
assert_eq!(
h.contents(),
h.raw_items(),
vec![
ResponseItem::LocalShellCall {
id: None,
@@ -717,7 +717,7 @@ fn normalize_removes_orphan_function_call_output() {
h.normalize_history();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[cfg(not(debug_assertions))]
@@ -731,7 +731,7 @@ fn normalize_removes_orphan_custom_tool_call_output() {
h.normalize_history();
assert_eq!(h.contents(), vec![]);
assert_eq!(h.raw_items(), vec![]);
}
#[cfg(not(debug_assertions))]
@@ -780,7 +780,7 @@ fn normalize_mixed_inserts_and_removals() {
h.normalize_history();
assert_eq!(
h.contents(),
h.raw_items(),
vec![
ResponseItem::FunctionCall {
id: None,
@@ -840,7 +840,7 @@ fn normalize_adds_missing_output_for_function_call_inserts_output() {
let mut h = create_history_with_items(items);
h.normalize_history();
assert_eq!(
h.contents(),
h.raw_items(),
vec![
ResponseItem::FunctionCall {
id: None,