Skip to content

feat: support parallel chat sessions streaming concurrently#55

Merged
KostasCherv merged 2 commits into
mainfrom
claude/competent-engelbart-dd7518
Jul 17, 2026
Merged

feat: support parallel chat sessions streaming concurrently#55
KostasCherv merged 2 commits into
mainfrom
claude/competent-engelbart-dd7518

Conversation

@KostasCherv

@KostasCherv KostasCherv commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Lets a user run multiple chat sessions in parallel: start a reply streaming in one session, switch to another and stream there too, and come back without losing anything. The backend was already parallel-safe (per-request SSE generators, UUID-keyed sessions), so this is a UI-only change — no API or schema changes.

Root cause fixed: all stream state (streamingText, chatting, abort controller) lived inside a single ChatThreadContainer instance and was aborted/reset on every session or view switch.

Changes

  • New ui/src/components/chat/chatStreamStore.ts — module-level, session-keyed stream store built on useSyncExternalStore (no new dependencies). Owns each stream's lifecycle (streaming → done/error). Streams started before a session id exists live under a pending key and are rekeyed via an alias when the server assigns one. One stream per session; MAX_CONCURRENT_STREAMS = 3 global cap; errored never-resolved entries are swept on the next start.
  • ChatThreadContainer.tsx — derives streaming UI from the store. Removed the unconditional abort-on-send; composer disabled only while this session streams; the in-flight exchange renders from stream state. Returning to a session whose stream finished in the background refetches persisted messages; a background failure surfaces the error banner and restores the question to the composer. Stop restores the question; edit deletes the last persisted exchange before resending.
  • AgentRail.tsx — workspace/agent session rows show a pulsing dot while streaming (same pattern as research runs).
  • chatThreadState.ts — simplified to a single removeLastExchange helper; ui/DESIGN.md updated.

Reviewed by the TypeScript reviewer agent: initial BLOCK (background errors swallowed; orphaned errored pending entries; double-send pending race; suggestions/webUsed cross-session bleed) — all fixed with regression tests, re-review verdict APPROVE.

Deliberately out of scope: resumable streams across page reload (server-side; can reuse the research-run polling pattern later), multi-pane chat UI.

Test plan

  • Store unit tests: independent concurrent accumulation, pending→session rekeying, same-session rejection, single pending stream per transport, concurrency cap, stop/abort cleanup, done/consume, error paths, orphan eviction
  • removeLastExchange unit tests
  • Component tests: stream survives a session switch (not aborted), background completion refetched on return, two sessions streaming at once, composer disabled only for the streaming session, background error surfaced with question restored
  • tsc -b, eslint, vite build clean; full npm test (26 tests) green
  • Manual smoke: two sessions streaming simultaneously with rail indicators (needs a running backend)

Move stream lifecycle out of ChatThreadContainer into a session-keyed
chatStreamStore (useSyncExternalStore, no new deps) so streams survive
session/view switches and multiple sessions can stream at once (capped
at 3). Background completions are folded in on return via refetch;
background errors surface with the question restored to the composer.
AgentRail rows show a pulse dot for streaming sessions.
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cortex Ready Ready Preview, Comment Jul 17, 2026 10:21am

@KostasCherv
KostasCherv merged commit a4c38aa into main Jul 17, 2026
5 checks passed
@KostasCherv
KostasCherv deleted the claude/competent-engelbart-dd7518 branch July 17, 2026 10:26
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