block / block/buzz

Preserve and display classified agent turn failures instead of collapsing all failures to transient "Turn error"

Open
#1,659 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Summary

Agent turn failures are being collapsed to a generic, transient "Turn error" indicator in the UI that disappears before the user can act on it. The system already has enough information to distinguish failure classes, but that information is discarded at two seams:

1. **Harness boundary** — `emit_turn_error` in `crates/buzz-relay/src/lib.rs` serializes turn outcomes to JSON but does not include an `error_class` field, so all failure types arrive at the UI as undifferentiated errors.
2. **UI store** — `activeAgentTurnsStore.ts` handles `turn_error` / `agent_panic` by immediately ending the turn with no persistent error state, so the failure badge vanishes before the user can read it.

## Root Cause

### Part 1 — Harness (`crates/buzz-relay/src/lib.rs`)

The `emit_turn_error` closure (~line 2785) captures `result.outcome` but emits only `outcome: "error"`. The `PromptOutcome` variants already carry enough information to classify the failure:

| Variant | Suggested `error_class` |
|---|---|
| `PromptOutcome::AgentExited` | `"exited"` |
| `PromptOutcome::Timeout` | `"timeout"` |
| `PromptOutcome::Error(AcpError::IdleTimeout)` | `"idle_timeout"` |
| `PromptOutcome::Error(AcpError::HardTimeout)` | `"hard_timeout"` |
| `PromptOutcome::Error(AcpError::AgentError)` | `"agent_error"` ← Codex auth-expiry lands here (`crates/buzz-relay/src/acp.rs:866`) |
| `PromptOutcome::Error(AcpError::Json)` | `"protocol"` |
| transport errors (via existing `is_transport_error` check ~line 2867) | `"transport"` |

Fix: add a string `error_class` field to the existing `serde_json::json!` payload at ~lines 2791–2794. No new types needed.

### Part 2 — UI Store (`desktop/src/activeAgentTurnsStore.ts`)

```ts
// current (~lines 342–352)
case "turn_error":
case "agent_panic":
endTurn(...) // deletes immediately, no error trace left
```

Fix: add an `errorClass` field to `ActiveTurn` and populate it from the event payload on `turn_error` before (or instead of immediately) calling `endTurn`. Keep the turn alive with an `isError: true` flag for a grace window (or until dismissed), so the badge can render "Auth error" / "Transport error" / "Timed out" instead of vanishing.

## Reproduction

1. Trigger a Codex agent turn that fails due to auth expiry (or any network/timeout failure).
2. Observe the "Turn error" badge in the session UI.
3. Badge disappears immediately — no actionable error class is shown.

## Affected Code

- `crates/buzz-relay/src/lib.rs` ~line 2785 — `emit_turn_error` closure, JSON payload
- `crates/buzz-relay/src/acp.rs` ~line 866 — `AcpError::AgentError` construction (Codex auth path)
- `desktop/src/activeAgentTurnsStore.ts` ~lines 342–352 — `turn_error` / `agent_panic` handling

## Suggested Fix

One PR, two commits:

1. **Harness commit**: expand `emit_turn_error` to include `error_class` in the JSON payload (~10 lines, no new types).
2. **Frontend commit**: add `errorClass`/`isError` to `ActiveTurn`, read `error_class` from the event in the store, and render a classified error badge.

**Open product question**: Should the error badge stay until dismissed, auto-clear after N seconds, or clear on the next successful turn? The code for any option is trivial once decided.

## Test Gaps

- No tests for the `AgentError` / auth-expiry path through `emit_turn_error`
- No tests for `turn_error` tombstone behavior in `activeAgentTurnsStore`
- Tests needed for: Codex/auth `AgentError`, transport error, timeout paths

## Out of Scope

- New triage agent
- Channel posting / notification policy
- Dashboard / activity-feed redesign

## References

Internal investigation by Ferret & Lazy Joe in channel `#bugfix-codex-logged-out`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.