Notify lifecycle extensions of compaction usage limits (#49097)

## Why

Usage-limit failures during manual or post-turn compaction did not notify turn lifecycle extensions, leaving them unable to react to these errors.

## What changed

Emit the turn error lifecycle notification for `UsageLimitExceeded` in both compaction paths. Preserve the completed answer after post-turn compaction fails, and avoid duplicating the error already emitted by manual compaction.

GitOrigin-RevId: f31155e5991d762a0779030921aedbd1f818cfbb
This commit is contained in:
xli-oai
2026-09-28 23:00:28 +00:00
committed by copyberry
parent 2ce64843be
commit 9563713df2
2 changed files with 19 additions and 6 deletions
+6
View File
@@ -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;
+13 -6
View File
@@ -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)
}