Skip to content

fix(tui): resolve streaming freeze from unhandled finish event, missing timeouts, and unguarded effects#15308

Open
coleleavitt wants to merge 1 commit intoanomalyco:devfrom
coleleavitt:fix/tui-freeze-gc-pressure
Open

fix(tui): resolve streaming freeze from unhandled finish event, missing timeouts, and unguarded effects#15308
coleleavitt wants to merge 1 commit intoanomalyco:devfrom
coleleavitt:fix/tui-freeze-gc-pressure

Conversation

@coleleavitt
Copy link
Contributor

@coleleavitt coleleavitt commented Feb 27, 2026

Issue for this PR

Closes #15310

Related upstream issues

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Fixes four independent bugs that cause TUI freezes/hangs during and after LLM streaming:

  1. processor.ts — The for await (stream.fullStream) loop never broke on the finish event, only on needsCompaction. After the LLM finishes, the loop hung at 0% CPU waiting for more events that would never come. Fix: added finished flag that breaks the loop on the finish case.

  2. sdk.tsx — The 16ms event batch window caused excessive render churn at high token rates (10+ tokens/sec). Each render re-parses accumulated markdown, generating O(n) garbage that pressures the GC. Fix: increased to 50ms, which still feels instant but cuts renders by ~3x during bursts.

  3. mcp/index.tsclient.listTools() had no timeout. If an MCP server stalls, this blocks indefinitely. Fix: wrapped in withTimeout() using the configured or default timeout.

  4. db.ts — Fire-and-forget effects could reject silently. Promise.resolve(effect()) was called without .catch(), causing unhandled rejections. Fix: added .catch() with error logging.

The stream termination bug (#1) is the most impactful — it's the direct cause of the "TUI hangs after response completes" behavior. The underlying GC contention that amplifies these bugs is tracked in the Bun/WebKit issues above.

How did you verify your code works?

  • turbo typecheck passes across all 18 packages
  • turbo build succeeds
  • LSP diagnostics clean on all 4 changed files
  • Manual testing: streamed long responses against a large project, TUI remained responsive and stream exited cleanly on completion

Screenshots / recordings

N/A — not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…ng timeouts, and unguarded effects

- Fix stream termination in processor.ts: for-await loop now breaks on finish event
- Increase SDK event batch window from 16ms to 50ms to reduce render churn
- Add withTimeout to MCP client.listTools() to prevent indefinite hangs
- Handle fire-and-forget effect Promise rejections in db.ts
@github-actions github-actions bot added contributor needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Feb 27, 2026
@github-actions
Copy link
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions github-actions bot removed needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Feb 27, 2026
@github-actions
Copy link
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI freezes/hangs after LLM streaming completes

1 participant