Skip to content

agents: wrap runEmbeddedAttempt in error boundary + add cancelled liveness state #64888

@100yenadmin

Description

@100yenadmin

Problem

Two small but related gaps in the terminal lifecycle coverage from PRs C and H:

  1. No uncaught-exception boundary around runEmbeddedAttempt. If the inner run function throws (network glitch, provider SDK bug, runtime OOM), setTerminalLifecycleMeta is never called and the caller gets no terminal lifecycle meta at all. The finally block at run.ts:1783 disposes context but doesn't set a fallback terminal state.

  2. No "cancelled" liveness state. In src/agents/pi-embedded-runner/run/incomplete-turn.ts:184, user-initiated abort signals and hard runtime errors both map to "blocked". From the user's perspective these are very different situations — a cancelled run should be visually distinct from a blocked run, and downstream channels may want to surface them differently.

Both are on completion criterion 4 in #64227 — "replay/liveness failures are surfaced as explicit states, not silent disappearance."

Fix

For the exception boundary:

Wrap the main body of runEmbeddedPiAgent in a try/finally or try/catch where the catch path sets:

attempt.setTerminalLifecycleMeta?.({
  replayInvalid: true,
  livenessState: "blocked",  // or a new "errored" state
});

and re-throws. This way every exit has terminal meta set, even uncaught exceptions.

For the "cancelled" state:

  1. Add "cancelled" to the EmbeddedRunLivenessState union in src/agents/pi-embedded-runner/types.ts.
  2. Update resolveRunLivenessState in incomplete-turn.ts:168-191 to return "cancelled" when params.aborted && !params.timedOut.
  3. Update any downstream consumer that does a 4-way match on liveness state to handle the new value (look for "working" | "paused" | "blocked" | "abandoned" grep hits).

Consider whether this interacts with the channel surfacing issue (#64XXX) — the two probably want to land together so the UX is coherent.

Acceptance

  • runEmbeddedPiAgent sets terminal meta on every uncaught exception path (regression test with a forced throw).
  • User abort produces livenessState: "cancelled" distinct from "blocked" (regression test with a simulated abort).

Part of

#64227 (criterion 4).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions