Skip to content

fix(decopilot): clear stuck run-status spinner when live stream is silent#4186

Open
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/decopilot-spinner-hang
Open

fix(decopilot): clear stuck run-status spinner when live stream is silent#4186
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/decopilot-spinner-hang

Conversation

@viktormarinho

@viktormarinho viktormarinho commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

What is this contribution about?

The decopilot chat would stick forever on the run-status spinner "Request received — The run was accepted and queued" even though the run completed server-side and the answer was persisted (confirmed read-only on prod: threads terminal, projected_seq advanced, assistant parts persisted). Root cause is client stream-delivery, not the backend: a fast run's live /stream tail can deliver 0 chunks — the JetStream subject is purged on terminal status before this client's consumer reads it, or a 204 degraded buffer returns permanently with no reconnect — so no finish chunk ever clears runStatusStage. The fix reconciles the spinner against the persisted DB client-side (all in thread-connection.ts): refetchLatestPage self-clears a stuck spinner when it surfaces the turn's reply; a bounded post-POST poll surfaces it when no reconnect ever happens; and a 204 on /stream is now transient (refetch + backoff-reconnect). It's scoped to fresh user turns via an awaitingMessageTurn guard so tool-output/approval continuations keep the live-stream behavior untouched.

Screenshots/Demonstration

N/A — no visual changes; the spinner simply clears instead of hanging. Behavior is covered by an e2e that drives the real browser.

How to Test

  1. bun test apps/mesh/src/web/components/chat/store/thread-connection.test.ts — 3 new cases (refetch-clears, poll-clears, 204-transient), red/green verified against the pre-fix code.
  2. e2e: packages/e2e/tests/decopilot-spinner-reconcile.spec.ts sends a turn with a silent stream, seeds the persisted reply, and asserts the spinner clears + reply renders without a reload (verified locally red on pre-fix / green on fix).
  3. Expected: the chat surfaces the persisted answer and drops the spinner within a couple seconds, with no duplicate re-sends.

Migration Notes

None.

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by cubic

Fixes the Decopilot chat spinner stuck on "Request received" when the live /stream delivers no chunks. The client now reconciles against persisted messages and treats 204 responses as transient, so the reply shows and the spinner clears without a reload.

  • Bug Fixes
    • Clear a stuck spinner when refetchLatestPage surfaces the persisted assistant reply.
    • Add a bounded post-POST reconcile poll for fresh user turns; cancels on stop/dispose.
    • Treat 204 on /stream as transient: refetch latest page and retry with backoff.
    • Scope reconcile to new user messages only; tool-output/approval flows keep live-stream behavior.
    • Add unit tests and an e2e to cover refetch-clear, poll-clear, and 204 recovery.

Written for commit ba353e8. Summary will update on new commits.

Review in cubic

…am is silent

A fast run's live /stream tail can deliver 0 chunks (the JetStream subject is
purged on terminal status before this client's consumer reads it, or a 204
degraded buffer), so no finish chunk ever clears runStatusStage — the chat
sticks on "Request received" forever even though the answer is persisted.

Reconcile the spinner against the persisted DB client-side: refetchLatestPage
self-clears a stuck spinner when it surfaces the turn's reply, a bounded
post-POST poll surfaces it when no reconnect ever happens, and a 204 on /stream
is now transient (refetch + backoff-reconnect) instead of a permanent dead
stream. Scoped to fresh user turns so tool-output/approval continuations are
untouched. Adds unit tests (red/green verified) + a black-box e2e.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant