[codex] Trim unused TurnContextItem fields (#22709)

## Why

`TurnContextItem` is the durable baseline used to reconstruct context
diffs across resume/fork. Most of the old persisted-only fields on it
are no longer read, so keeping them in rollout snapshots adds schema
surface and state that can drift without affecting reconstruction.

`summary` is the exception: older Codex versions require it to
deserialize `turn_context` records, so keep writing a default
compatibility value until that schema surface can be removed safely.

## What changed

- Removed the unused persisted fields from `TurnContextItem`: trace ids,
user/developer instructions, output schema, and truncation policy.
- Kept `summary` with a compatibility comment and made
`TurnContext::to_turn_context_item` write `ReasoningSummary::Auto`
instead of live turn state.
- Updated rollout/context reconstruction fixtures for the retained
summary field.

## Verification

- `cargo test -p codex-protocol --lib turn_context_item`
- `cargo test -p codex-rollout
resume_candidate_matches_cwd_reads_latest_turn_context`
- `cargo test -p codex-state turn_context`
- `cargo test -p codex-core --lib
new_default_turn_captures_current_span_trace_id`
- `cargo test -p codex-core --lib
record_initial_history_resumed_turn_context_after_compaction_reestablishes_reference_context_item`
- `cargo test -p codex-core --test all
emits_warning_when_resumed_model_differs`
- `git diff --check`
This commit is contained in:
pakrym-oai
2026-05-18 14:54:36 -07:00
committed by GitHub
Unverified
parent c95a70fb42
commit f2368b7de6
8 changed files with 24 additions and 119 deletions
@@ -2,7 +2,6 @@ use super::*;
use base64::Engine;
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use codex_protocol::AgentPath;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::models::BaseInstructions;
use codex_protocol::models::ContentItem;
use codex_protocol::models::DEFAULT_IMAGE_DETAIL;
@@ -121,7 +120,6 @@ fn developer_msg_with_fragments(texts: &[&str]) -> ResponseItem {
fn reference_context_item() -> TurnContextItem {
TurnContextItem {
turn_id: Some("reference-turn".to_string()),
trace_id: None,
cwd: PathBuf::from("/tmp/reference-cwd"),
current_date: Some("2026-03-23".to_string()),
timezone: Some("America/Los_Angeles".to_string()),
@@ -135,11 +133,7 @@ fn reference_context_item() -> TurnContextItem {
collaboration_mode: None,
realtime_active: Some(false),
effort: None,
summary: ReasoningSummary::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(codex_protocol::protocol::TruncationPolicy::Tokens(10_000)),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}
}
@@ -59,7 +59,6 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ
let previous_model = "previous-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -74,11 +73,7 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let rollout_items = vec![RolloutItem::TurnContext(previous_context_item)];
@@ -101,7 +96,6 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
let previous_model = "previous-rollout-model";
let mut previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -116,11 +110,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let turn_id = previous_context_item
.turn_id
@@ -925,7 +915,6 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
let previous_model = "previous-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -940,11 +929,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
.turn_id
@@ -1005,7 +990,6 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
.expect("serialize seeded reference context item"),
serde_json::to_value(Some(TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -1020,11 +1004,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}))
.expect("serialize expected reference context item")
);
@@ -1037,7 +1017,6 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
let previous_model = "previous-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -1052,11 +1031,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
.turn_id
@@ -1155,7 +1130,6 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
let unmatched_abort_turn_id = "other-turn".to_string();
let current_context_item = TurnContextItem {
turn_id: Some(current_turn_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -1170,11 +1144,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let rollout_items = vec![
@@ -1272,7 +1242,6 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
let previous_model = "previous-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -1287,11 +1256,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
.turn_id
@@ -1428,7 +1393,6 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
let previous_model = "previous-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -1443,11 +1407,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
.turn_id
+5 -11
View File
@@ -2317,7 +2317,6 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
let previous_model = "forked-rollout-model";
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
trace_id: turn_context.trace_id.clone(),
#[allow(deprecated)]
cwd: turn_context.cwd.to_path_buf(),
current_date: turn_context.current_date.clone(),
@@ -2332,11 +2331,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
summary: turn_context.reasoning_summary,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: Some(turn_context.truncation_policy),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let turn_id = previous_context_item
.turn_id
@@ -5125,7 +5120,7 @@ async fn new_default_turn_captures_current_span_trace_id() {
&request_parent
));
let turn_context_item = async {
let turn_trace_id = async {
let expected_trace_id = Span::current()
.context()
.span()
@@ -5133,15 +5128,14 @@ async fn new_default_turn_captures_current_span_trace_id() {
.trace_id()
.to_string();
let turn_context = session.new_default_turn().await;
let turn_context_item = turn_context.to_turn_context_item();
assert_eq!(turn_context_item.trace_id, Some(expected_trace_id));
turn_context_item
assert_eq!(turn_context.trace_id, Some(expected_trace_id));
turn_context.trace_id.clone()
}
.instrument(request_span)
.await;
assert_eq!(
turn_context_item.trace_id.as_deref(),
turn_trace_id.as_deref(),
Some("00000000000000000000000000000011")
);
}
+1 -6
View File
@@ -368,7 +368,6 @@ impl TurnContext {
pub(crate) fn to_turn_context_item(&self) -> TurnContextItem {
TurnContextItem {
turn_id: Some(self.sub_id.clone()),
trace_id: self.trace_id.clone(),
#[allow(deprecated)]
cwd: self.cwd.to_path_buf(),
current_date: self.current_date.clone(),
@@ -383,11 +382,7 @@ impl TurnContext {
collaboration_mode: Some(self.collaboration_mode.clone()),
realtime_active: Some(self.realtime_active),
effort: self.reasoning_effort,
summary: self.reasoning_summary,
user_instructions: self.user_instructions.clone(),
developer_instructions: self.developer_instructions.clone(),
final_output_json_schema: self.final_output_json_schema.clone(),
truncation_policy: Some(self.truncation_policy),
summary: ReasoningSummaryConfig::Auto,
}
}
@@ -27,7 +27,6 @@ fn resume_history(
let turn_id = "resume-warning-seed-turn".to_string();
let turn_ctx = TurnContextItem {
turn_id: Some(turn_id.clone()),
trace_id: None,
cwd: config.cwd.to_path_buf(),
current_date: None,
timezone: None,
@@ -44,10 +43,6 @@ fn resume_history(
summary: config
.model_reasoning_summary
.unwrap_or(ReasoningSummary::Auto),
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
};
InitialHistory::Resumed(ResumedHistory {
+5 -16
View File
@@ -2824,8 +2824,6 @@ pub struct TurnContextNetworkItem {
pub struct TurnContextItem {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_id: Option<String>,
pub cwd: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub current_date: Option<String>,
@@ -2848,15 +2846,11 @@ pub struct TurnContextItem {
pub realtime_active: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub effort: Option<ReasoningEffortConfig>,
// Compatibility-only field written with a default value so older Codex
// versions can deserialize turn-context rollout items. It is no longer
// read by context reconstruction and should be removed in a future schema
// cleanup.
pub summary: ReasoningSummaryConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub developer_instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub final_output_json_schema: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub truncation_policy: Option<TruncationPolicy>,
}
impl TurnContextItem {
@@ -5246,7 +5240,6 @@ mod tests {
"summary": "auto",
}))?;
assert_eq!(item.trace_id, None);
assert_eq!(item.network, None);
assert_eq!(item.file_system_sandbox_policy, None);
Ok(())
@@ -5256,7 +5249,6 @@ mod tests {
fn turn_context_item_serializes_network_when_present() -> Result<()> {
let item = TurnContextItem {
turn_id: None,
trace_id: None,
cwd: test_path_buf("/tmp"),
current_date: None,
timezone: None,
@@ -5281,10 +5273,6 @@ mod tests {
realtime_active: None,
effort: None,
summary: ReasoningSummaryConfig::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
};
let value = serde_json::to_value(item)?;
@@ -5308,6 +5296,7 @@ mod tests {
}]
})
);
assert_eq!(value["summary"], json!("auto"));
Ok(())
}
+1 -7
View File
@@ -4,7 +4,6 @@ use super::*;
use crate::config::RolloutConfig;
use chrono::TimeZone;
use codex_protocol::ThreadId;
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
use codex_protocol::models::ResponseItem;
use codex_protocol::protocol::AgentMessageEvent;
use codex_protocol::protocol::AskForApproval;
@@ -1127,7 +1126,6 @@ async fn resume_candidate_matches_cwd_reads_latest_turn_context() -> std::io::Re
timestamp: "2025-01-03T13:00:01Z".to_string(),
item: RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
trace_id: None,
cwd: latest_cwd.clone(),
current_date: None,
timezone: None,
@@ -1141,11 +1139,7 @@ async fn resume_candidate_matches_cwd_reads_latest_turn_context() -> std::io::Re
collaboration_mode: None,
realtime_active: None,
effort: None,
summary: ReasoningSummaryConfig::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}),
};
writeln!(file, "{}", serde_json::to_string(&turn_context)?)?;
+3 -19
View File
@@ -156,7 +156,6 @@ mod tests {
use chrono::DateTime;
use chrono::Utc;
use codex_protocol::ThreadId;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::models::ContentItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ReasoningEffort;
@@ -339,7 +338,6 @@ mod tests {
&mut metadata,
&RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
trace_id: None,
cwd: PathBuf::from("/parent/workspace"),
current_date: None,
timezone: None,
@@ -353,11 +351,7 @@ mod tests {
collaboration_mode: None,
realtime_active: None,
effort: None,
summary: ReasoningSummary::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}),
"test-provider",
);
@@ -379,7 +373,6 @@ mod tests {
&mut metadata,
&RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
trace_id: None,
cwd: PathBuf::from("/fallback/workspace"),
current_date: None,
timezone: None,
@@ -393,11 +386,7 @@ mod tests {
collaboration_mode: None,
realtime_active: None,
effort: Some(ReasoningEffort::High),
summary: ReasoningSummary::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}),
"test-provider",
);
@@ -413,7 +402,6 @@ mod tests {
&mut metadata,
&RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
trace_id: None,
cwd: PathBuf::from("/fallback/workspace"),
current_date: None,
timezone: None,
@@ -427,11 +415,7 @@ mod tests {
collaboration_mode: None,
realtime_active: None,
effort: Some(ReasoningEffort::High),
summary: ReasoningSummary::Auto,
user_instructions: None,
developer_instructions: None,
final_output_json_schema: None,
truncation_policy: None,
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}),
"test-provider",
);