Skip to content

Refresh mid-stream: composer stays in idle state — Send instead of Stop, agent run can't be stopped #6233

Description

@touzenesmy

Prerequisites

  • I searched open issues and discussions and did not find an existing report of this bug.
  • This is not a security vulnerability. (Vulnerabilities go to GitHub Security Advisories — see SECURITY.md.)
  • I am running the latest code from the dev branch (the default branch you get on clone, where fixes land first) and the bug still reproduces there. Please git pull the latest dev before filing.

Odysseus Revision

ce04dc1 (2026-09-01)

Install Method

Manual Python install (pip / venv)

Operating System

Linux

Steps to Reproduce

  1. In any session, send a prompt that produces a long streaming answer (e.g. a multi-step agent task with a few seconds of tokens / tool output).
  2. While the answer is still streaming, refresh the page (F5).
  3. The page re-enters the session and the run re-attaches live via /api/chat/resume/{session_id} — the answer keeps streaming (this part works; see Frontend never calls /api/chat/resume — detached agent runs show a spinner instead of live progress #2931 / [Bug] Detached agent runs show a dead spinner after page refresh — /api/chat/resume never called #3048 / Chat stream re-entry shows "Generating response…" forever instead of live-resuming #2539).
  4. Look at the composer while tokens are still streaming.

Expected Behaviour

The composer restores its streaming state: the submit button shows the Stop icon and clicking it stops the in-flight run (same as if the stream had never been interrupted by a reload).

Actual Behaviour

The composer is in idle state: the submit button shows the Send arrow, not Stop.

qKk6VoZBFo.mp4

Logs / Screenshots

No server-side errors: the server-side run is healthy (that's why the replay keeps streaming).
Client console: the resume attach succeeds (X-Odysseus-Run-Id header replayed, deltas render live), no exceptions. The bug is purely missing client-side state restoration in resumeStream() (static/js/chat.js) — it re-attaches the SSE reader and renders deltas, but never sets isStreaming=true, never calls updateSubmitButton('streaming'), and never registers the session in the active-streams map, so the Stop button never appears and the stall watchdog / foreground-busy state are not set either.

Model / Backend (if relevant)

llama.cpp + qwen3.8-27b-q3kxl (local multimodal 27B GGUF)

Are you willing to submit a fix?

Yes — I can open a PR

Additional Information

Searched open AND closed issues for this symptom ("stop button" streaming / refresh mid-stream / resume streaming refresh) — the closest reports are #2931 (open), #3048 and #2539 (both closed), all of which describe the dead-spinner symptom (resume never called). This is a distinct, unreported symptom: resume works, but the composer's streaming state is never restored.
Fix prepared and verified locally (~20 lines in static/js/chat.js restoring the streaming UI state inside resumeStream()); a PR referencing this issue will follow after the issue is filed.
Recording of the repro (refresh mid-stream, Send instead of Stop while tokens stream) is attached above in the Actual Behaviour section.

Activity

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

    bugSomething isn't workingready for reviewDescription complete — ready for maintainer review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions