Skip to content

Retry/Continue can run while session runtime is reported idle #51

Description

@ashwin-pc

Summary

When an incomplete or aborted response is resumed with the Continue/Retry action, the agent can be actively generating messages and executing tools while pi-web reports the session as idle.

Consequences:

  • the session tab/drawer has no running spinner;
  • the composer running status and Stop action disappear;
  • GET /api/sessions reports runtime.isRunning: false and runtime.isStreaming: false for the active session.

Reproduction

  1. Produce an aborted or otherwise incomplete assistant response.
  2. Use the response card's Continue (or Retry) action, which calls POST /api/session/retry.
  3. Let the resumed turn execute one or more tools.
  4. While tools are visibly running and transcript entries are still being appended, inspect the session tab/composer or GET /api/sessions.

Actual: the session is shown as idle and the API runtime has isRunning: false.

Expected: the resumed session remains running for the full retry/continuation, including tool execution, and the Stop action remains available.

Root cause

The compatibility fallback in retrySessionFromFailure() calls the low-level agent directly:

await internal.agent.continue();
while (typeof internal._handlePostAgentRun === "function" && await internal._handlePostAgentRun()) {
  await internal.agent.continue();
}

This bypasses AgentSession._runAgentPrompt(), which normally sets _isAgentRunActive = true and later emits the settled lifecycle. AgentSession.isStreaming therefore stays false for the entire resumed run.

runtimeForPath() derives isRunning only from live.isStreaming, retrying, or compacting. Although /api/session/retry acquires a work lease, runtimeForPath() does not consider entry.workLeases. Every pi event consequently broadcasts a false session_runtime_changed, immediately overwriting the frontend's optimistic agent_start state.

Relevant locations:

  • server.ts: retrySessionFromFailure() fallback
  • server.ts: runtimeForPath()
  • server.ts: registerLiveSession() runtime broadcast
  • src/realtime/realtime.ts: session_runtime_changed handling

Suggested direction

Prefer a public AgentSession continuation/retry API that participates in the normal run lifecycle. As a compatibility fallback, ensure the whole low-level continuation is represented as active runtime.

If work leases are incorporated into runtimeForPath(), the finalizer must release the lease before broadcasting the terminal runtime; otherwise the final broadcast will remain running. Concurrency guards should also reject a second retry while a work lease/continuation is active.

Acceptance criteria

  • A retried/continued response reports isRunning: true from start through all model and tool activity.
  • The session tab/drawer spinner and composer running/Stop UI stay visible throughout.
  • Exactly one terminal runtime update reports the session idle after completion or abort.
  • A second retry cannot start while the first retry is active.
  • Regression coverage includes a retry with a long-running tool, not only model streaming.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions