diff --git a/codex-rs/core/src/context_manager/history.rs b/codex-rs/core/src/context_manager/history.rs index f80e2cb1cc..7de0cf9101 100644 --- a/codex-rs/core/src/context_manager/history.rs +++ b/codex-rs/core/src/context_manager/history.rs @@ -247,12 +247,13 @@ impl ContextManager { // These are local items added after the most recent model-emitted item. // They are not reflected in `last_token_usage.total_tokens`. + // If no model item has been emitted yet, treat the delta as empty. fn items_after_last_model_generated_item(&self) -> &[ResponseItem] { let start = self .items .iter() .rposition(is_model_generated_item) - .map_or(0, |index| index.saturating_add(1)); + .map_or(self.items.len(), |index| index.saturating_add(1)); &self.items[start..] } diff --git a/codex-rs/core/src/context_manager/history_tests.rs b/codex-rs/core/src/context_manager/history_tests.rs index 81a5983726..e4e5e36099 100644 --- a/codex-rs/core/src/context_manager/history_tests.rs +++ b/codex-rs/core/src/context_manager/history_tests.rs @@ -249,6 +249,31 @@ fn usage_breakdown_counts_no_items_after_last_model_generated_item() { ); } +#[test] +fn usage_breakdown_is_zero_without_model_generated_items() { + let mut history = create_history_with_items(vec![user_msg("no model output yet")]); + history.update_token_info( + &TokenUsage { + total_tokens: 100, + ..Default::default() + }, + None, + ); + + assert_eq!( + history + .get_total_token_usage_breakdown() + .estimated_tokens_of_items_added_since_last_successful_api_response, + 0 + ); + assert_eq!( + history + .get_total_token_usage_breakdown() + .estimated_bytes_of_items_added_since_last_successful_api_response, + 0 + ); +} + #[test] fn total_token_usage_includes_all_items_after_last_model_generated_item() { let mut history = create_history_with_items(vec![assistant_msg("already counted by API")]);