Skip to content

Fix first message not sent to model on new session creation#270

Merged
bra1nDump merged 1 commit intoslopus:mainfrom
tiann:fix-first-message-loss
Dec 7, 2025
Merged

Fix first message not sent to model on new session creation#270
bra1nDump merged 1 commit intoslopus:mainfrom
tiann:fix-first-message-loss

Conversation

@tiann
Copy link
Copy Markdown
Contributor

@tiann tiann commented Dec 7, 2025

Bug: First Message Not Sent to Agent on New Session Creation

Symptoms

When creating a new session with prefilled text, the first message appears in the UI but the agent never responds. User must copy and resend the message manually.

When Claude starts the binary via spawn, it is more likely to be triggered because spawn is time-consuming.

Root Cause

Race condition between app sending message and agent WebSocket connection.

Fix

The app now waits for agentStateVersion > 0 before sending the first message. This field starts at 0 when a session is created and increments when the CLI connects and calls updateAgentState(), serving as a reliable signal that the agent's WebSocket is ready to receive messages.

Timeline Diagrams

Before fix (message lost)

App                              Server                      Agent
──────────────────────────────────────────────────────────────────────────────
machineSpawnNewSession ────────► spawn daemon ─────────────► Agent starting…
refreshSessions (session in DB)                                │ (connecting)
sendMessage(input) ───────────► store in DB ✓                 │ not connected
                              │ broadcast via WebSocket ────► (no recipient)
navigate to session                                               │
                                                                    ▼
                                                            Agent connects
                                                            updateAgentState()
                                                            (first message missed)

After fix (message delivered)

App                              Server                      Agent
──────────────────────────────────────────────────────────────────────────────
machineSpawnNewSession ────────► spawn daemon ─────────────► Agent starting…
refreshSessions (session in DB)                                │ (connecting)
  └─ agentStateVersion = 0                                     │
                                                                 │
sendMessage(input) ──┐                                          │
                     │ waitForAgentReady()                      │
                     │  - watches agentStateVersion             │
                     │  - 10s timeout fallback                  │
                     │                                          ▼
                     │                                    WebSocket connects
                     │                                    updateAgentState()
                     │                              ◄──── agentStateVersion = 1
                     └─ resumes ───────────────► broadcast message ─────────► receives ✓
navigate to session
Agent responds

Testing

To reproduce the bug, a 5-second delay was added in happy-cli/src/claude/runClaude.ts before the WebSocket connects:

// DEBUG: Simulate slow CLI startup to reproduce first-message-lost bug
// The delay must be BEFORE sessionSyncClient() because that's where WebSocket connects
// Remove this after testing!
await new Promise(resolve => setTimeout(resolve, 5000));

// Create realtime session
const session = api.sessionSyncClient(response);

Steps to verify:

  1. Start daemon with the delay in place
  2. Create a new session from mobile app (e.g., via spawn)
  3. Send a message immediately after session creation

Expected behavior:

  • Without fix: Message appears in UI but agent never responds (lost during 5s window)
  • With fix: App waits ~5s for agentStateVersion > 0, then message is delivered and agent responds

Comment thread sources/sync/sync.ts Outdated
Comment thread sources/sync/sync.ts Outdated
Comment thread sources/sync/sync.ts Outdated
When creating a new session with prefilled text, the initial message was
not delivered to the CLI/model despite being displayed in the UI. This was
caused by a race condition: the app sent the message before the CLI had
connected its WebSocket, so the server broadcast went nowhere.

Fix: sendMessage now waits for agentStateVersion > 0 before sending over
the network. This field starts at 0 and increments when CLI connects and
calls updateAgentState(), serving as a reliable ready signal.

Co-authored-by: Kirill Dubovitskiy <kirill2003de@gmail.com>
@tiann tiann force-pushed the fix-first-message-loss branch from 8582d52 to adb51f9 Compare December 7, 2025 10:07
@tiann tiann requested a review from bra1nDump December 7, 2025 10:08
Copy link
Copy Markdown
Contributor

@bra1nDump bra1nDump left a comment

Choose a reason for hiding this comment

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

Beautiful stuff!

@bra1nDump bra1nDump merged commit 6e606c9 into slopus:main Dec 7, 2025
JoeLuker pushed a commit to JoeLuker/happy that referenced this pull request Feb 1, 2026
When creating a new session with prefilled text, the initial message was
not delivered to the CLI/model despite being displayed in the UI. This was
caused by a race condition: the app sent the message before the CLI had
connected its WebSocket, so the server broadcast went nowhere.

Fix: sendMessage now waits for agentStateVersion > 0 before sending over
the network. This field starts at 0 and increments when CLI connects and
calls updateAgentState(), serving as a reliable ready signal.

Co-authored-by: Kirill Dubovitskiy <kirill2003de@gmail.com>
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.

2 participants