Skip to content

fix(chat): prevent stalled turns from hanging and show activity status#40

Merged
albanm merged 1 commit into
mainfrom
fix-prevent-hangup
Jun 21, 2026
Merged

fix(chat): prevent stalled turns from hanging and show activity status#40
albanm merged 1 commit into
mainfrom
fix-prevent-hangup

Conversation

@albanm

@albanm albanm commented Jun 21, 2026

Copy link
Copy Markdown
Member

Prevent chat turns from hanging when the stream stalls or compaction can't be cancelled, and replace the ambiguous loading skeleton with a discreet activity indicator.

Why: conversations kept getting "stuck" with a mute spinner — most often around compaction in long sessions (e.g. an evaluator pulling large trace entries). The earlier #38 fix covered silent drops; this covers silent stalls, which it never touched.

  • compaction is now abortable: it runs under the turn's abort controller and passes the signal to the summarizer, so Stop (and the watchdog) can cancel it; on abort it stops the turn instead of failing open, while non-abort errors still fail open
  • idle watchdog (default 90s, overridable via sessionStorage for tests), re-armed on every stream part and around compaction, turns a genuine stall into a recoverable timeout error instead of an endless spinner
  • the two loading skeletons are replaced by one muted phase-label line — Compacting… / Thinking… / Analyzing tool result… — driven by a new activity ref
  • compaction summary prompt + recap framing reworked to keep the continuation context actionable (open task/next step, verbatim ids/indices/paths)

Heads-up: during active text streaming there is no longer a skeleton — progress relies on the markdown streaming cursor. And the 90s watchdog will abort a turn that produces no bytes for that long.

The prior #38 fix covered silent *drops* (error parts, empty completions) but
not silent *stalls*: compaction ran before the abort controller existed and its
summarizer call had no abort signal or timeout, so a slow/stalled summarize (easy
once a large tool result pushed history past the 24KB threshold) froze the turn
with the Stop button dead and only a mute skeleton showing. There was also no
idle timeout anywhere on the main stream.

- compaction is now abortable: the abort controller is created before it and its
  signal is passed to the summarizer generateText; on abort it rethrows (so the
  turn stops) instead of failing open, while non-abort errors still fail open
- idle watchdog: re-armed on every fullStream part and around compaction; on
  expiry it aborts the turn and surfaces a recoverable timeout error instead of an
  endless spinner. Generous default (90s), overridable via sessionStorage for tests
- activity indicator: an `activity` phase (compacting/thinking/analyzing) is
  exposed from the composable and threaded to AgentChatMessages, which replaces the
  two ambiguous skeletons with one discreet muted label line (null while text streams)
- compaction summary prompt + recap framing reworked to keep the continuation
  context actionable (open task/next step, verbatim ids/indices/paths/URLs)
- mock "stall" seam + chat-hang e2e covering the indicator and the timeout

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the fix label Jun 21, 2026
@albanm albanm merged commit 9999487 into main Jun 21, 2026
4 checks passed
@albanm albanm deleted the fix-prevent-hangup branch June 21, 2026 15:51
albanm added a commit that referenced this pull request Jun 21, 2026
…ssage

While text streams there was no in-progress signal: renderStreamingMarkdown
rendered no cursor and #40 removed the discreet 'receiving more' skeleton, setting
activity=null during text. Append an inline blinking caret to the streamed markdown
(before the last leaf block closer so it sits inline at the true end of the text),
removed once the turn settles.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant