tui: queue follow-ups during manual /compact (#15259)

## Summary
- queue input after the user submits `/compact` until that manual
compact turn ends
- mirror the same behavior in the app-server TUI
- add regressions for input queued before compact starts and while it is
running

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charley Cunningham
2026-03-23 10:19:44 -07:00
committed by GitHub
parent 54801634e1
commit e838645fa2
43 changed files with 1898 additions and 157 deletions

View File

@@ -1538,6 +1538,15 @@ pub enum AgentStatus {
NotFound,
}
/// Turn kinds that reject same-turn steering.
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum NonSteerableTurnKind {
Review,
Compact,
}
/// Codex errors that we expose to clients.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
@@ -1565,6 +1574,11 @@ pub enum CodexErrorInfo {
ResponseTooManyFailedAttempts {
http_status_code: Option<u16>,
},
/// Returned when `turn/start` or `turn/steer` is submitted while the current active turn
/// cannot accept same-turn steering, for example `/review` or manual `/compact`.
ActiveTurnNotSteerable {
turn_kind: NonSteerableTurnKind,
},
ThreadRollbackFailed,
Other,
}
@@ -1573,7 +1587,7 @@ impl CodexErrorInfo {
/// Whether this error should mark the current turn as failed when replaying history.
pub fn affects_turn_status(&self) -> bool {
match self {
Self::ThreadRollbackFailed => false,
Self::ThreadRollbackFailed | Self::ActiveTurnNotSteerable { .. } => false,
Self::ContextWindowExceeded
| Self::UsageLimitExceeded
| Self::ServerOverloaded
@@ -4211,6 +4225,17 @@ mod tests {
assert!(!event.affects_turn_status());
}
#[test]
fn active_turn_not_steerable_error_does_not_affect_turn_status() {
let event = ErrorEvent {
message: "cannot steer a review turn".into(),
codex_error_info: Some(CodexErrorInfo::ActiveTurnNotSteerable {
turn_kind: NonSteerableTurnKind::Review,
}),
};
assert!(!event.affects_turn_status());
}
#[test]
fn generic_error_affects_turn_status() {
let event = ErrorEvent {