Skip to content

Conversation

@ammar-agent
Copy link
Collaborator

Summary

Fixes a UX bug where the chat input was disabled during the "stream starting" phase (the window between when a user sends a message and when the AI stream actually starts). This prevented users from queueing follow-up messages before streaming begins. The fix generalizes the existing "compaction-starting" concept to all streams.

Background

When a user sends a message, there's a brief window (typically <1s but sometimes longer) where:

  1. The message is sent to the backend
  2. The AI provider is contacted
  3. The stream hasn't started yet

During this window, the frontend was disabling the input, and the backend wasn't queuing messages. This was confusing because users couldn't add follow-up thoughts before the AI started responding.

Implementation

Frontend changes:

  • WorkspaceStore: Added isStreamStarting state derived from pendingStreamStartTime !== null && !canInterrupt
  • ChatInput: Uses isStreamStarting prop to keep input enabled during the starting phase (only blocks when actually streaming)
  • Generalized "compaction-starting" concept to all streams

Backend changes:

  • AgentSession: Renamed compactionStarting to streamStarting, applies to all sendMessage() and resumeStream() calls
  • WorkspaceService: Queue condition now checks session.isStreamStarting() in addition to aiService.isStreaming()

Test infrastructure:

  • Added mock stream-start gate mechanism ([mock:wait-start] marker) for deterministic testing
  • Added prompt snapshot API (debugGetLastMockPrompt) to verify both messages reach the model
  • Test uses explicit synchronization instead of sleeps

Validation

  • Added tests/ipc/queuedMessages.starting.test.ts that proves:
    1. User sends message with gate marker
    2. System enters starting state (not yet streaming)
    3. User sends follow-up message
    4. Gate is released, stream starts
    5. Both messages appear in the prompt sent to the model
    6. Both user messages appear in the collected events

Risks

Low risk - the change makes the system more permissive (allows queueing where it previously didn't) rather than adding new restrictions. The backend queue logic is additive and uses the same code path as the existing streaming queue.


Generated with mux • Model: anthropic:claude-opus-4-5 • Thinking: high • Cost: $25.80

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b50090aff9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

- Generalize compaction-starting to stream-starting across frontend/backend
- Frontend: WorkspaceStore exposes isStreamStarting computed from pendingStreamStartTime
- Backend: AgentSession tracks streamStarting state, WorkspaceService queues during starting
- Add explicit mock stream-start gate for deterministic testing
- Test proves both messages reach model when follow-up sent during starting phase
@ammario ammario merged commit e132a51 into main Jan 24, 2026
23 checks passed
@ammario ammario deleted the compacting-4t2m branch January 24, 2026 20:56
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.

2 participants