From f50c02d7bcd4c06a23173389da8ed2c68c03d81d Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Thu, 30 Apr 2026 20:03:26 -0700 Subject: [PATCH] [codex] Remove unused event messages (#20511) ## Why Several legacy `EventMsg` variants were still emitted or mapped even though clients either ignored them or had moved to item/lifecycle events. `Op::Undo` had also degraded to an unavailable shim, so this removes that dead task path instead of preserving a command that cannot do useful work. `McpStartupComplete`, `WebSearchBegin`, and `ImageGenerationBegin` are intentionally kept because useful consumers still depend on them: MCP startup completion drives readiness behavior, and the begin events let app-server/core consumers surface in-progress web-search and image-generation items before the final payload arrives. ## What Changed - Removed weak legacy event variants and payloads from `codex-protocol`, including legacy agent deltas, background events, and undo lifecycle events. - Kept/restored `EventMsg::McpStartupComplete`, `EventMsg::WebSearchBegin`, and `EventMsg::ImageGenerationBegin` with serializer and emission coverage. - Updated core, rollout, MCP server, app-server thread history, review/delegate filtering, and tests to rely on the useful replacement events that remain. - Removed `Op::Undo`, `UndoTask`, the undo test module, and stale TUI slash-command comments. - Stopped agent job/background progress and compaction retry notices from emitting `BackgroundEvent` payloads. ## Verification - `cargo check -p codex-protocol -p codex-app-server-protocol -p codex-core -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - `cargo test -p codex-protocol -p codex-app-server-protocol -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - `cargo test -p codex-core --test all suite::items` - `just fix -p codex-protocol -p codex-app-server-protocol -p codex-core -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - Earlier coverage on this PR also included `codex-mcp`, `codex-tui`, core library tests, MCP/plugin/delegate/review/agent job tests, and MCP startup TUI tests. --- .../src/protocol/thread_history.rs | 1 - codex-rs/core/src/codex_delegate.rs | 5 - codex-rs/core/src/compact.rs | 12 -- codex-rs/core/src/mcp_skill_dependencies.rs | 16 -- codex-rs/core/src/session/handlers.rs | 11 -- codex-rs/core/src/session/mod.rs | 12 -- codex-rs/core/src/session/turn.rs | 8 +- codex-rs/core/src/tasks/mod.rs | 2 - codex-rs/core/src/tasks/review.rs | 2 - codex-rs/core/src/tasks/undo.rs | 72 --------- .../core/src/tools/handlers/agent_jobs.rs | 141 ------------------ codex-rs/core/tests/suite/codex_delegate.rs | 6 - codex-rs/core/tests/suite/compact.rs | 10 -- codex-rs/core/tests/suite/items.rs | 20 --- codex-rs/core/tests/suite/mod.rs | 1 - codex-rs/core/tests/suite/review.rs | 4 - codex-rs/core/tests/suite/undo.rs | 43 ------ codex-rs/mcp-server/src/codex_tool_runner.rs | 10 -- codex-rs/protocol/src/protocol.rs | 68 +-------- codex-rs/rollout-trace/src/protocol_event.rs | 12 -- codex-rs/rollout/src/policy.rs | 12 +- codex-rs/tui/src/chatwidget/slash_dispatch.rs | 3 - codex-rs/tui/src/slash_command.rs | 3 - 23 files changed, 7 insertions(+), 467 deletions(-) delete mode 100644 codex-rs/core/src/tasks/undo.rs delete mode 100644 codex-rs/core/tests/suite/undo.rs diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index 019c9fa83e..c95637fe66 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -217,7 +217,6 @@ impl ThreadHistoryBuilder { EventMsg::Error(payload) => self.handle_error(payload), EventMsg::TokenCount(_) => {} EventMsg::ThreadRolledBack(payload) => self.handle_thread_rollback(payload), - EventMsg::UndoCompleted(_) => {} EventMsg::TurnAborted(payload) => self.handle_turn_aborted(payload), EventMsg::TurnStarted(payload) => self.handle_turn_started(payload), EventMsg::TurnComplete(payload) => self.handle_turn_complete(payload), diff --git a/codex-rs/core/src/codex_delegate.rs b/codex-rs/core/src/codex_delegate.rs index f3df3cd4c6..01907a5594 100644 --- a/codex-rs/core/src/codex_delegate.rs +++ b/codex-rs/core/src/codex_delegate.rs @@ -262,11 +262,6 @@ async fn forward_events( Err(_) => break, }; match event { - // ignore all legacy delta events - Event { - id: _, - msg: EventMsg::AgentMessageDelta(_) | EventMsg::AgentReasoningDelta(_), - } => {} Event { id: _, msg: EventMsg::TokenCount(_), diff --git a/codex-rs/core/src/compact.rs b/codex-rs/core/src/compact.rs index 1ebc307e33..58a2610fcb 100644 --- a/codex-rs/core/src/compact.rs +++ b/codex-rs/core/src/compact.rs @@ -165,8 +165,6 @@ async fn run_compact_task_inner_impl( turn_context.truncation_policy, ); - let mut truncated_count = 0usize; - let max_retries = turn_context.provider.info().stream_max_retries(); let mut retries = 0; let mut client_session = sess.services.model_client.new_session(); @@ -198,15 +196,6 @@ async fn run_compact_task_inner_impl( match attempt_result { Ok(()) => { - if truncated_count > 0 { - sess.notify_background_event( - turn_context.as_ref(), - format!( - "Trimmed {truncated_count} older thread item(s) before compacting so the prompt fits the model context window." - ), - ) - .await; - } break; } Err(CodexErr::Interrupted) => { @@ -219,7 +208,6 @@ async fn run_compact_task_inner_impl( "Context window exceeded while compacting; removing oldest history item. Error: {e}" ); history.remove_first_item(); - truncated_count += 1; retries = 0; continue; } diff --git a/codex-rs/core/src/mcp_skill_dependencies.rs b/codex-rs/core/src/mcp_skill_dependencies.rs index 882b09b9f0..c24a6f3a48 100644 --- a/codex-rs/core/src/mcp_skill_dependencies.rs +++ b/codex-rs/core/src/mcp_skill_dependencies.rs @@ -136,14 +136,6 @@ pub(crate) async fn maybe_install_mcp_dependencies( } }; - sess.notify_background_event( - turn_context, - format!( - "Authenticating MCP {name}... Follow instructions in your browser if prompted." - ), - ) - .await; - let resolved_scopes = resolve_oauth_scopes( /*explicit_scopes*/ None, server_config.scopes.clone(), @@ -164,14 +156,6 @@ pub(crate) async fn maybe_install_mcp_dependencies( if let Err(err) = first_attempt { if should_retry_without_scopes(&resolved_scopes, &err) { - sess.notify_background_event( - turn_context, - format!( - "Retrying MCP {name} authentication without scopes after provider rejection." - ), - ) - .await; - if let Err(err) = perform_oauth_login( &name, &oauth_config.url, diff --git a/codex-rs/core/src/session/handlers.rs b/codex-rs/core/src/session/handlers.rs index 4baabd56cd..612eaf5d65 100644 --- a/codex-rs/core/src/session/handlers.rs +++ b/codex-rs/core/src/session/handlers.rs @@ -27,7 +27,6 @@ use codex_utils_absolute_path::AbsolutePathBuf; use crate::review_prompts::resolve_review_request; use crate::tasks::CompactTask; -use crate::tasks::UndoTask; use crate::tasks::UserShellCommandMode; use crate::tasks::UserShellCommandTask; use crate::tasks::execute_user_shell_command; @@ -649,12 +648,6 @@ pub async fn list_skills(sess: &Session, sub_id: String, cwds: Vec, for sess.send_event_raw(event).await; } -pub async fn undo(sess: &Arc, sub_id: String) { - let turn_context = sess.new_default_turn_with_sub_id(sub_id).await; - sess.spawn_task(turn_context, Vec::new(), UndoTask::new()) - .await; -} - pub async fn compact(sess: &Arc, sub_id: String) { let turn_context = sess.new_default_turn_with_sub_id(sub_id).await; @@ -1118,10 +1111,6 @@ pub(super) async fn submission_loop( list_skills(&sess, sub.id.clone(), cwds, force_reload).await; false } - Op::Undo => { - undo(&sess, sub.id.clone()).await; - false - } Op::Compact => { compact(&sess, sub.id.clone()).await; false diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index 8333fd2dd3..b08d31c205 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -318,7 +318,6 @@ use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::protocol::ApplyPatchApprovalRequestEvent; use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::BackgroundEventEvent; use codex_protocol::protocol::CodexErrorInfo; use codex_protocol::protocol::CompactedItem; use codex_protocol::protocol::DeprecationNoticeEvent; @@ -2938,17 +2937,6 @@ impl Session { self.ensure_rollout_materialized().await; } - pub(crate) async fn notify_background_event( - &self, - turn_context: &TurnContext, - message: impl Into, - ) { - let event = EventMsg::BackgroundEvent(BackgroundEventEvent { - message: message.into(), - }); - self.send_event(turn_context, event).await; - } - pub(crate) async fn notify_stream_error( &self, turn_context: &TurnContext, diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 286aa2d687..faf869f497 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -336,7 +336,7 @@ pub(crate) async fn run_turn( record_additional_contexts(&sess, &turn_context, additional_contexts).await; if !input.is_empty() { // Track the previous-turn baseline from the regular user-turn path only so - // standalone tasks (compact/shell/review/undo) cannot suppress future + // standalone tasks (compact/shell/review) cannot suppress future // model/realtime injections. sess.set_previous_turn_settings(Some(PreviousTurnSettings { model: turn_context.model_info.slug.clone(), @@ -1443,11 +1443,8 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option { | EventMsg::TurnComplete(_) | EventMsg::TokenCount(_) | EventMsg::UserMessage(_) - | EventMsg::AgentMessageDelta(_) | EventMsg::AgentReasoning(_) - | EventMsg::AgentReasoningDelta(_) | EventMsg::AgentReasoningRawContent(_) - | EventMsg::AgentReasoningRawContentDelta(_) | EventMsg::AgentReasoningSectionBreak(_) | EventMsg::SessionConfigured(_) | EventMsg::ThreadNameUpdated(_) @@ -1477,9 +1474,6 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option { | EventMsg::ElicitationRequest(_) | EventMsg::ApplyPatchApprovalRequest(_) | EventMsg::DeprecationNotice(_) - | EventMsg::BackgroundEvent(_) - | EventMsg::UndoStarted(_) - | EventMsg::UndoCompleted(_) | EventMsg::StreamError(_) | EventMsg::TurnDiff(_) | EventMsg::GetHistoryEntryResponse(_) diff --git a/codex-rs/core/src/tasks/mod.rs b/codex-rs/core/src/tasks/mod.rs index 91078c50ce..17a2728601 100644 --- a/codex-rs/core/src/tasks/mod.rs +++ b/codex-rs/core/src/tasks/mod.rs @@ -1,7 +1,6 @@ mod compact; mod regular; mod review; -mod undo; mod user_shell; use std::sync::Arc; @@ -57,7 +56,6 @@ use codex_protocol::models::ContentItem; pub(crate) use compact::CompactTask; pub(crate) use regular::RegularTask; pub(crate) use review::ReviewTask; -pub(crate) use undo::UndoTask; pub(crate) use user_shell::UserShellCommandMode; pub(crate) use user_shell::UserShellCommandTask; pub(crate) use user_shell::execute_user_shell_command; diff --git a/codex-rs/core/src/tasks/review.rs b/codex-rs/core/src/tasks/review.rs index c81c011f47..f89c7d062f 100644 --- a/codex-rs/core/src/tasks/review.rs +++ b/codex-rs/core/src/tasks/review.rs @@ -6,7 +6,6 @@ use codex_protocol::items::TurnItem; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::AgentMessageContentDeltaEvent; -use codex_protocol::protocol::AgentMessageDeltaEvent; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; @@ -162,7 +161,6 @@ async fn process_review_events( item: TurnItem::AgentMessage(_), .. }) - | EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { .. }) | EventMsg::AgentMessageContentDelta(AgentMessageContentDeltaEvent { .. }) => {} EventMsg::TurnComplete(task_complete) => { // Parse review output from the last agent message (if present). diff --git a/codex-rs/core/src/tasks/undo.rs b/codex-rs/core/src/tasks/undo.rs deleted file mode 100644 index 2abd0d2686..0000000000 --- a/codex-rs/core/src/tasks/undo.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::sync::Arc; - -use crate::session::turn_context::TurnContext; -use crate::state::TaskKind; -use crate::tasks::SessionTask; -use crate::tasks::SessionTaskContext; -use codex_protocol::protocol::EventMsg; -use codex_protocol::protocol::UndoCompletedEvent; -use codex_protocol::protocol::UndoStartedEvent; -use codex_protocol::user_input::UserInput; -use tokio_util::sync::CancellationToken; - -pub(crate) struct UndoTask; - -impl UndoTask { - pub(crate) fn new() -> Self { - Self - } -} - -impl SessionTask for UndoTask { - fn kind(&self) -> TaskKind { - TaskKind::Regular - } - - fn span_name(&self) -> &'static str { - "session_task.undo" - } - - async fn run( - self: Arc, - session: Arc, - ctx: Arc, - _input: Vec, - cancellation_token: CancellationToken, - ) -> Option { - session - .session - .services - .session_telemetry - .counter("codex.task.undo", /*inc*/ 1, &[]); - let sess = session.clone_session(); - sess.send_event( - ctx.as_ref(), - EventMsg::UndoStarted(UndoStartedEvent { - message: Some("Undo in progress...".to_string()), - }), - ) - .await; - - if cancellation_token.is_cancelled() { - sess.send_event( - ctx.as_ref(), - EventMsg::UndoCompleted(UndoCompletedEvent { - success: false, - message: Some("Undo cancelled.".to_string()), - }), - ) - .await; - return None; - } - - let completed = UndoCompletedEvent { - success: false, - message: Some("Undo is no longer available.".to_string()), - }; - - sess.send_event(ctx.as_ref(), EventMsg::UndoCompleted(completed)) - .await; - None - } -} diff --git a/codex-rs/core/src/tools/handlers/agent_jobs.rs b/codex-rs/core/src/tools/handlers/agent_jobs.rs index bb5b82190a..d5f719febf 100644 --- a/codex-rs/core/src/tools/handlers/agent_jobs.rs +++ b/codex-rs/core/src/tools/handlers/agent_jobs.rs @@ -41,7 +41,6 @@ pub struct BatchJobHandler; const DEFAULT_AGENT_JOB_CONCURRENCY: usize = 16; const MAX_AGENT_JOB_CONCURRENCY: usize = 64; const STATUS_POLL_INTERVAL: Duration = Duration::from_millis(250); -const PROGRESS_EMIT_INTERVAL: Duration = Duration::from_secs(1); const DEFAULT_AGENT_JOB_ITEM_TIMEOUT: Duration = Duration::from_secs(60 * 30); #[derive(Debug, Deserialize)] @@ -83,17 +82,6 @@ struct AgentJobFailureSummary { last_error: String, } -#[derive(Debug, Serialize)] -struct AgentJobProgressUpdate { - job_id: String, - total_items: usize, - pending_items: usize, - running_items: usize, - completed_items: usize, - failed_items: usize, - eta_seconds: Option, -} - #[derive(Debug, Serialize)] struct ReportAgentJobResultToolResult { accepted: bool, @@ -112,73 +100,6 @@ struct ActiveJobItem { status_rx: Option>, } -struct JobProgressEmitter { - started_at: Instant, - last_emit_at: Instant, - last_processed: usize, - last_failed: usize, -} - -impl JobProgressEmitter { - fn new() -> Self { - let now = Instant::now(); - let last_emit_at = now.checked_sub(PROGRESS_EMIT_INTERVAL).unwrap_or(now); - Self { - started_at: now, - last_emit_at, - last_processed: 0, - last_failed: 0, - } - } - - async fn maybe_emit( - &mut self, - session: &Session, - turn: &TurnContext, - job_id: &str, - progress: &codex_state::AgentJobProgress, - force: bool, - ) -> anyhow::Result<()> { - let processed = progress.completed_items + progress.failed_items; - let should_emit = force - || processed != self.last_processed - || progress.failed_items != self.last_failed - || self.last_emit_at.elapsed() >= PROGRESS_EMIT_INTERVAL; - if !should_emit { - return Ok(()); - } - let elapsed = self.started_at.elapsed().as_secs_f64(); - let eta_seconds = if processed > 0 && elapsed > 0.0 { - let remaining = progress.total_items.saturating_sub(processed) as f64; - let rate = processed as f64 / elapsed; - if rate > 0.0 { - Some((remaining / rate).round() as u64) - } else { - None - } - } else { - None - }; - let update = AgentJobProgressUpdate { - job_id: job_id.to_string(), - total_items: progress.total_items, - pending_items: progress.pending_items, - running_items: progress.running_items, - completed_items: progress.completed_items, - failed_items: progress.failed_items, - eta_seconds, - }; - let payload = serde_json::to_string(&update)?; - session - .notify_background_event(turn, format!("agent_job_progress:{payload}")) - .await; - self.last_emit_at = Instant::now(); - self.last_processed = processed; - self.last_failed = progress.failed_items; - Ok(()) - } -} - impl ToolHandler for BatchJobHandler { type Output = FunctionToolOutput; @@ -358,12 +279,6 @@ mod spawn_agents_on_csv { "failed to transition agent job {job_id} to running: {err}" )) })?; - let max_threads = turn.config.agent_max_threads; - let effective_concurrency = options.max_concurrency; - let message = format!( - "agent job concurrency: job_id={job_id} requested={requested_concurrency:?} max_threads={max_threads:?} effective={effective_concurrency}" - ); - let _ = session.notify_background_event(&turn, message).await; if let Err(err) = run_agent_job_loop( session.clone(), turn.clone(), @@ -584,7 +499,6 @@ async fn run_agent_job_loop( .ok_or_else(|| anyhow::anyhow!("agent job {job_id} was not found"))?; let runtime_timeout = job_runtime_timeout(&job); let mut active_items: HashMap = HashMap::new(); - let mut progress_emitter = JobProgressEmitter::new(); recover_running_items( session.clone(), db.clone(), @@ -593,16 +507,6 @@ async fn run_agent_job_loop( runtime_timeout, ) .await?; - let initial_progress = db.get_agent_job_progress(job_id.as_str()).await?; - progress_emitter - .maybe_emit( - &session, - &turn, - job_id.as_str(), - &initial_progress, - /*force*/ true, - ) - .await?; let mut cancel_requested = db.is_agent_job_cancelled(job_id.as_str()).await?; loop { @@ -610,12 +514,6 @@ async fn run_agent_job_loop( if !cancel_requested && db.is_agent_job_cancelled(job_id.as_str()).await? { cancel_requested = true; - let _ = session - .notify_background_event( - &turn, - format!("agent job {job_id} cancellation requested; stopping new workers"), - ) - .await; } if !cancel_requested && active_items.len() < options.max_concurrency { @@ -749,20 +647,9 @@ async fn run_agent_job_loop( ) .await?; active_items.remove(&thread_id); - let progress = db.get_agent_job_progress(job_id.as_str()).await?; - progress_emitter - .maybe_emit( - &session, - &turn, - job_id.as_str(), - &progress, - /*force*/ false, - ) - .await?; } } - let progress = db.get_agent_job_progress(job_id.as_str()).await?; if let Err(err) = export_job_csv_snapshot(db.clone(), &job).await { let message = format!("auto-export failed: {err}"); db.mark_agent_job_failed(job_id.as_str(), message.as_str()) @@ -771,37 +658,9 @@ async fn run_agent_job_loop( } let cancelled = cancel_requested || db.is_agent_job_cancelled(job_id.as_str()).await?; if cancelled { - let pending_items = progress.pending_items; - let message = - format!("agent job {job_id} cancelled with {pending_items} unprocessed items"); - let _ = session.notify_background_event(&turn, message).await; - progress_emitter - .maybe_emit( - &session, - &turn, - job_id.as_str(), - &progress, - /*force*/ true, - ) - .await?; return Ok(()); } - if progress.failed_items > 0 { - let failed_items = progress.failed_items; - let message = format!("agent job completed with {failed_items} failed items"); - let _ = session.notify_background_event(&turn, message).await; - } db.mark_agent_job_completed(job_id.as_str()).await?; - let progress = db.get_agent_job_progress(job_id.as_str()).await?; - progress_emitter - .maybe_emit( - &session, - &turn, - job_id.as_str(), - &progress, - /*force*/ true, - ) - .await?; Ok(()) } diff --git a/codex-rs/core/tests/suite/codex_delegate.rs b/codex-rs/core/tests/suite/codex_delegate.rs index 2ccb6fecba..12669a601c 100644 --- a/codex-rs/core/tests/suite/codex_delegate.rs +++ b/codex-rs/core/tests/suite/codex_delegate.rs @@ -229,21 +229,15 @@ async fn codex_delegate_ignores_legacy_deltas() { .expect("submit review"); let mut reasoning_delta_count = 0; - let mut legacy_reasoning_delta_count = 0; loop { let ev = wait_for_event(&test.codex, |_| true).await; match ev { EventMsg::ReasoningContentDelta(_) => reasoning_delta_count += 1, - EventMsg::AgentReasoningDelta(_) => legacy_reasoning_delta_count += 1, EventMsg::TurnComplete(_) => break, _ => {} } } assert_eq!(reasoning_delta_count, 1, "expected one new reasoning delta"); - assert_eq!( - legacy_reasoning_delta_count, 1, - "expected one legacy reasoning delta" - ); } diff --git a/codex-rs/core/tests/suite/compact.rs b/codex-rs/core/tests/suite/compact.rs index 629c370103..1d770649d0 100644 --- a/codex-rs/core/tests/suite/compact.rs +++ b/codex-rs/core/tests/suite/compact.rs @@ -2149,16 +2149,6 @@ async fn manual_compact_retries_after_context_window_error() { wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; codex.submit(Op::Compact).await.unwrap(); - let EventMsg::BackgroundEvent(event) = - wait_for_event(&codex, |ev| matches!(ev, EventMsg::BackgroundEvent(_))).await - else { - panic!("expected background event after compact retry"); - }; - assert!( - event.message.contains("Trimmed 1 older thread item"), - "background event should mention trimmed item count: {}", - event.message - ); let warning_event = wait_for_event(&codex, |ev| matches!(ev, EventMsg::Warning(_))).await; let EventMsg::Warning(WarningEvent { message }) = warning_event else { panic!("expected warning event after compact retry"); diff --git a/codex-rs/core/tests/suite/items.rs b/codex-rs/core/tests/suite/items.rs index 053f03ca90..2e60823c0c 100644 --- a/codex-rs/core/tests/suite/items.rs +++ b/codex-rs/core/tests/suite/items.rs @@ -503,11 +503,6 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> { _ => None, }) .await; - let legacy_delta = wait_for_event_match(&codex, |ev| match ev { - EventMsg::AgentMessageDelta(event) => Some(event.clone()), - _ => None, - }) - .await; let completed_item = wait_for_event_match(&codex, |ev| match ev { EventMsg::ItemCompleted(ItemCompletedEvent { item: TurnItem::AgentMessage(item), @@ -522,7 +517,6 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> { assert_eq!(delta_event.turn_id, started_turn_id); assert_eq!(delta_event.item_id, started_item.id); assert_eq!(delta_event.delta, "streamed response"); - assert_eq!(legacy_delta.delta, "streamed response"); assert_eq!(completed_item.id, started_item.id); Ok(()) @@ -1091,15 +1085,8 @@ async fn reasoning_content_delta_has_item_metadata() -> anyhow::Result<()> { _ => None, }) .await; - let legacy_delta = wait_for_event_match(&codex, |ev| match ev { - EventMsg::AgentReasoningDelta(event) => Some(event.clone()), - _ => None, - }) - .await; - assert_eq!(delta_event.item_id, reasoning_item.id); assert_eq!(delta_event.delta, "step one"); - assert_eq!(legacy_delta.delta, "step one"); Ok(()) } @@ -1152,15 +1139,8 @@ async fn reasoning_raw_content_delta_respects_flag() -> anyhow::Result<()> { _ => None, }) .await; - let legacy_delta = wait_for_event_match(&codex, |ev| match ev { - EventMsg::AgentReasoningRawContentDelta(event) => Some(event.clone()), - _ => None, - }) - .await; - assert_eq!(delta_event.item_id, reasoning_item.id); assert_eq!(delta_event.delta, "raw detail"); - assert_eq!(legacy_delta.delta, "raw detail"); Ok(()) } diff --git a/codex-rs/core/tests/suite/mod.rs b/codex-rs/core/tests/suite/mod.rs index bcf4e3d558..fb96e23c8b 100644 --- a/codex-rs/core/tests/suite/mod.rs +++ b/codex-rs/core/tests/suite/mod.rs @@ -102,7 +102,6 @@ mod tool_suggest; mod tools; mod truncation; mod turn_state; -mod undo; mod unified_exec; mod unstable_features_warning; mod user_notification; diff --git a/codex-rs/core/tests/suite/review.rs b/codex-rs/core/tests/suite/review.rs index e3b462a1c6..f371cdacad 100644 --- a/codex-rs/core/tests/suite/review.rs +++ b/codex-rs/core/tests/suite/review.rs @@ -233,7 +233,6 @@ async fn review_op_with_plain_text_emits_review_fallback() { /// Ensure review flow suppresses assistant-specific streaming/completion events: /// - AgentMessageContentDelta -/// - AgentMessageDelta (legacy) /// - ItemCompleted for TurnItem::AgentMessage // Windows CI only: bump to 4 workers to prevent SSE/event starvation and test timeouts. #[cfg_attr(windows, tokio::test(flavor = "multi_thread", worker_threads = 4))] @@ -290,9 +289,6 @@ async fn review_filters_agent_message_related_events() { EventMsg::AgentMessageContentDelta(_) => { panic!("unexpected AgentMessageContentDelta surfaced during review") } - EventMsg::AgentMessageDelta(_) => { - panic!("unexpected AgentMessageDelta surfaced during review") - } _ => false, }) .await; diff --git a/codex-rs/core/tests/suite/undo.rs b/codex-rs/core/tests/suite/undo.rs deleted file mode 100644 index afddb59c62..0000000000 --- a/codex-rs/core/tests/suite/undo.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![cfg(not(target_os = "windows"))] - -use std::sync::Arc; - -use anyhow::Result; -use codex_core::CodexThread; -use codex_protocol::protocol::EventMsg; -use codex_protocol::protocol::Op; -use codex_protocol::protocol::UndoCompletedEvent; -use core_test_support::test_codex::TestCodexHarness; -use core_test_support::test_codex::test_codex; -use core_test_support::wait_for_event_match; -use pretty_assertions::assert_eq; - -async fn undo_harness() -> Result { - TestCodexHarness::with_builder(test_codex().with_model("gpt-5.4")).await -} - -async fn invoke_undo(codex: &Arc) -> Result { - codex.submit(Op::Undo).await?; - let event = wait_for_event_match(codex, |msg| match msg { - EventMsg::UndoCompleted(done) => Some(done.clone()), - _ => None, - }) - .await; - Ok(event) -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn undo_reports_feature_removal() -> Result<()> { - let harness = undo_harness().await?; - let codex = Arc::clone(&harness.test().codex); - - let event = invoke_undo(&codex).await?; - - assert!(!event.success, "expected undo to fail"); - assert_eq!( - event.message.as_deref(), - Some("Undo is no longer available.") - ); - - Ok(()) -} diff --git a/codex-rs/mcp-server/src/codex_tool_runner.rs b/codex-rs/mcp-server/src/codex_tool_runner.rs index 46b786eba7..79b43122d9 100644 --- a/codex-rs/mcp-server/src/codex_tool_runner.rs +++ b/codex-rs/mcp-server/src/codex_tool_runner.rs @@ -328,12 +328,6 @@ async fn run_codex_tool_session_inner( EventMsg::ThreadGoalUpdated(_) => { // Ignore thread goal metadata updates in MCP tool runner. } - EventMsg::AgentMessageDelta(_) => { - // TODO: think how we want to support this in the MCP - } - EventMsg::AgentReasoningDelta(_) => { - // TODO: think how we want to support this in the MCP - } EventMsg::McpStartupUpdate(_) | EventMsg::McpStartupComplete(_) => { // Ignored in MCP tool runner. } @@ -341,7 +335,6 @@ async fn run_codex_tool_session_inner( // TODO: think how we want to support this in the MCP } EventMsg::AgentReasoningRawContent(_) - | EventMsg::AgentReasoningRawContentDelta(_) | EventMsg::TurnStarted(_) | EventMsg::TokenCount(_) | EventMsg::AgentReasoning(_) @@ -355,7 +348,6 @@ async fn run_codex_tool_session_inner( | EventMsg::TerminalInteraction(_) | EventMsg::ExecCommandOutputDelta(_) | EventMsg::ExecCommandEnd(_) - | EventMsg::BackgroundEvent(_) | EventMsg::StreamError(_) | EventMsg::PatchApplyBegin(_) | EventMsg::PatchApplyUpdated(_) @@ -381,8 +373,6 @@ async fn run_codex_tool_session_inner( | EventMsg::ReasoningContentDelta(_) | EventMsg::ReasoningRawContentDelta(_) | EventMsg::SkillsUpdateAvailable - | EventMsg::UndoStarted(_) - | EventMsg::UndoCompleted(_) | EventMsg::ExitedReviewMode(_) | EventMsg::RequestUserInput(_) | EventMsg::RequestPermissions(_) diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 9445c1994e..c3e4f5abaa 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -777,12 +777,6 @@ pub enum Op { /// model. SetThreadMemoryMode { mode: ThreadMemoryMode }, - /// Legacy request to undo a turn. - /// - /// The op is still accepted for compatibility, but ghost snapshots are no - /// longer produced so the request reports unavailable. - Undo, - /// Request Codex to drop the last N user turns from in-memory context. /// /// This does not attempt to revert local filesystem changes. Clients are @@ -911,7 +905,6 @@ impl Op { Self::Compact => "compact", Self::SetThreadName { .. } => "set_thread_name", Self::SetThreadMemoryMode { .. } => "set_thread_memory_mode", - Self::Undo => "undo", Self::ThreadRollback { .. } => "thread_rollback", Self::Review { .. } => "review", Self::ApproveGuardianDeniedAction { .. } => "approve_guardian_denied_action", @@ -1368,20 +1361,12 @@ pub enum EventMsg { /// User/system input message (what was sent to the model) UserMessage(UserMessageEvent), - /// Agent text output delta message - AgentMessageDelta(AgentMessageDeltaEvent), - /// Reasoning event from agent. AgentReasoning(AgentReasoningEvent), - /// Agent reasoning delta event from agent. - AgentReasoningDelta(AgentReasoningDeltaEvent), - /// Raw chain-of-thought from agent. AgentReasoningRawContent(AgentReasoningRawContentEvent), - /// Agent reasoning content delta event from agent. - AgentReasoningRawContentDelta(AgentReasoningRawContentDeltaEvent), /// Signaled when the model begins a new reasoning summary section (e.g., a new titled block). AgentReasoningSectionBreak(AgentReasoningSectionBreakEvent), @@ -1447,12 +1432,6 @@ pub enum EventMsg { /// deprecated and should be phased out. DeprecationNotice(DeprecationNoticeEvent), - BackgroundEvent(BackgroundEventEvent), - - UndoStarted(UndoStartedEvent), - - UndoCompleted(UndoCompletedEvent), - /// Notification that a model stream experienced an error or disconnect /// and the system is handling it (e.g., retrying with backoff). StreamError(StreamErrorEvent), @@ -1894,9 +1873,7 @@ pub struct AgentMessageContentDeltaEvent { impl HasLegacyEvent for AgentMessageContentDeltaEvent { fn as_legacy_events(&self, _: bool) -> Vec { - vec![EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { - delta: self.delta.clone(), - })] + Vec::new() } } @@ -1921,9 +1898,7 @@ pub struct ReasoningContentDeltaEvent { impl HasLegacyEvent for ReasoningContentDeltaEvent { fn as_legacy_events(&self, _: bool) -> Vec { - vec![EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent { - delta: self.delta.clone(), - })] + Vec::new() } } @@ -1940,11 +1915,7 @@ pub struct ReasoningRawContentDeltaEvent { impl HasLegacyEvent for ReasoningRawContentDeltaEvent { fn as_legacy_events(&self, _: bool) -> Vec { - vec![EventMsg::AgentReasoningRawContentDelta( - AgentReasoningRawContentDeltaEvent { - delta: self.delta.clone(), - }, - )] + Vec::new() } } @@ -2309,11 +2280,6 @@ pub struct UserMessageEvent { pub text_elements: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct AgentMessageDeltaEvent { - pub delta: String, -} - #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningEvent { pub text: String, @@ -2324,11 +2290,6 @@ pub struct AgentReasoningRawContentEvent { pub text: String, } -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct AgentReasoningRawContentDeltaEvent { - pub delta: String, -} - #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningSectionBreakEvent { // load with default value so it's backward compatible with the old format. @@ -2338,11 +2299,6 @@ pub struct AgentReasoningSectionBreakEvent { pub summary_index: i64, } -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct AgentReasoningDeltaEvent { - pub delta: String, -} - #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS, PartialEq)] pub struct McpInvocation { /// Name of the MCP server as defined in the config. @@ -3188,11 +3144,6 @@ pub struct TerminalInteractionEvent { pub stdin: String, } -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct BackgroundEventEvent { - pub message: String, -} - #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct DeprecationNoticeEvent { /// Concise summary of what is deprecated. @@ -3202,19 +3153,6 @@ pub struct DeprecationNoticeEvent { pub details: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct UndoStartedEvent { - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, -} - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] -pub struct UndoCompletedEvent { - pub success: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, -} - #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ThreadRolledBackEvent { /// Number of user turns that were removed from context. diff --git a/codex-rs/rollout-trace/src/protocol_event.rs b/codex-rs/rollout-trace/src/protocol_event.rs index 2aa5af5af6..f982e8028a 100644 --- a/codex-rs/rollout-trace/src/protocol_event.rs +++ b/codex-rs/rollout-trace/src/protocol_event.rs @@ -232,11 +232,8 @@ pub(crate) fn tool_runtime_trace_event(event: &EventMsg) -> Option Option Option<&'static s | EventMsg::TokenCount(_) | EventMsg::AgentMessage(_) | EventMsg::UserMessage(_) - | EventMsg::AgentMessageDelta(_) | EventMsg::AgentReasoning(_) - | EventMsg::AgentReasoningDelta(_) | EventMsg::AgentReasoningRawContent(_) - | EventMsg::AgentReasoningRawContentDelta(_) | EventMsg::AgentReasoningSectionBreak(_) | EventMsg::ThreadGoalUpdated(_) | EventMsg::McpStartupUpdate(_) @@ -341,9 +332,6 @@ pub(crate) fn wrapped_protocol_event_type(event: &EventMsg) -> Option<&'static s | EventMsg::ApplyPatchApprovalRequest(_) | EventMsg::GuardianAssessment(_) | EventMsg::DeprecationNotice(_) - | EventMsg::BackgroundEvent(_) - | EventMsg::UndoStarted(_) - | EventMsg::UndoCompleted(_) | EventMsg::StreamError(_) | EventMsg::PatchApplyBegin(_) | EventMsg::PatchApplyUpdated(_) diff --git a/codex-rs/rollout/src/policy.rs b/codex-rs/rollout/src/policy.rs index e6e4de862d..146e1dc365 100644 --- a/codex-rs/rollout/src/policy.rs +++ b/codex-rs/rollout/src/policy.rs @@ -101,7 +101,6 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::EnteredReviewMode(_) | EventMsg::ExitedReviewMode(_) | EventMsg::ThreadRolledBack(_) - | EventMsg::UndoCompleted(_) | EventMsg::TurnAborted(_) | EventMsg::TurnStarted(_) | EventMsg::TurnComplete(_) @@ -137,15 +136,11 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::RealtimeConversationClosed(_) | EventMsg::ModelReroute(_) | EventMsg::ModelVerification(_) - | EventMsg::AgentMessageDelta(_) - | EventMsg::AgentReasoningDelta(_) - | EventMsg::AgentReasoningRawContentDelta(_) | EventMsg::AgentReasoningSectionBreak(_) | EventMsg::RawResponseItem(_) | EventMsg::SessionConfigured(_) | EventMsg::ThreadGoalUpdated(_) | EventMsg::McpToolCallBegin(_) - | EventMsg::WebSearchBegin(_) | EventMsg::ExecCommandBegin(_) | EventMsg::TerminalInteraction(_) | EventMsg::ExecCommandOutputDelta(_) @@ -154,18 +149,17 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::RequestUserInput(_) | EventMsg::ElicitationRequest(_) | EventMsg::ApplyPatchApprovalRequest(_) - | EventMsg::BackgroundEvent(_) | EventMsg::StreamError(_) | EventMsg::PatchApplyBegin(_) | EventMsg::PatchApplyUpdated(_) | EventMsg::TurnDiff(_) | EventMsg::GetHistoryEntryResponse(_) - | EventMsg::UndoStarted(_) | EventMsg::McpListToolsResponse(_) | EventMsg::RealtimeConversationListVoicesResponse(_) | EventMsg::McpStartupUpdate(_) | EventMsg::McpStartupComplete(_) | EventMsg::ListSkillsResponse(_) + | EventMsg::WebSearchBegin(_) | EventMsg::PlanUpdate(_) | EventMsg::ShutdownComplete | EventMsg::DeprecationNotice(_) @@ -176,12 +170,12 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::PlanDelta(_) | EventMsg::ReasoningContentDelta(_) | EventMsg::ReasoningRawContentDelta(_) + | EventMsg::ImageGenerationBegin(_) | EventMsg::SkillsUpdateAvailable | EventMsg::CollabAgentSpawnBegin(_) | EventMsg::CollabAgentInteractionBegin(_) | EventMsg::CollabWaitingBegin(_) | EventMsg::CollabCloseBegin(_) - | EventMsg::CollabResumeBegin(_) - | EventMsg::ImageGenerationBegin(_) => None, + | EventMsg::CollabResumeBegin(_) => None, } } diff --git a/codex-rs/tui/src/chatwidget/slash_dispatch.rs b/codex-rs/tui/src/chatwidget/slash_dispatch.rs index dd869892b1..cd828274f6 100644 --- a/codex-rs/tui/src/chatwidget/slash_dispatch.rs +++ b/codex-rs/tui/src/chatwidget/slash_dispatch.rs @@ -319,9 +319,6 @@ impl ChatWidget { SlashCommand::Logout => { self.app_event_tx.send(AppEvent::Logout); } - // SlashCommand::Undo => { - // self.app_event_tx.send(AppEvent::CodexOp(Op::Undo)); - // } SlashCommand::Copy => { self.copy_last_agent_markdown(); } diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs index 3d0be1b580..9f4dbf57d0 100644 --- a/codex-rs/tui/src/slash_command.rs +++ b/codex-rs/tui/src/slash_command.rs @@ -40,7 +40,6 @@ pub enum SlashCommand { Collab, Agent, Side, - // Undo, Copy, Diff, Mention, @@ -87,7 +86,6 @@ impl SlashCommand { SlashCommand::Resume => "resume a saved chat", SlashCommand::Clear => "clear the terminal and start a new chat", SlashCommand::Fork => "fork the current chat", - // SlashCommand::Undo => "ask Codex to undo a turn", SlashCommand::Quit | SlashCommand::Exit => "exit Codex", SlashCommand::Copy => "copy last response as markdown", SlashCommand::Diff => "show git diff (including untracked files)", @@ -173,7 +171,6 @@ impl SlashCommand { | SlashCommand::Fork | SlashCommand::Init | SlashCommand::Compact - // | SlashCommand::Undo | SlashCommand::Model | SlashCommand::Fast | SlashCommand::Personality