diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 996cb33e73..818d44dfac 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -736,6 +736,12 @@ pub(crate) async fn run_turn( ) { return Err(err); } + let error = err.to_codex_protocol_error(); + if matches!(error, CodexErrorInfo::UsageLimitExceeded) { + // Preserve the completed answer while stopping automatic work. + sess.emit_turn_error_lifecycle(turn_context.as_ref(), error) + .await; + } warn!(error = %err, "Post-turn compaction failed; preserving the completed turn"); } break; diff --git a/codex-rs/core/src/tasks/compact.rs b/codex-rs/core/src/tasks/compact.rs index 14913d95c8..85f1a54f91 100644 --- a/codex-rs/core/src/tasks/compact.rs +++ b/codex-rs/core/src/tasks/compact.rs @@ -10,6 +10,7 @@ use crate::state::TaskKind; use codex_features::Feature; use codex_model_provider::RemoteCompactionSupport; use codex_protocol::error::CodexErrorDetails; +use codex_protocol::protocol::CodexErrorInfo; use codex_protocol::user_input::UserInput; use tokio_util::sync::CancellationToken; @@ -45,7 +46,8 @@ impl SessionTask for CompactTask { "remote_v2", /*manual*/ true, ); - crate::compact_remote_v2::run_remote_compact_task(session.clone(), ctx).await + crate::compact_remote_v2::run_remote_compact_task(session.clone(), Arc::clone(&ctx)) + .await } RemoteCompactionSupport::Unsupported => { emit_compact_metric( @@ -63,13 +65,18 @@ impl SessionTask for CompactTask { // Compaction prompt is synthesized; no UI element ranges to preserve. text_elements: Vec::new(), }]; - crate::compact::run_compact_task(session.clone(), ctx, input).await + crate::compact::run_compact_task(session.clone(), Arc::clone(&ctx), input).await } }; - if let Err(err) = result - && matches!(err.details(), CodexErrorDetails::TurnAborted) - { - return Err(err); + if let Err(err) = result { + if matches!(err.details(), CodexErrorDetails::TurnAborted) { + return Err(err); + } + let error = err.to_codex_protocol_error(); + if matches!(error, CodexErrorInfo::UsageLimitExceeded) { + // Compaction already emitted the error; notify extensions without emitting it twice. + session.emit_turn_error_lifecycle(ctx.as_ref(), error).await; + } } Ok(None) }