Skip to content

Mark orphaned assistant messages as aborted after server restart #24

Closed

Description

@dzianisv

Summary

When the opencode server restarts during an in-flight session turn, Session.recover() patches running/pending tool parts to error but only force-completes unfinished assistant messages by setting time.completed. It does not mark the assistant message itself as aborted.

Symptoms

  • Session transcript shows Tool execution aborted: server restarted for tool parts.
  • The turn can end with an empty assistant message (parts: [], error: null, time.completed set) attached to the last user prompt.
  • The session reads like it silently stalled instead of clearly showing an interrupted turn.

Investigation

Observed on a live session URL under the local server on port 4096. The affected session had:

  • no active entry in /session/status
  • no pending permissions/questions
  • an assistant message with zero parts and no error after restart recovery

Relevant code:

  • packages/opencode/src/session/index.ts Session.recover()
  • packages/ui/src/components/session-turn.tsx already understands MessageAbortedError and renders interrupted turns cleanly

Expected

Recovered assistant messages should be marked with MessageAbortedError (or equivalent interrupted state) so the UI and downstream logic can distinguish an interrupted turn from a clean completion.

Follow-up

Add a regression test that creates an unfinished assistant message, runs Session.recover(), and asserts the message is completed and marked aborted.

Activity

  1. dzianisv commented on Mar 16, 2026

    @dzianisv
    OwnerAuthor

    Investigation update:

    • Reproduced the affected session state from the local server on port 4096.
    • /session/status had no active entry for the session, so it was not actually still running.
    • The transcript contained restart-aborted tool parts plus a trailing assistant message with parts: [], error: null, and time.completed set by recovery.
    • Root cause is in Session.recover(): it force-completes orphaned assistant messages after restart but does not mark them as aborted.

    I have a local fix plus regression test in progress.

  2. dzianisv commented on Mar 16, 2026

    @dzianisv
    OwnerAuthor

    Validation update:

    • Added a follow-up fix on top of the existing startup recovery commit.
    • Local focused test passed: bun test test/session/session.test.ts.
    • bun typecheck passed in a clean origin/dev worktree.
    • Browser-visible E2E verified on an isolated server/data dir: the recovered session renders Interrupted plus the server restarted tool error instead of looking like a live stuck turn.
  3. dzianisv commented on Mar 16, 2026

    @dzianisv
    OwnerAuthor

    PR opened: #26

    This carries the recovery fix plus regression test and is linked with Closes #24 in the PR body.

  4. dzianisv commented on Jun 21, 2026

    @dzianisv
    OwnerAuthor

    Session recovery now properly handles server restart scenarios. Session.recover() patches running/pending tool parts to error state. The empty assistant message issue was a display bug that's been addressed in the current message-v2 schema with proper abort/error states.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions