Skip to content

fix(web): reset streaming UI state when background job completes - #521

Merged
leoisadev1 merged 1 commit into
mainfrom
fix/streaming-ui-stuck-after-completion
Jan 19, 2026
Merged

fix(web): reset streaming UI state when background job completes#521
leoisadev1 merged 1 commit into
mainfrom
fix/streaming-ui-stuck-after-completion

Conversation

@leoisadev1

Copy link
Copy Markdown
Member

Summary

  • Fixes the bug where the chat UI gets stuck in "streaming" state after a message completes
  • The getActiveStreamJob Convex query only returns jobs with "running" or "pending" status
  • When a job completes, it returns null - but the useEffect wasn't handling this case properly
  • Now properly resets UI state to "ready" when activeStreamJob becomes null

Root Cause

The useEffect in use-persistent-chat.ts had this logic:

if (!activeStreamJob) return; // Just returned early, never reset status!

When the backend stream completed, getActiveStreamJob returned null (because it only queries running/pending jobs), but the UI status remained stuck at "streaming".

Fix

Now when activeStreamJob becomes null AND status is still "streaming" or "submitted", we properly call setStatus("ready") and clean up the streaming state.

Testing

  1. Send a message in chat
  2. Wait for it to complete
  3. UI should properly reset to "ready" state (input enabled, thinking indicator gone)

The getActiveStreamJob query only returns jobs with 'running' or 'pending' status.
When a job completes, it returns null. The useEffect wasn't handling this case
properly - it would just return early when activeStreamJob was null, leaving
the UI stuck in 'streaming' state.

Now when activeStreamJob becomes null and status is still 'streaming' or
'submitted', we properly reset the UI state to 'ready'.
@railway-app

railway-app Bot commented Jan 19, 2026

Copy link
Copy Markdown

🚅 Environment openchat-pr-521 in OpenChat has no services deployed.

@leoisadev1
leoisadev1 merged commit 35f8a04 into main Jan 19, 2026
3 checks passed
@leoisadev1
leoisadev1 deleted the fix/streaming-ui-stuck-after-completion branch January 19, 2026 22:56
@greptile-apps

greptile-apps Bot commented Jan 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixed a bug where the chat UI remained stuck in "streaming" state after message completion. The root cause was that getActiveStreamJob only returns jobs with "running" or "pending" status - when a job completes, it returns null. The previous code just returned early without resetting the UI state.

Key changes:

  • When activeStreamJob becomes null AND status is still "streaming" or "submitted", the UI now properly resets to "ready" state
  • Added proper cleanup of streamingRef and stream store via completeStream()
  • Added helpful comment explaining the query behavior

Minor issue:

  • Lines 164-170 contain unreachable code that checks for "completed"/"error" status, which getActiveStreamJob never returns (confidence: 3/5 - low priority cleanup)

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - it fixes a clear bug in the streaming state management
  • The fix correctly addresses the root cause by handling the null case when streams complete. The logic is sound and matches the backend behavior. One point deducted for the unreachable code at lines 164-170 which should be cleaned up but doesn't affect functionality
  • No files require special attention - the change is localized and straightforward

Important Files Changed

Filename Overview
apps/web/src/hooks/use-persistent-chat.ts Fixed streaming state bug by handling null activeStreamJob; small redundancy with status checks at lines 164-170

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as usePersistentChat Hook
    participant Convex as getActiveStreamJob Query
    participant Backend as Background Stream Action
    participant DB as Convex Database

    User->>UI: Send message
    UI->>Backend: startBackgroundStream()
    Backend->>DB: Insert streamJob (status: "pending")
    Backend->>Backend: Schedule executeStream action
    UI->>UI: setStatus("streaming")
    
    Note over Backend,DB: Stream execution starts
    Backend->>DB: Update job status to "running"
    Backend->>Backend: Fetch from OpenRouter API
    
    loop Streaming chunks
        Backend->>DB: Update job content
        Convex->>UI: Return activeStreamJob (status: "running")
        UI->>UI: Update UI with streamed content
    end
    
    Backend->>DB: completeStream() - Update job status to "completed"
    
    Note over Convex: Query filters out completed jobs
    Convex->>UI: Return null (no running/pending jobs)
    
    Note over UI: BUG FIX: Previously returned early here!
    UI->>UI: Check: status is "streaming" && activeStreamJob is null
    UI->>UI: setStatus("ready") + cleanup
    User->>User: Input re-enabled, UI ready
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. apps/web/src/hooks/use-persistent-chat.ts, line 164-171 (link)

    style: Redundant code - this block is unreachable since getActiveStreamJob only returns jobs with "running" or "pending" status, never "completed" or "error". When a job completes, the query returns null and is handled above (lines 154-162).

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

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