Move previous turn context tracking into ContextManager history (#12179)

## Summary
- add `previous_context_item: Option<TurnContextItem>` to
`ContextManager`
- expose session/state accessors for reading and updating the stored
previous context item
- switch settings diffing to use `TurnContextItem` instead of
`TurnContext`
- remove submission-loop local `previous_context` and persist the
previous context item in history

## Testing
- `just fmt`
- `just fix -p codex-core`
- `cargo test -p codex-core --test all model_switching::`
- `cargo test -p codex-core --test all collaboration_instructions::`
- `cargo test -p codex-core --test all personality::`
- `cargo test -p codex-core --test all
permissions_messages::permissions_message_not_added_when_no_change`
This commit is contained in:
Charley Cunningham
2026-02-19 09:56:20 -08:00
committed by GitHub
parent f6fd4cb3f5
commit f2d5842ed1
6 changed files with 103 additions and 66 deletions

View File

@@ -18,6 +18,7 @@ use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::InputModality;
use codex_protocol::protocol::TokenUsage;
use codex_protocol::protocol::TokenUsageInfo;
use codex_protocol::protocol::TurnContextItem;
use std::ops::Deref;
/// Transcript of thread history
@@ -26,6 +27,12 @@ pub(crate) struct ContextManager {
/// The oldest items are at the beginning of the vector.
items: Vec<ResponseItem>,
token_info: Option<TokenUsageInfo>,
/// Previous turn context snapshot used for diffing context and producing
/// model-visible settings update items.
///
/// When this is `None`, settings diffing treats the next turn as having no
/// baseline and emits a full reinjection of context state.
previous_context_item: Option<TurnContextItem>,
}
#[derive(Debug, Clone, Copy, Default)]
@@ -41,6 +48,7 @@ impl ContextManager {
Self {
items: Vec::new(),
token_info: TokenUsageInfo::new_or_append(&None, &None, None),
previous_context_item: None,
}
}
@@ -52,6 +60,14 @@ impl ContextManager {
self.token_info = info;
}
pub(crate) fn set_previous_context_item(&mut self, item: Option<TurnContextItem>) {
self.previous_context_item = item;
}
pub(crate) fn previous_context_item(&self) -> Option<TurnContextItem> {
self.previous_context_item.clone()
}
pub(crate) fn set_token_usage_full(&mut self, context_window: i64) {
match &mut self.token_info {
Some(info) => info.fill_to_context_window(context_window),

View File

@@ -6,26 +6,27 @@ use codex_protocol::config_types::Personality;
use codex_protocol::models::DeveloperInstructions;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ModelInfo;
use codex_protocol::protocol::TurnContextItem;
fn build_environment_update_item(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
next: &TurnContext,
shell: &Shell,
) -> Option<ResponseItem> {
let prev = previous?;
let prev_context = EnvironmentContext::from_turn_context(prev, shell);
let prev_context = EnvironmentContext::from_turn_context_item(prev, shell);
let next_context = EnvironmentContext::from_turn_context(next, shell);
if prev_context.equals_except_shell(&next_context) {
return None;
}
Some(ResponseItem::from(EnvironmentContext::diff(
prev, next, shell,
)))
Some(ResponseItem::from(
EnvironmentContext::diff_from_turn_context_item(prev, next, shell),
))
}
fn build_permissions_update_item(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
next: &TurnContext,
exec_policy: &Policy,
) -> Option<ResponseItem> {
@@ -46,11 +47,11 @@ fn build_permissions_update_item(
}
fn build_collaboration_mode_update_item(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
next: &TurnContext,
) -> Option<ResponseItem> {
let prev = previous?;
if prev.collaboration_mode != next.collaboration_mode {
if prev.collaboration_mode.as_ref() != Some(&next.collaboration_mode) {
// If the next mode has empty developer instructions, this returns None and we emit no
// update, so prior collaboration instructions remain in the prompt history.
Some(DeveloperInstructions::from_collaboration_mode(&next.collaboration_mode)?.into())
@@ -60,7 +61,7 @@ fn build_collaboration_mode_update_item(
}
fn build_personality_update_item(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
next: &TurnContext,
personality_feature_enabled: bool,
) -> Option<ResponseItem> {
@@ -68,7 +69,7 @@ fn build_personality_update_item(
return None;
}
let previous = previous?;
if next.model_info.slug != previous.model_info.slug {
if next.model_info.slug != previous.model {
return None;
}
@@ -96,12 +97,11 @@ pub(crate) fn personality_message_for(
}
pub(crate) fn build_model_instructions_update_item(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
resumed_model: Option<&str>,
next: &TurnContext,
) -> Option<ResponseItem> {
let previous_model =
resumed_model.or_else(|| previous.map(|prev| prev.model_info.slug.as_str()))?;
let previous_model = resumed_model.or_else(|| previous.map(|prev| prev.model.as_str()))?;
if previous_model == next.model_info.slug {
return None;
}
@@ -115,7 +115,7 @@ pub(crate) fn build_model_instructions_update_item(
}
pub(crate) fn build_settings_update_items(
previous: Option<&TurnContext>,
previous: Option<&TurnContextItem>,
resumed_model: Option<&str>,
next: &TurnContext,
shell: &Shell,