mirror of
https://github.com/openai/codex.git
synced 2026-03-24 00:56:34 +03:00
Compare commits
4 Commits
dev/cc/exp
...
cc/referen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec9e0d355a | ||
|
|
98371b3632 | ||
|
|
145932ba5d | ||
|
|
57deac7dfa |
@@ -2121,14 +2121,13 @@ impl Session {
|
||||
InitialHistory::New => {
|
||||
// Defer initial context insertion until the first real turn starts so
|
||||
// turn/start overrides can be merged before we write model-visible context.
|
||||
self.set_previous_turn_settings(/*previous_turn_settings*/ None)
|
||||
.await;
|
||||
self.reset_reference_turn_context_state().await;
|
||||
}
|
||||
InitialHistory::Resumed(resumed_history) => {
|
||||
let rollout_items = resumed_history.history;
|
||||
let previous_turn_settings = self
|
||||
.apply_rollout_reconstruction(&turn_context, &rollout_items)
|
||||
self.apply_rollout_reconstruction(&turn_context, &rollout_items)
|
||||
.await;
|
||||
let previous_turn_settings = self.previous_turn_settings().await;
|
||||
|
||||
// If resuming, warn when the last recorded model differs from the current one.
|
||||
let curr: &str = turn_context.model_info.slug.as_str();
|
||||
@@ -2185,7 +2184,7 @@ impl Session {
|
||||
.await;
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
state.set_reference_context_item(Some(turn_context.to_turn_context_item()));
|
||||
state.note_model_visible_turn_context(turn_context.to_turn_context_item());
|
||||
}
|
||||
|
||||
// Forked threads should remain file-backed immediately after startup.
|
||||
@@ -2203,19 +2202,15 @@ impl Session {
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
rollout_items: &[RolloutItem],
|
||||
) -> Option<PreviousTurnSettings> {
|
||||
) {
|
||||
let reconstructed_rollout = self
|
||||
.reconstruct_history_from_rollout(turn_context, rollout_items)
|
||||
.await;
|
||||
let previous_turn_settings = reconstructed_rollout.previous_turn_settings.clone();
|
||||
self.replace_history(
|
||||
let mut state = self.state.lock().await;
|
||||
state.replace_history_with_reference_turn_context_state(
|
||||
reconstructed_rollout.history,
|
||||
reconstructed_rollout.reference_context_item,
|
||||
)
|
||||
.await;
|
||||
self.set_previous_turn_settings(previous_turn_settings.clone())
|
||||
.await;
|
||||
previous_turn_settings
|
||||
reconstructed_rollout.reference_turn_context_state,
|
||||
);
|
||||
}
|
||||
|
||||
fn last_token_info_from_rollout(rollout_items: &[RolloutItem]) -> Option<TokenUsageInfo> {
|
||||
@@ -2230,12 +2225,14 @@ impl Session {
|
||||
state.previous_turn_settings()
|
||||
}
|
||||
|
||||
pub(crate) async fn set_previous_turn_settings(
|
||||
&self,
|
||||
previous_turn_settings: Option<PreviousTurnSettings>,
|
||||
) {
|
||||
pub(crate) async fn note_model_visible_turn_context(&self, turn_context_item: TurnContextItem) {
|
||||
let mut state = self.state.lock().await;
|
||||
state.set_previous_turn_settings(previous_turn_settings);
|
||||
state.note_model_visible_turn_context(turn_context_item);
|
||||
}
|
||||
|
||||
async fn reset_reference_turn_context_state(&self) {
|
||||
let mut state = self.state.lock().await;
|
||||
state.reset_reference_turn_context_state();
|
||||
}
|
||||
|
||||
fn maybe_refresh_shell_snapshot_for_cwd(
|
||||
@@ -3631,10 +3628,11 @@ impl Session {
|
||||
self.persist_rollout_items(&[RolloutItem::TurnContext(turn_context_item.clone())])
|
||||
.await;
|
||||
|
||||
// Advance the in-memory diff baseline even when this turn emitted no model-visible
|
||||
// context items. This keeps later runtime diffing aligned with the current turn state.
|
||||
let mut state = self.state.lock().await;
|
||||
state.set_reference_context_item(Some(turn_context_item));
|
||||
// Advance the stored turn-context snapshot even when this turn emitted no model-visible
|
||||
// context items. Regular turns become both the `previous_turn_settings()` source and the
|
||||
// active model-visible reference baseline for subsequent diffing.
|
||||
self.note_model_visible_turn_context(turn_context_item)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(crate) async fn update_token_usage_info(
|
||||
@@ -5558,15 +5556,6 @@ pub(crate) async fn run_turn(
|
||||
sess.record_user_prompt_and_emit_turn_item(turn_context.as_ref(), &input, response_item)
|
||||
.await;
|
||||
record_additional_contexts(&sess, &turn_context, additional_contexts).await;
|
||||
// Track the previous-turn baseline from the regular user-turn path only so
|
||||
// standalone tasks (compact/shell/review/undo) cannot suppress future
|
||||
// model/realtime injections.
|
||||
sess.set_previous_turn_settings(Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
}))
|
||||
.await;
|
||||
|
||||
if !skill_items.is_empty() {
|
||||
sess.record_conversation_items(&turn_context, &skill_items)
|
||||
.await;
|
||||
|
||||
@@ -1,36 +1,19 @@
|
||||
use super::*;
|
||||
use crate::context_manager::ReferenceTurnContextState;
|
||||
|
||||
// Return value of `Session::reconstruct_history_from_rollout`, bundling the rebuilt history with
|
||||
// the resume/fork hydration metadata derived from the same replay.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct RolloutReconstruction {
|
||||
pub(super) history: Vec<ResponseItem>,
|
||||
pub(super) previous_turn_settings: Option<PreviousTurnSettings>,
|
||||
pub(super) reference_context_item: Option<TurnContextItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
enum TurnReferenceContextItem {
|
||||
/// No `TurnContextItem` has been seen for this replay span yet.
|
||||
///
|
||||
/// This differs from `Cleared`: `NeverSet` means there is no evidence this turn ever
|
||||
/// established a baseline, while `Cleared` means a baseline existed and a later compaction
|
||||
/// invalidated it. Only the latter must emit an explicit clearing segment for resume/fork
|
||||
/// hydration.
|
||||
#[default]
|
||||
NeverSet,
|
||||
/// A previously established baseline was invalidated by later compaction.
|
||||
Cleared,
|
||||
/// The latest baseline established by this replay span.
|
||||
Latest(Box<TurnContextItem>),
|
||||
pub(super) reference_turn_context_state: ReferenceTurnContextState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ActiveReplaySegment<'a> {
|
||||
turn_id: Option<String>,
|
||||
counts_as_user_turn: bool,
|
||||
previous_turn_settings: Option<PreviousTurnSettings>,
|
||||
reference_context_item: TurnReferenceContextItem,
|
||||
reference_turn_context_state: ReferenceTurnContextState,
|
||||
base_replacement_history: Option<&'a [ResponseItem]>,
|
||||
}
|
||||
|
||||
@@ -42,8 +25,7 @@ fn turn_ids_are_compatible(active_turn_id: Option<&str>, item_turn_id: Option<&s
|
||||
fn finalize_active_segment<'a>(
|
||||
active_segment: ActiveReplaySegment<'a>,
|
||||
base_replacement_history: &mut Option<&'a [ResponseItem]>,
|
||||
previous_turn_settings: &mut Option<PreviousTurnSettings>,
|
||||
reference_context_item: &mut TurnReferenceContextItem,
|
||||
reference_turn_context_state: &mut ReferenceTurnContextState,
|
||||
pending_rollback_turns: &mut usize,
|
||||
) {
|
||||
// Thread rollback drops the newest surviving real user-message boundaries. In replay, that
|
||||
@@ -64,21 +46,47 @@ fn finalize_active_segment<'a>(
|
||||
*base_replacement_history = Some(segment_base_replacement_history);
|
||||
}
|
||||
|
||||
// `previous_turn_settings` come from the newest surviving user turn that established them.
|
||||
if previous_turn_settings.is_none() && active_segment.counts_as_user_turn {
|
||||
*previous_turn_settings = active_segment.previous_turn_settings;
|
||||
merge_surviving_segment_turn_context_state(
|
||||
reference_turn_context_state,
|
||||
active_segment.reference_turn_context_state,
|
||||
active_segment.counts_as_user_turn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Merge one surviving replay segment's turn-context bookkeeping into the aggregate
|
||||
/// `reference_turn_context_state` we are reconstructing for the newest surviving history tail.
|
||||
///
|
||||
/// `segment_turn_context_state` is the per-segment state collected while replaying one reverse
|
||||
/// segment. `reference_turn_context_state` is the cross-segment accumulator for the surviving
|
||||
/// transcript after rollback has skipped newer user turns.
|
||||
fn merge_surviving_segment_turn_context_state(
|
||||
reference_turn_context_state: &mut ReferenceTurnContextState,
|
||||
segment_turn_context_state: ReferenceTurnContextState,
|
||||
counts_as_user_turn: bool,
|
||||
) {
|
||||
// A compaction seen in this segment shadows any older stored turn context, but it must not
|
||||
// erase a newer stored turn context we already captured from a later surviving user turn.
|
||||
if segment_turn_context_state.compacted_since_model_saw_reference_turn_context()
|
||||
&& reference_turn_context_state
|
||||
.stored_turn_context_item()
|
||||
.is_none()
|
||||
{
|
||||
reference_turn_context_state.note_compaction();
|
||||
}
|
||||
|
||||
// `reference_context_item` comes from the newest surviving user turn baseline, or
|
||||
// from a surviving compaction that explicitly cleared that baseline.
|
||||
if matches!(reference_context_item, TurnReferenceContextItem::NeverSet)
|
||||
&& (active_segment.counts_as_user_turn
|
||||
|| matches!(
|
||||
active_segment.reference_context_item,
|
||||
TurnReferenceContextItem::Cleared
|
||||
))
|
||||
// Only real user turns should establish the stored turn context. Standalone task turns may
|
||||
// carry lifecycle events, but they must not become the source of `previous_turn_settings()`
|
||||
// or the reference baseline.
|
||||
//
|
||||
// This stores the newest surviving real turn context, while preserving any later compaction
|
||||
// shadow we already learned about from newer surviving segments.
|
||||
if counts_as_user_turn
|
||||
&& reference_turn_context_state
|
||||
.stored_turn_context_item()
|
||||
.is_none()
|
||||
&& let Some(turn_context_item) = segment_turn_context_state.stored_turn_context_item()
|
||||
{
|
||||
*reference_context_item = active_segment.reference_context_item;
|
||||
reference_turn_context_state.note_turn_context_during_reverse_replay(&turn_context_item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,12 +98,11 @@ impl Session {
|
||||
) -> RolloutReconstruction {
|
||||
// Replay metadata should already match the shape of the future lazy reverse loader, even
|
||||
// while history materialization still uses an eager bridge. Scan newest-to-oldest,
|
||||
// stopping once a surviving replacement-history checkpoint and the required resume metadata
|
||||
// are both known; then replay only the buffered surviving tail forward to preserve exact
|
||||
// history semantics.
|
||||
// stopping once a surviving replacement-history checkpoint and the latest surviving turn
|
||||
// context are both known; then replay only the buffered surviving tail forward to
|
||||
// preserve exact history semantics.
|
||||
let mut base_replacement_history: Option<&[ResponseItem]> = None;
|
||||
let mut previous_turn_settings = None;
|
||||
let mut reference_context_item = TurnReferenceContextItem::NeverSet;
|
||||
let mut reference_turn_context_state = ReferenceTurnContextState::default();
|
||||
// Rollback is "drop the newest N user turns". While scanning in reverse, that becomes
|
||||
// "skip the next N user-turn segments we finalize".
|
||||
let mut pending_rollback_turns = 0usize;
|
||||
@@ -113,12 +120,9 @@ impl Session {
|
||||
active_segment.get_or_insert_with(ActiveReplaySegment::default);
|
||||
// Looking backward, compaction clears any older baseline unless a newer
|
||||
// `TurnContextItem` in this same segment has already re-established it.
|
||||
if matches!(
|
||||
active_segment.reference_context_item,
|
||||
TurnReferenceContextItem::NeverSet
|
||||
) {
|
||||
active_segment.reference_context_item = TurnReferenceContextItem::Cleared;
|
||||
}
|
||||
active_segment
|
||||
.reference_turn_context_state
|
||||
.note_compaction_during_reverse_replay();
|
||||
if active_segment.base_replacement_history.is_none()
|
||||
&& let Some(replacement_history) = &compacted.replacement_history
|
||||
{
|
||||
@@ -170,17 +174,9 @@ impl Session {
|
||||
active_segment.turn_id.as_deref(),
|
||||
ctx.turn_id.as_deref(),
|
||||
) {
|
||||
active_segment.previous_turn_settings = Some(PreviousTurnSettings {
|
||||
model: ctx.model.clone(),
|
||||
realtime_active: ctx.realtime_active,
|
||||
});
|
||||
if matches!(
|
||||
active_segment.reference_context_item,
|
||||
TurnReferenceContextItem::NeverSet
|
||||
) {
|
||||
active_segment.reference_context_item =
|
||||
TurnReferenceContextItem::Latest(Box::new(ctx.clone()));
|
||||
}
|
||||
active_segment
|
||||
.reference_turn_context_state
|
||||
.note_turn_context_during_reverse_replay(ctx);
|
||||
}
|
||||
}
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(event)) => {
|
||||
@@ -195,8 +191,7 @@ impl Session {
|
||||
finalize_active_segment(
|
||||
active_segment,
|
||||
&mut base_replacement_history,
|
||||
&mut previous_turn_settings,
|
||||
&mut reference_context_item,
|
||||
&mut reference_turn_context_state,
|
||||
&mut pending_rollback_turns,
|
||||
);
|
||||
}
|
||||
@@ -207,12 +202,13 @@ impl Session {
|
||||
}
|
||||
|
||||
if base_replacement_history.is_some()
|
||||
&& previous_turn_settings.is_some()
|
||||
&& !matches!(reference_context_item, TurnReferenceContextItem::NeverSet)
|
||||
&& pending_rollback_turns == 0
|
||||
&& reference_turn_context_state
|
||||
.stored_turn_context_item()
|
||||
.is_some()
|
||||
{
|
||||
// At this point we have both eager resume metadata values and the replacement-
|
||||
// history base for the surviving tail, so older rollout items cannot affect this
|
||||
// result.
|
||||
// At this point the replay-derived metadata and replacement-history base for the
|
||||
// surviving tail are both fixed, so older rollout items cannot affect this result.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,8 +217,7 @@ impl Session {
|
||||
finalize_active_segment(
|
||||
active_segment,
|
||||
&mut base_replacement_history,
|
||||
&mut previous_turn_settings,
|
||||
&mut reference_context_item,
|
||||
&mut reference_turn_context_state,
|
||||
&mut pending_rollback_turns,
|
||||
);
|
||||
}
|
||||
@@ -276,22 +271,12 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
let reference_context_item = match reference_context_item {
|
||||
TurnReferenceContextItem::NeverSet | TurnReferenceContextItem::Cleared => None,
|
||||
TurnReferenceContextItem::Latest(turn_reference_context_item) => {
|
||||
Some(*turn_reference_context_item)
|
||||
}
|
||||
};
|
||||
let reference_context_item = if saw_legacy_compaction_without_replacement_history {
|
||||
None
|
||||
} else {
|
||||
reference_context_item
|
||||
};
|
||||
|
||||
if saw_legacy_compaction_without_replacement_history {
|
||||
reference_turn_context_state.note_compaction();
|
||||
}
|
||||
RolloutReconstruction {
|
||||
history: history.raw_items().to_vec(),
|
||||
previous_turn_settings,
|
||||
reference_context_item,
|
||||
reference_turn_context_state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,18 +228,34 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_com
|
||||
vec![turn_one_user, turn_one_assistant]
|
||||
);
|
||||
assert_eq!(
|
||||
reconstructed.previous_turn_settings,
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.previous_turn_settings(),
|
||||
Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(reconstructed.reference_context_item)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(Some(first_context_item))
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item(),
|
||||
)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(Some(first_context_item.clone()))
|
||||
.expect("serialize expected reference context item")
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.stored_turn_context_item(),
|
||||
)
|
||||
.expect("serialize surviving turn context item"),
|
||||
serde_json::to_value(Some(first_context_item))
|
||||
.expect("serialize expected surviving turn context item")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -310,20 +326,166 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_inc
|
||||
vec![turn_one_user, turn_one_assistant]
|
||||
);
|
||||
assert_eq!(
|
||||
reconstructed.previous_turn_settings,
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.previous_turn_settings(),
|
||||
Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(reconstructed.reference_context_item)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item(),
|
||||
)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(Some(first_context_item))
|
||||
.expect("serialize expected reference context item")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn reconstruct_history_rollback_backfills_surviving_turn_context_from_older_turn() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let first_context_item = turn_context.to_turn_context_item();
|
||||
let first_turn_id = first_context_item
|
||||
.turn_id
|
||||
.clone()
|
||||
.expect("turn context should have turn_id");
|
||||
let second_turn_id = "second-turn-without-context".to_string();
|
||||
let rolled_back_turn_id = "rolled-back-turn".to_string();
|
||||
let turn_one_user = user_message("turn 1 user");
|
||||
let turn_one_assistant = assistant_message("turn 1 assistant");
|
||||
let turn_two_user = user_message("turn 2 user");
|
||||
let turn_two_assistant = assistant_message("turn 2 assistant");
|
||||
|
||||
let rollout_items = vec![
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
turn_id: first_turn_id.clone(),
|
||||
model_context_window: Some(128_000),
|
||||
collaboration_mode_kind: ModeKind::Default,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::UserMessage(
|
||||
codex_protocol::protocol::UserMessageEvent {
|
||||
message: "turn 1 user".to_string(),
|
||||
images: None,
|
||||
local_images: Vec::new(),
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
)),
|
||||
RolloutItem::TurnContext(first_context_item.clone()),
|
||||
RolloutItem::ResponseItem(turn_one_user.clone()),
|
||||
RolloutItem::ResponseItem(turn_one_assistant.clone()),
|
||||
RolloutItem::EventMsg(EventMsg::TurnComplete(
|
||||
codex_protocol::protocol::TurnCompleteEvent {
|
||||
turn_id: first_turn_id,
|
||||
last_agent_message: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
turn_id: second_turn_id.clone(),
|
||||
model_context_window: Some(128_000),
|
||||
collaboration_mode_kind: ModeKind::Default,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::UserMessage(
|
||||
codex_protocol::protocol::UserMessageEvent {
|
||||
message: "turn 2 user".to_string(),
|
||||
images: None,
|
||||
local_images: Vec::new(),
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
)),
|
||||
RolloutItem::ResponseItem(turn_two_user.clone()),
|
||||
RolloutItem::ResponseItem(turn_two_assistant.clone()),
|
||||
RolloutItem::EventMsg(EventMsg::TurnComplete(
|
||||
codex_protocol::protocol::TurnCompleteEvent {
|
||||
turn_id: second_turn_id,
|
||||
last_agent_message: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
turn_id: rolled_back_turn_id.clone(),
|
||||
model_context_window: Some(128_000),
|
||||
collaboration_mode_kind: ModeKind::Default,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::UserMessage(
|
||||
codex_protocol::protocol::UserMessageEvent {
|
||||
message: "turn 3 user".to_string(),
|
||||
images: None,
|
||||
local_images: Vec::new(),
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
)),
|
||||
RolloutItem::TurnContext(TurnContextItem {
|
||||
turn_id: Some(rolled_back_turn_id.clone()),
|
||||
model: "rolled-back-model".to_string(),
|
||||
..first_context_item.clone()
|
||||
}),
|
||||
RolloutItem::ResponseItem(user_message("turn 3 user")),
|
||||
RolloutItem::ResponseItem(assistant_message("turn 3 assistant")),
|
||||
RolloutItem::EventMsg(EventMsg::TurnComplete(
|
||||
codex_protocol::protocol::TurnCompleteEvent {
|
||||
turn_id: rolled_back_turn_id,
|
||||
last_agent_message: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
codex_protocol::protocol::ThreadRolledBackEvent { num_turns: 1 },
|
||||
)),
|
||||
];
|
||||
|
||||
let reconstructed = session
|
||||
.reconstruct_history_from_rollout(&turn_context, &rollout_items)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
reconstructed.history,
|
||||
vec![
|
||||
turn_one_user,
|
||||
turn_one_assistant,
|
||||
turn_two_user,
|
||||
turn_two_assistant
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.previous_turn_settings(),
|
||||
Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item(),
|
||||
)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(Some(first_context_item.clone()))
|
||||
.expect("serialize expected reference context item")
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.stored_turn_context_item(),
|
||||
)
|
||||
.expect("serialize surviving turn context item"),
|
||||
serde_json::to_value(Some(first_context_item))
|
||||
.expect("serialize expected surviving turn context item")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metadata() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
@@ -416,15 +578,21 @@ async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metad
|
||||
vec![turn_one_user, turn_one_assistant]
|
||||
);
|
||||
assert_eq!(
|
||||
reconstructed.previous_turn_settings,
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.previous_turn_settings(),
|
||||
Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(reconstructed.reference_context_item)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item(),
|
||||
)
|
||||
.expect("serialize reconstructed reference context item"),
|
||||
serde_json::to_value(Some(first_context_item))
|
||||
.expect("serialize expected reference context item")
|
||||
);
|
||||
@@ -473,8 +641,18 @@ async fn reconstruct_history_rollback_clears_history_and_metadata_when_exceeding
|
||||
.await;
|
||||
|
||||
assert_eq!(reconstructed.history, Vec::new());
|
||||
assert_eq!(reconstructed.previous_turn_settings, None);
|
||||
assert!(reconstructed.reference_context_item.is_none());
|
||||
assert_eq!(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.previous_turn_settings(),
|
||||
None
|
||||
);
|
||||
assert!(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item()
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -685,7 +863,12 @@ async fn reconstruct_history_legacy_compaction_without_replacement_history_does_
|
||||
user_message("legacy summary"),
|
||||
]
|
||||
);
|
||||
assert!(reconstructed.reference_context_item.is_none());
|
||||
assert!(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item()
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -731,7 +914,12 @@ async fn reconstruct_history_legacy_compaction_without_replacement_history_clear
|
||||
.reconstruct_history_from_rollout(&turn_context, &rollout_items)
|
||||
.await;
|
||||
|
||||
assert!(reconstructed.reference_context_item.is_none());
|
||||
assert!(
|
||||
reconstructed
|
||||
.reference_turn_context_state
|
||||
.reference_context_item()
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -118,6 +118,39 @@ fn user_message(text: &str) -> ResponseItem {
|
||||
}
|
||||
}
|
||||
|
||||
fn turn_context_item_with_previous_turn_settings(
|
||||
turn_context: &TurnContext,
|
||||
previous_turn_settings: PreviousTurnSettings,
|
||||
) -> TurnContextItem {
|
||||
let mut turn_context_item = turn_context.to_turn_context_item();
|
||||
turn_context_item.model = previous_turn_settings.model;
|
||||
turn_context_item.realtime_active = previous_turn_settings.realtime_active;
|
||||
turn_context_item
|
||||
}
|
||||
|
||||
async fn seed_previous_turn_settings(
|
||||
session: &Session,
|
||||
turn_context: &TurnContext,
|
||||
previous_turn_settings: PreviousTurnSettings,
|
||||
) {
|
||||
session
|
||||
.note_model_visible_turn_context(turn_context_item_with_previous_turn_settings(
|
||||
turn_context,
|
||||
previous_turn_settings,
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn seed_previous_turn_settings_without_reference(
|
||||
session: &Session,
|
||||
turn_context: &TurnContext,
|
||||
previous_turn_settings: PreviousTurnSettings,
|
||||
) {
|
||||
seed_previous_turn_settings(session, turn_context, previous_turn_settings).await;
|
||||
let mut state = session.state.lock().await;
|
||||
state.history.set_reference_context_item(None);
|
||||
}
|
||||
|
||||
fn assistant_message(text: &str) -> ResponseItem {
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
@@ -1116,7 +1149,7 @@ async fn record_initial_history_reconstructs_forked_transcript() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn record_initial_history_forked_hydrates_previous_turn_settings() {
|
||||
async fn record_initial_history_forked_advances_previous_turn_settings_to_current_baseline() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let previous_model = "forked-rollout-model";
|
||||
let previous_context_item = TurnContextItem {
|
||||
@@ -1175,7 +1208,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
|
||||
assert_eq!(
|
||||
session.previous_turn_settings().await,
|
||||
Some(PreviousTurnSettings {
|
||||
model: previous_model.to_string(),
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
realtime_active: Some(turn_context.realtime_active),
|
||||
})
|
||||
);
|
||||
@@ -1206,14 +1239,11 @@ async fn thread_rollback_drops_last_turn_from_history() {
|
||||
.map(RolloutItem::ResponseItem)
|
||||
.collect();
|
||||
sess.persist_rollout_items(&rollout_items).await;
|
||||
sess.set_previous_turn_settings(Some(PreviousTurnSettings {
|
||||
model: "stale-model".to_string(),
|
||||
realtime_active: Some(tc.realtime_active),
|
||||
}))
|
||||
.await;
|
||||
{
|
||||
let mut state = sess.state.lock().await;
|
||||
state.set_reference_context_item(Some(tc.to_turn_context_item()));
|
||||
state
|
||||
.history
|
||||
.set_reference_context_item(Some(tc.to_turn_context_item()));
|
||||
}
|
||||
|
||||
handlers::thread_rollback(&sess, "sub-1".to_string(), 1).await;
|
||||
@@ -1368,11 +1398,6 @@ async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context
|
||||
Some(first_context_item.clone()),
|
||||
)
|
||||
.await;
|
||||
sess.set_previous_turn_settings(Some(PreviousTurnSettings {
|
||||
model: "stale-model".to_string(),
|
||||
realtime_active: None,
|
||||
}))
|
||||
.await;
|
||||
|
||||
handlers::thread_rollback(&sess, "sub-1".to_string(), 1).await;
|
||||
let rollback_event = wait_for_thread_rolled_back(&rx).await;
|
||||
@@ -3453,7 +3478,7 @@ async fn record_model_warning_appends_user_message() {
|
||||
#[tokio::test]
|
||||
async fn spawn_task_does_not_update_previous_turn_settings_for_non_run_turn_tasks() {
|
||||
let (sess, tc, _rx) = make_session_and_context_with_rx().await;
|
||||
sess.set_previous_turn_settings(None).await;
|
||||
sess.reset_reference_turn_context_state().await;
|
||||
let input = vec![UserInput::Text {
|
||||
text: "hello".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3637,9 +3662,7 @@ async fn build_settings_update_items_uses_previous_turn_settings_for_realtime_en
|
||||
.await;
|
||||
current_context.realtime_active = false;
|
||||
|
||||
session
|
||||
.set_previous_turn_settings(Some(previous_turn_settings))
|
||||
.await;
|
||||
seed_previous_turn_settings(&session, &previous_context, previous_turn_settings).await;
|
||||
let update_items = session
|
||||
.build_settings_update_items(Some(&previous_context_item), ¤t_context)
|
||||
.await;
|
||||
@@ -3670,7 +3693,9 @@ async fn build_initial_context_uses_previous_realtime_state() {
|
||||
let previous_context_item = turn_context.to_turn_context_item();
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(Some(previous_context_item));
|
||||
state
|
||||
.history
|
||||
.set_reference_context_item(Some(previous_context_item));
|
||||
}
|
||||
let resumed_context = session.build_initial_context(&turn_context).await;
|
||||
let resumed_developer_texts = developer_input_texts(&resumed_context);
|
||||
@@ -3821,8 +3846,7 @@ async fn build_initial_context_uses_previous_turn_settings_for_realtime_end() {
|
||||
realtime_active: Some(true),
|
||||
};
|
||||
|
||||
session
|
||||
.set_previous_turn_settings(Some(previous_turn_settings))
|
||||
seed_previous_turn_settings_without_reference(&session, &turn_context, previous_turn_settings)
|
||||
.await;
|
||||
let initial_context = session.build_initial_context(&turn_context).await;
|
||||
let developer_texts = developer_input_texts(&initial_context);
|
||||
@@ -3843,8 +3867,7 @@ async fn build_initial_context_restates_realtime_start_when_reference_context_is
|
||||
realtime_active: Some(true),
|
||||
};
|
||||
|
||||
session
|
||||
.set_previous_turn_settings(Some(previous_turn_settings))
|
||||
seed_previous_turn_settings_without_reference(&session, &turn_context, previous_turn_settings)
|
||||
.await;
|
||||
let initial_context = session.build_initial_context(&turn_context).await;
|
||||
let developer_texts = developer_input_texts(&initial_context);
|
||||
@@ -3896,7 +3919,7 @@ async fn record_context_updates_and_set_reference_context_item_reinjects_full_co
|
||||
.await;
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(None);
|
||||
state.history.set_reference_context_item(None);
|
||||
}
|
||||
session
|
||||
.replace_history(vec![compacted_summary.clone()], None)
|
||||
@@ -3913,7 +3936,7 @@ async fn record_context_updates_and_set_reference_context_item_reinjects_full_co
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn record_context_updates_and_set_reference_context_item_persists_baseline_without_emitting_diffs()
|
||||
async fn record_context_updates_and_set_reference_context_item_emits_model_switch_for_stored_baseline()
|
||||
{
|
||||
let (session, previous_context) = make_session_and_context().await;
|
||||
let next_model = if previous_context.model_info.slug == "gpt-5.1" {
|
||||
@@ -3927,7 +3950,9 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
|
||||
let previous_context_item = previous_context.to_turn_context_item();
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(Some(previous_context_item.clone()));
|
||||
state
|
||||
.history
|
||||
.set_reference_context_item(Some(previous_context_item.clone()));
|
||||
}
|
||||
let config = session.get_config().await;
|
||||
let recorder = RolloutRecorder::new(
|
||||
@@ -3954,7 +3979,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
|
||||
let update_items = session
|
||||
.build_settings_update_items(Some(&previous_context_item), &turn_context)
|
||||
.await;
|
||||
assert_eq!(update_items, Vec::new());
|
||||
assert!(!update_items.is_empty());
|
||||
|
||||
session
|
||||
.record_context_updates_and_set_reference_context_item(&turn_context)
|
||||
@@ -3962,7 +3987,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
|
||||
|
||||
assert_eq!(
|
||||
session.clone_history().await.raw_items().to_vec(),
|
||||
Vec::new()
|
||||
update_items
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(session.reference_context_item().await)
|
||||
@@ -3999,8 +4024,7 @@ async fn build_initial_context_prepends_model_switch_message() {
|
||||
realtime_active: None,
|
||||
};
|
||||
|
||||
session
|
||||
.set_previous_turn_settings(Some(previous_turn_settings))
|
||||
seed_previous_turn_settings_without_reference(&session, &turn_context, previous_turn_settings)
|
||||
.await;
|
||||
let initial_context = session.build_initial_context(&turn_context).await;
|
||||
|
||||
@@ -4060,15 +4084,18 @@ async fn record_context_updates_and_set_reference_context_item_persists_full_rei
|
||||
.await;
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(None);
|
||||
state.history.set_reference_context_item(None);
|
||||
}
|
||||
|
||||
session
|
||||
.set_previous_turn_settings(Some(PreviousTurnSettings {
|
||||
seed_previous_turn_settings_without_reference(
|
||||
&session,
|
||||
&previous_context,
|
||||
PreviousTurnSettings {
|
||||
model: previous_context.model_info.slug.clone(),
|
||||
realtime_active: Some(previous_context.realtime_active),
|
||||
}))
|
||||
.await;
|
||||
},
|
||||
)
|
||||
.await;
|
||||
session
|
||||
.record_context_updates_and_set_reference_context_item(&turn_context)
|
||||
.await;
|
||||
@@ -4099,7 +4126,7 @@ async fn run_user_shell_command_does_not_set_reference_context_item() {
|
||||
let (session, _turn_context, rx) = make_session_and_context_with_rx().await;
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.set_reference_context_item(None);
|
||||
state.history.set_reference_context_item(None);
|
||||
}
|
||||
|
||||
handlers::run_user_shell_command(&session, "sub-id".to_string(), "echo shell".to_string())
|
||||
|
||||
@@ -6,9 +6,15 @@ async fn process_compacted_history_with_test_session(
|
||||
previous_turn_settings: Option<&PreviousTurnSettings>,
|
||||
) -> (Vec<ResponseItem>, Vec<ResponseItem>) {
|
||||
let (session, turn_context) = crate::codex::make_session_and_context().await;
|
||||
session
|
||||
.set_previous_turn_settings(previous_turn_settings.cloned())
|
||||
.await;
|
||||
if let Some(previous_turn_settings) = previous_turn_settings {
|
||||
let mut previous_turn_context_item = turn_context.to_turn_context_item();
|
||||
previous_turn_context_item.model = previous_turn_settings.model.clone();
|
||||
previous_turn_context_item.realtime_active = previous_turn_settings.realtime_active;
|
||||
session
|
||||
.note_model_visible_turn_context(previous_turn_context_item)
|
||||
.await;
|
||||
session.replace_history(Vec::new(), None).await;
|
||||
}
|
||||
let initial_context = session.build_initial_context(&turn_context).await;
|
||||
let refreshed = crate::compact_remote::process_compacted_history(
|
||||
&session,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::codex::PreviousTurnSettings;
|
||||
use crate::codex::TurnContext;
|
||||
use crate::context_manager::normalize;
|
||||
use crate::event_mapping::is_contextual_user_message_content;
|
||||
@@ -32,15 +33,94 @@ pub(crate) struct ContextManager {
|
||||
/// The oldest items are at the beginning of the vector.
|
||||
items: Vec<ResponseItem>,
|
||||
token_info: Option<TokenUsageInfo>,
|
||||
/// Reference context snapshot used for diffing and producing model-visible
|
||||
/// settings update items.
|
||||
reference_turn_context_state: ReferenceTurnContextState,
|
||||
}
|
||||
|
||||
/// Session-owned bookkeeping for the stored turn context that drives both
|
||||
/// `previous_turn_settings()` and the model-visible reference baseline.
|
||||
///
|
||||
/// The stored turn context survives compaction so future turns can still diff
|
||||
/// against the last known settings, while
|
||||
/// `compacted_since_model_saw_reference_turn_context` controls whether the model
|
||||
/// may still treat that stored item as the active reference baseline.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct ReferenceTurnContextState {
|
||||
/// The last stored turn context we reconstructed or recorded.
|
||||
///
|
||||
/// This is the baseline for the next regular model turn, and may already
|
||||
/// match the current turn after context updates are persisted.
|
||||
/// This is the single source of truth for both `previous_turn_settings()` and
|
||||
/// the reference baseline. Compaction can shadow it for model visibility
|
||||
/// without erasing it.
|
||||
turn_context_item: Option<TurnContextItem>,
|
||||
/// Whether compaction has crossed the current reference baseline without a later
|
||||
/// reinjection or real turn context re-establishing it.
|
||||
///
|
||||
/// When this is `None`, settings diffing treats the next turn as having no
|
||||
/// baseline and emits a full reinjection of context state.
|
||||
reference_context_item: Option<TurnContextItem>,
|
||||
/// When this is true, `reference_context_item()` must return `None` even if
|
||||
/// `turn_context_item` still retains the last stored baseline for replay or
|
||||
/// rollback bookkeeping.
|
||||
compacted_since_model_saw_reference_turn_context: bool,
|
||||
}
|
||||
|
||||
impl ReferenceTurnContextState {
|
||||
pub(crate) fn reset(&mut self) {
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
pub(crate) fn note_compaction(&mut self) {
|
||||
self.compacted_since_model_saw_reference_turn_context = true;
|
||||
}
|
||||
|
||||
pub(crate) fn note_compaction_during_reverse_replay(&mut self) {
|
||||
if self.turn_context_item.is_none() {
|
||||
self.compacted_since_model_saw_reference_turn_context = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn note_turn_context_during_reverse_replay(
|
||||
&mut self,
|
||||
turn_context_item: &TurnContextItem,
|
||||
) {
|
||||
if self.turn_context_item.is_none() {
|
||||
self.turn_context_item = Some(turn_context_item.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn note_model_visible_turn_context(&mut self, turn_context_item: TurnContextItem) {
|
||||
self.turn_context_item = Some(turn_context_item);
|
||||
self.compacted_since_model_saw_reference_turn_context = false;
|
||||
}
|
||||
|
||||
pub(crate) fn set_reference_context_item(&mut self, item: Option<TurnContextItem>) {
|
||||
if let Some(item) = item {
|
||||
self.note_model_visible_turn_context(item);
|
||||
} else {
|
||||
self.note_compaction();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn stored_turn_context_item(&self) -> Option<TurnContextItem> {
|
||||
self.turn_context_item.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn compacted_since_model_saw_reference_turn_context(&self) -> bool {
|
||||
self.compacted_since_model_saw_reference_turn_context
|
||||
}
|
||||
|
||||
pub(crate) fn previous_turn_settings(&self) -> Option<PreviousTurnSettings> {
|
||||
self.turn_context_item
|
||||
.as_ref()
|
||||
.map(|turn_context_item| PreviousTurnSettings {
|
||||
model: turn_context_item.model.clone(),
|
||||
realtime_active: turn_context_item.realtime_active,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn reference_context_item(&self) -> Option<TurnContextItem> {
|
||||
if self.compacted_since_model_saw_reference_turn_context {
|
||||
None
|
||||
} else {
|
||||
self.turn_context_item.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
@@ -58,7 +138,7 @@ impl ContextManager {
|
||||
token_info: TokenUsageInfo::new_or_append(
|
||||
&None, &None, /*model_context_window*/ None,
|
||||
),
|
||||
reference_context_item: None,
|
||||
reference_turn_context_state: ReferenceTurnContextState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,12 +150,33 @@ impl ContextManager {
|
||||
self.token_info = info;
|
||||
}
|
||||
|
||||
pub(crate) fn set_reference_turn_context_state(
|
||||
&mut self,
|
||||
reference_turn_context_state: ReferenceTurnContextState,
|
||||
) {
|
||||
self.reference_turn_context_state = reference_turn_context_state;
|
||||
}
|
||||
|
||||
pub(crate) fn reset_reference_turn_context_state(&mut self) {
|
||||
self.reference_turn_context_state.reset();
|
||||
}
|
||||
|
||||
pub(crate) fn note_model_visible_turn_context(&mut self, turn_context_item: TurnContextItem) {
|
||||
self.reference_turn_context_state
|
||||
.note_model_visible_turn_context(turn_context_item);
|
||||
}
|
||||
|
||||
pub(crate) fn previous_turn_settings(&self) -> Option<PreviousTurnSettings> {
|
||||
self.reference_turn_context_state.previous_turn_settings()
|
||||
}
|
||||
|
||||
pub(crate) fn set_reference_context_item(&mut self, item: Option<TurnContextItem>) {
|
||||
self.reference_context_item = item;
|
||||
self.reference_turn_context_state
|
||||
.set_reference_context_item(item);
|
||||
}
|
||||
|
||||
pub(crate) fn reference_context_item(&self) -> Option<TurnContextItem> {
|
||||
self.reference_context_item.clone()
|
||||
self.reference_turn_context_state.reference_context_item()
|
||||
}
|
||||
|
||||
pub(crate) fn set_token_usage_full(&mut self, context_window: i64) {
|
||||
|
||||
@@ -3,6 +3,7 @@ mod normalize;
|
||||
pub(crate) mod updates;
|
||||
|
||||
pub(crate) use history::ContextManager;
|
||||
pub(crate) use history::ReferenceTurnContextState;
|
||||
pub(crate) use history::TotalTokenUsageBreakdown;
|
||||
pub(crate) use history::estimate_response_item_model_visible_bytes;
|
||||
pub(crate) use history::is_codex_generated_item;
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::collections::HashSet;
|
||||
use crate::codex::PreviousTurnSettings;
|
||||
use crate::codex::SessionConfiguration;
|
||||
use crate::context_manager::ContextManager;
|
||||
use crate::context_manager::ReferenceTurnContextState;
|
||||
use crate::protocol::RateLimitSnapshot;
|
||||
use crate::protocol::TokenUsage;
|
||||
use crate::protocol::TokenUsageInfo;
|
||||
@@ -24,10 +25,6 @@ pub(crate) struct SessionState {
|
||||
pub(crate) server_reasoning_included: bool,
|
||||
pub(crate) dependency_env: HashMap<String, String>,
|
||||
pub(crate) mcp_dependency_prompted: HashSet<String>,
|
||||
/// Settings used by the latest regular user turn, used for turn-to-turn
|
||||
/// model/realtime handling on subsequent regular turns (including full-context
|
||||
/// reinjection after resume or `/compact`).
|
||||
previous_turn_settings: Option<PreviousTurnSettings>,
|
||||
/// Startup prewarmed session prepared during session initialization.
|
||||
pub(crate) startup_prewarm: Option<SessionStartupPrewarmHandle>,
|
||||
pub(crate) active_connector_selection: HashSet<String>,
|
||||
@@ -46,7 +43,6 @@ impl SessionState {
|
||||
server_reasoning_included: false,
|
||||
dependency_env: HashMap::new(),
|
||||
mcp_dependency_prompted: HashSet::new(),
|
||||
previous_turn_settings: None,
|
||||
startup_prewarm: None,
|
||||
active_connector_selection: HashSet::new(),
|
||||
pending_session_start_source: None,
|
||||
@@ -64,13 +60,7 @@ impl SessionState {
|
||||
}
|
||||
|
||||
pub(crate) fn previous_turn_settings(&self) -> Option<PreviousTurnSettings> {
|
||||
self.previous_turn_settings.clone()
|
||||
}
|
||||
pub(crate) fn set_previous_turn_settings(
|
||||
&mut self,
|
||||
previous_turn_settings: Option<PreviousTurnSettings>,
|
||||
) {
|
||||
self.previous_turn_settings = previous_turn_settings;
|
||||
self.history.previous_turn_settings()
|
||||
}
|
||||
|
||||
pub(crate) fn clone_history(&self) -> ContextManager {
|
||||
@@ -81,18 +71,37 @@ impl SessionState {
|
||||
&mut self,
|
||||
items: Vec<ResponseItem>,
|
||||
reference_context_item: Option<TurnContextItem>,
|
||||
) {
|
||||
self.history.replace(items);
|
||||
match reference_context_item {
|
||||
Some(turn_context_item) => self
|
||||
.history
|
||||
.note_model_visible_turn_context(turn_context_item),
|
||||
None => self.history.set_reference_context_item(/*item*/ None),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn replace_history_with_reference_turn_context_state(
|
||||
&mut self,
|
||||
items: Vec<ResponseItem>,
|
||||
reference_turn_context_state: ReferenceTurnContextState,
|
||||
) {
|
||||
self.history.replace(items);
|
||||
self.history
|
||||
.set_reference_context_item(reference_context_item);
|
||||
.set_reference_turn_context_state(reference_turn_context_state);
|
||||
}
|
||||
|
||||
pub(crate) fn reset_reference_turn_context_state(&mut self) {
|
||||
self.history.reset_reference_turn_context_state();
|
||||
}
|
||||
|
||||
pub(crate) fn set_token_info(&mut self, info: Option<TokenUsageInfo>) {
|
||||
self.history.set_token_info(info);
|
||||
}
|
||||
|
||||
pub(crate) fn set_reference_context_item(&mut self, item: Option<TurnContextItem>) {
|
||||
self.history.set_reference_context_item(item);
|
||||
pub(crate) fn note_model_visible_turn_context(&mut self, turn_context_item: TurnContextItem) {
|
||||
self.history
|
||||
.note_model_visible_turn_context(turn_context_item);
|
||||
}
|
||||
|
||||
pub(crate) fn reference_context_item(&self) -> Option<TurnContextItem> {
|
||||
|
||||
Reference in New Issue
Block a user