Files
codex/codex-rs/core/src/session/step_context.rs
T
pakrym-oai f92655d07f Preempt model responses when new user input arrives (#48141)
## Why

With `instant_interrupt` enabled, new user input should reach the model without waiting for an unfinished response or stream retry backoff.

## What changed

- Interrupt request setup, response streaming, and retry backoff when user input arrives, then continue the turn with the queued input.
- Reset the WebSocket connection and continuation state after preemption so the next request sends full history.
- Drain pending input after a preempted step even when compaction leaves the estimated context above the token limit.

## Testing

Add regression coverage for WebSocket reconnection with full history, interrupted retry backoff, input queued during compaction, and yielding running code-mode calls. Add a streaming scenario that preserves completed commentary while excluding unfinished assistant text from the replacement request.

GitOrigin-RevId: b7e42b6afffbf87da15af05e0850af8579d1353f
2026-09-25 17:05:53 +00:00

65 lines
3.0 KiB
Rust

//! Request-scoped settings and capabilities, including the durable context snapshot.
use std::sync::Arc;
use crate::agents_md::LoadedAgentsMd;
use crate::config::TokenBudgetConfig;
use crate::environment_selection::TurnEnvironmentSnapshot;
use crate::realtime_conversation::RealtimeConversationSnapshot;
use crate::session::step_settings::ResolvedStepSettings;
use crate::session::turn_context::TurnContext;
use crate::tools::router::ToolRouter;
use codex_exec_server::ExecutorCapabilityDiscoverySnapshot;
use codex_exec_server::ResolvedSelectedCapabilityRoot;
use codex_mcp::McpBinding;
use codex_otel::SessionTelemetry;
use codex_protocol::items::ModelInvocationContext;
use codex_protocol::protocol::TurnContextItem;
use tokio_util::sync::CancellationToken;
/// Request-scoped state that may change between model sampling requests.
pub(crate) struct StepContext {
pub(crate) turn: Arc<TurnContext>,
/// Preempts this request and yields its code-mode observations when user input arrives.
pub(crate) preempt: Option<CancellationToken>,
/// Realtime call activity and instructions captured for this sampling request.
pub(crate) realtime: RealtimeConversationSnapshot,
/// One immutable settings version captured before request preparation.
pub(crate) settings: Arc<ResolvedStepSettings>,
/// Frozen turn preferences resolved against this step's captured model.
pub(crate) token_budget: Option<TokenBudgetConfig>,
/// Telemetry context tagged with this sampling request's model.
pub(crate) session_telemetry: SessionTelemetry,
pub(crate) environments: TurnEnvironmentSnapshot,
/// Capability roots bound to ready environments in this exact step.
pub(crate) selected_capability_roots: Vec<ResolvedSelectedCapabilityRoot>,
/// Executor-materialized capability files shared by MCP and skills in this exact step.
pub(crate) executor_capability_discovery: Option<Arc<ExecutorCapabilityDiscoverySnapshot>>,
/// The exact MCP connections, configuration, and catalog captured for this step.
pub(crate) mcp: Arc<McpBinding>,
/// The finalized tool plan advertised and executed for this exact sampling request.
pub(crate) tool_router: Arc<ToolRouter>,
/// The canonical AGENTS.md value observed with this environment snapshot.
pub(crate) loaded_agents_md: Option<Arc<LoadedAgentsMd>>,
}
impl StepContext {
/// Persist the context captured for this request, even after a live update.
pub(crate) fn to_turn_context_item(&self) -> TurnContextItem {
let mut item = self.turn.to_turn_context_item();
item.realtime_active = Some(self.realtime.active);
item.summary = self.settings.reasoning_summary;
item
}
pub(crate) fn model_context(&self) -> ModelInvocationContext {
ModelInvocationContext {
model_slug: self.settings.model_info.slug.clone(),
reasoning_effort: self
.settings
.effective_reasoning_effort()
.map(|effort| effort.to_string()),
}
}
}