Skip to content

Commit 258153b

Browse files
committed
Persist TurnContext after full-context reinjection
1 parent 37cacb2 commit 258153b

File tree

1 file changed

+87
-5
lines changed

1 file changed

+87
-5
lines changed

codex-rs/core/src/codex.rs

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,14 +2705,15 @@ impl Session {
27052705
self.record_conversation_items(turn_context, &context_items)
27062706
.await;
27072707
}
2708-
if previous_user_turn_model.is_none()
2709-
|| (!should_inject_full_context && !context_items.is_empty())
2708+
if should_inject_full_context
2709+
|| previous_user_turn_model.is_none()
2710+
|| !context_items.is_empty()
27102711
{
2711-
// Keep rollout TurnContext entries to:
2712+
// Keep rollout TurnContext entries for any turn that establishes or changes the
2713+
// persisted model-visible baseline:
27122714
// - the first real user turn (to recover `previous_model` on resume)
2715+
// - full-context reinjection after the baseline was cleared
27132716
// - steady-state turns that emitted explicit context diffs
2714-
// Full reinjection after compaction is tracked in runtime state only; resume will
2715-
// conservatively fall back to a missing baseline and reinject again if needed.
27162717
self.persist_rollout_items(&[RolloutItem::TurnContext(turn_context_item.clone())])
27172718
.await;
27182719
}
@@ -5952,6 +5953,10 @@ mod tests {
59525953
use crate::protocol::TokenCountEvent;
59535954
use crate::protocol::TokenUsage;
59545955
use crate::protocol::TokenUsageInfo;
5956+
use crate::protocol::UserMessageEvent;
5957+
use crate::rollout::policy::EventPersistenceMode;
5958+
use crate::rollout::recorder::RolloutRecorder;
5959+
use crate::rollout::recorder::RolloutRecorderParams;
59555960
use crate::state::TaskKind;
59565961
use crate::tasks::SessionTask;
59575962
use crate::tasks::SessionTaskContext;
@@ -7978,6 +7983,83 @@ mod tests {
79787983
);
79797984
}
79807985

7986+
#[tokio::test]
7987+
async fn record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout()
7988+
{
7989+
let (session, previous_context) = make_session_and_context().await;
7990+
let next_model = if previous_context.model_info.slug == "gpt-5.1" {
7991+
"gpt-5"
7992+
} else {
7993+
"gpt-5.1"
7994+
};
7995+
let turn_context = previous_context
7996+
.with_model(next_model.to_string(), &session.services.models_manager)
7997+
.await;
7998+
let config = session.get_config().await;
7999+
let recorder = RolloutRecorder::new(
8000+
config.as_ref(),
8001+
RolloutRecorderParams::new(
8002+
ThreadId::default(),
8003+
None,
8004+
SessionSource::Exec,
8005+
BaseInstructions::default(),
8006+
Vec::new(),
8007+
EventPersistenceMode::Limited,
8008+
),
8009+
None,
8010+
None,
8011+
)
8012+
.await
8013+
.expect("create rollout recorder");
8014+
let rollout_path = recorder.rollout_path().to_path_buf();
8015+
{
8016+
let mut rollout = session.services.rollout.lock().await;
8017+
*rollout = Some(recorder);
8018+
}
8019+
8020+
session
8021+
.persist_rollout_items(&[RolloutItem::EventMsg(EventMsg::UserMessage(
8022+
UserMessageEvent {
8023+
message: "seed rollout".to_string(),
8024+
images: None,
8025+
local_images: Vec::new(),
8026+
text_elements: Vec::new(),
8027+
},
8028+
))])
8029+
.await;
8030+
{
8031+
let mut state = session.state.lock().await;
8032+
state.set_reference_context_item(None);
8033+
}
8034+
8035+
session
8036+
.record_context_updates_and_set_reference_context_item(
8037+
&turn_context,
8038+
Some(previous_context.model_info.slug.as_str()),
8039+
)
8040+
.await;
8041+
session.ensure_rollout_materialized().await;
8042+
session.flush_rollout().await;
8043+
8044+
let InitialHistory::Resumed(resumed) = RolloutRecorder::get_rollout_history(&rollout_path)
8045+
.await
8046+
.expect("read rollout history")
8047+
else {
8048+
panic!("expected resumed rollout history");
8049+
};
8050+
let persisted_turn_context = resumed.history.iter().find_map(|item| match item {
8051+
RolloutItem::TurnContext(ctx) => Some(ctx.clone()),
8052+
_ => None,
8053+
});
8054+
8055+
assert_eq!(
8056+
serde_json::to_value(persisted_turn_context)
8057+
.expect("serialize persisted turn context item"),
8058+
serde_json::to_value(Some(turn_context.to_turn_context_item()))
8059+
.expect("serialize expected turn context item")
8060+
);
8061+
}
8062+
79818063
#[tokio::test]
79828064
async fn run_user_shell_command_does_not_set_reference_context_item() {
79838065
let (session, _turn_context, rx) = make_session_and_context_with_rx().await;

0 commit comments

Comments
 (0)