mirror of
https://github.com/openai/codex.git
synced 2026-11-09 20:50:33 +00:00
## Why Reasoning configuration changes need to retain their position and trusted provenance when model history is persisted and replayed. Client-injected history must not be able to forge these controls. ## What changed - Add a typed `configuration_update` response item carrying reasoning effort, including custom model-defined values. - Persist harness-authored updates with provenance and preserve them across history reconstruction, thread resume, raw response notifications, and agent forks. - Exclude untrusted configuration updates from model history, strip client-supplied provenance metadata, and reject configuration updates supplied as turn input. - Export the new item through the JSON and TypeScript app-server schemas and classify it in telemetry and persistence metrics. ## Testing - Cover serialization, provenance persistence, history filtering and rollback, resume reconstruction, and injection attempts before and after restart. GitOrigin-RevId: eb5559d2b52b7a931621e7c9812f009ff9fb8939
207 lines
8.2 KiB
Rust
207 lines
8.2 KiB
Rust
use crate::RolloutItem;
|
|
use crate::protocol::EventMsg;
|
|
use codex_extension_items::ExtensionItem;
|
|
use codex_protocol::items::TurnItem;
|
|
use codex_protocol::models::ResponseItem;
|
|
use codex_protocol::protocol::SubAgentActivityKind;
|
|
use codex_protocol::protocol::ThreadHistoryMode;
|
|
|
|
/// Whether a rollout `item` should be persisted in rollout files.
|
|
pub fn is_persisted_rollout_item(item: &RolloutItem, history_mode: ThreadHistoryMode) -> bool {
|
|
match item {
|
|
RolloutItem::ResponseItem(item) => should_persist_response_item(&item.item),
|
|
RolloutItem::InterAgentCommunication(_)
|
|
| RolloutItem::InterAgentCommunicationMetadata { .. } => true,
|
|
RolloutItem::EventMsg(ev) => should_persist_event_msg(ev, history_mode),
|
|
RolloutItem::RealtimeItem(_) => matches!(history_mode, ThreadHistoryMode::Paginated),
|
|
// Persist Codex executive markers so we can analyze flows (e.g., compaction, API turns).
|
|
RolloutItem::Compacted(_)
|
|
| RolloutItem::TurnContext(_)
|
|
| RolloutItem::TokenUsageRecord(_)
|
|
| RolloutItem::WorldState(_)
|
|
| RolloutItem::RetainedContext(_)
|
|
| RolloutItem::SecurityRiskScore(_)
|
|
| RolloutItem::SessionMeta(_) => true,
|
|
}
|
|
}
|
|
|
|
/// Return the rollout items that should be persisted for a live append.
|
|
pub fn persisted_rollout_items(
|
|
items: &[RolloutItem],
|
|
history_mode: ThreadHistoryMode,
|
|
) -> Vec<RolloutItem> {
|
|
let mut persisted = Vec::new();
|
|
for item in items {
|
|
if is_persisted_rollout_item(item, history_mode) {
|
|
persisted.push(item.clone());
|
|
}
|
|
}
|
|
persisted
|
|
}
|
|
|
|
/// Whether a `ResponseItem` should be persisted in rollout files.
|
|
#[inline]
|
|
pub fn should_persist_response_item(item: &ResponseItem) -> bool {
|
|
match item {
|
|
ResponseItem::Message { .. }
|
|
| ResponseItem::AgentMessage { .. }
|
|
| ResponseItem::Reasoning { .. }
|
|
| ResponseItem::LocalShellCall { .. }
|
|
| ResponseItem::FunctionCall { .. }
|
|
| ResponseItem::ToolSearchCall { .. }
|
|
| ResponseItem::FunctionCallOutput { .. }
|
|
| ResponseItem::ToolSearchOutput { .. }
|
|
| ResponseItem::CustomToolCall { .. }
|
|
| ResponseItem::CustomToolCallOutput { .. }
|
|
| ResponseItem::WebSearchCall { .. }
|
|
| ResponseItem::ImageGenerationCall { .. }
|
|
| ResponseItem::ConfigurationUpdate { .. }
|
|
| ResponseItem::Compaction { .. }
|
|
| ResponseItem::ContextCompaction { .. } => true,
|
|
ResponseItem::AdditionalTools { .. }
|
|
| ResponseItem::CompactionTrigger { .. }
|
|
| ResponseItem::Other => false,
|
|
}
|
|
}
|
|
|
|
/// Whether a `ResponseItem` should be persisted for the memories.
|
|
#[inline]
|
|
pub fn should_persist_response_item_for_memories(item: &ResponseItem) -> bool {
|
|
match item {
|
|
ResponseItem::Message { role, .. } => role != "developer",
|
|
ResponseItem::AgentMessage { .. }
|
|
| ResponseItem::LocalShellCall { .. }
|
|
| ResponseItem::FunctionCall { .. }
|
|
| ResponseItem::ToolSearchCall { .. }
|
|
| ResponseItem::FunctionCallOutput { .. }
|
|
| ResponseItem::ToolSearchOutput { .. }
|
|
| ResponseItem::CustomToolCall { .. }
|
|
| ResponseItem::CustomToolCallOutput { .. }
|
|
| ResponseItem::WebSearchCall { .. } => true,
|
|
ResponseItem::AdditionalTools { .. }
|
|
| ResponseItem::Reasoning { .. }
|
|
| ResponseItem::ConfigurationUpdate { .. }
|
|
| ResponseItem::ImageGenerationCall { .. }
|
|
| ResponseItem::Compaction { .. }
|
|
| ResponseItem::CompactionTrigger { .. }
|
|
| ResponseItem::ContextCompaction { .. }
|
|
| ResponseItem::Other => false,
|
|
}
|
|
}
|
|
|
|
/// Whether an `EventMsg` should be persisted in rollout files.
|
|
#[inline]
|
|
pub fn should_persist_event_msg(ev: &EventMsg, history_mode: ThreadHistoryMode) -> bool {
|
|
match ev {
|
|
EventMsg::ItemCompleted(event) => {
|
|
// Paginated rollouts store TurnItems.
|
|
// Legacy rollouts keep only items with no lossless raw ResponseItem or legacy
|
|
// equivalent.
|
|
matches!(history_mode, ThreadHistoryMode::Paginated)
|
|
|| matches!(
|
|
event.item,
|
|
TurnItem::FunctionCallOutput(_)
|
|
| TurnItem::Plan(_)
|
|
| TurnItem::Extension(ExtensionItem::Sleep(_))
|
|
)
|
|
|| matches!(
|
|
&event.item,
|
|
TurnItem::SubAgentActivity(item)
|
|
if item.kind == SubAgentActivityKind::Completed
|
|
)
|
|
}
|
|
EventMsg::TokenCount(_)
|
|
| EventMsg::ThreadGoalUpdated(_)
|
|
| EventMsg::ThreadRolledBack(_)
|
|
| EventMsg::TurnAborted(_)
|
|
| EventMsg::TurnStarted(_)
|
|
| EventMsg::TurnComplete(_)
|
|
| EventMsg::ThreadSettingsApplied(_) => true,
|
|
|
|
// Only persist these legacy events when the thread's history mode is Legacy.
|
|
// New, paginated rollouts persist ItemCompleted events with TurnItems.
|
|
EventMsg::UserMessage(_)
|
|
| EventMsg::AgentMessage(_)
|
|
| EventMsg::AgentReasoning(_)
|
|
| EventMsg::AgentReasoningRawContent(_)
|
|
| EventMsg::EnteredReviewMode(_)
|
|
| EventMsg::ExitedReviewMode(_)
|
|
| EventMsg::PatchApplyEnd(_)
|
|
| EventMsg::ContextCompacted(_)
|
|
| EventMsg::McpToolCallEnd(_)
|
|
| EventMsg::WebSearchEnd(_)
|
|
| EventMsg::ImageGenerationEnd(_) => {
|
|
matches!(history_mode, ThreadHistoryMode::Legacy)
|
|
}
|
|
EventMsg::SubAgentActivity(event) => {
|
|
matches!(history_mode, ThreadHistoryMode::Legacy)
|
|
&& event.kind != SubAgentActivityKind::Completed
|
|
}
|
|
|
|
// Transient, non-durable events.
|
|
EventMsg::Error(_)
|
|
| EventMsg::ThreadQueueChanged(_)
|
|
| EventMsg::GuardianAssessment(_)
|
|
| EventMsg::ExecCommandEnd(_)
|
|
| EventMsg::ViewImageToolCall(_)
|
|
| EventMsg::CollabAgentSpawnEnd(_)
|
|
| EventMsg::CollabAgentInteractionEnd(_)
|
|
| EventMsg::CollabWaitingEnd(_)
|
|
| EventMsg::CollabCloseEnd(_)
|
|
| EventMsg::CollabResumeEnd(_)
|
|
| EventMsg::DynamicToolCallRequest(_)
|
|
| EventMsg::DynamicToolCallResponse(_)
|
|
| EventMsg::Warning(_)
|
|
| EventMsg::AuthRecoveryStarted(_)
|
|
| EventMsg::AuthRecoveryCompleted(_)
|
|
| EventMsg::GuardianWarning(_)
|
|
| EventMsg::RealtimeConversationStarted(_)
|
|
| EventMsg::RealtimeConversationSdp(_)
|
|
| EventMsg::RealtimeConversationRealtime(_)
|
|
| EventMsg::RealtimeConversationClosed(_)
|
|
| EventMsg::SafetyBuffering(_)
|
|
| EventMsg::ModelReroute(_)
|
|
| EventMsg::ModelVerification(_)
|
|
| EventMsg::TurnModerationMetadata(_)
|
|
| EventMsg::AgentReasoningSectionBreak(_)
|
|
| EventMsg::RawResponseItem(_)
|
|
| EventMsg::RawResponseCompleted(_)
|
|
| EventMsg::SessionConfigured(_)
|
|
| EventMsg::EnvironmentConnected(_)
|
|
| EventMsg::EnvironmentDisconnected(_)
|
|
| EventMsg::McpToolCallBegin(_)
|
|
| EventMsg::ExecCommandBegin(_)
|
|
| EventMsg::TerminalInteraction(_)
|
|
| EventMsg::ExecCommandOutputDelta(_)
|
|
| EventMsg::ExecApprovalRequest(_)
|
|
| EventMsg::RequestPermissions(_)
|
|
| EventMsg::RequestUserInput(_)
|
|
| EventMsg::ElicitationRequest(_)
|
|
| EventMsg::ApplyPatchApprovalRequest(_)
|
|
| EventMsg::StreamError(_)
|
|
| EventMsg::PatchApplyBegin(_)
|
|
| EventMsg::PatchApplyUpdated(_)
|
|
| EventMsg::TurnDiff(_)
|
|
| EventMsg::RealtimeConversationListVoicesResponse(_)
|
|
| EventMsg::McpStartupUpdate(_)
|
|
| EventMsg::McpStartupComplete(_)
|
|
| EventMsg::WebSearchBegin(_)
|
|
| EventMsg::PlanUpdate(_)
|
|
| EventMsg::ShutdownComplete
|
|
| EventMsg::DeprecationNotice(_)
|
|
| EventMsg::ItemStarted(_)
|
|
| EventMsg::HookStarted(_)
|
|
| EventMsg::HookCompleted(_)
|
|
| EventMsg::AgentMessageContentDelta(_)
|
|
| EventMsg::PlanDelta(_)
|
|
| EventMsg::ReasoningContentDelta(_)
|
|
| EventMsg::ReasoningRawContentDelta(_)
|
|
| EventMsg::ImageGenerationBegin(_)
|
|
| EventMsg::CollabAgentSpawnBegin(_)
|
|
| EventMsg::CollabAgentInteractionBegin(_)
|
|
| EventMsg::CollabWaitingBegin(_)
|
|
| EventMsg::CollabCloseBegin(_)
|
|
| EventMsg::CollabResumeBegin(_) => false,
|
|
}
|
|
}
|