fix(site): prevent spurious startup warning during pending status#23805
Conversation
selectIsAwaitingFirstStreamChunk was using isActiveChatStatus which includes both 'running' and 'pending'. During 'pending' status the transport's shouldApplyMessagePart guard drops all incoming message_part events, so streamState can never transition away from null. This created a dead state where: 1. The system showed phase='starting' (expecting a first chunk) 2. But could never receive one (parts dropped during pending) 3. The 15s grace timer fired showing 'Response startup is taking longer than expected' while durable messages appeared normally The fix narrows the check to chatStatus === 'running' — the only status where stream parts are actually accepted by the transport.
kylecarbs
left a comment
There was a problem hiding this comment.
Clean, well-scoped fix. The contract trace checks out end-to-end — the selector now only returns true when the transport can actually deliver parts to resolve it. Good call leaving isActiveChatStatus unchanged for shouldSurfaceReconnectState. Tests are authentic and hit the key regression scenarios.
1 Obs across 1 inline comment. No blockers.
| return ( | ||
| state.streamState === null && | ||
| isActiveChatStatus(state.chatStatus) && | ||
| state.chatStatus === "running" && |
There was a problem hiding this comment.
Obs Implicit coupling with transport gate (Edge Case Analyst, Contract Auditor)
shouldApplyMessagePart()inuseChatStore.ts:362decides which statuses block part delivery (pending,waiting), whileselectIsAwaitingFirstStreamChunkhere decides which statuses mean "we're expecting parts" (runningonly). These two functions must agree — if a future status is added that accepts parts, both places need updating. There's no shared constant, type constraint, or test that enforces this invariant.
The comment you added here is good documentation of the coupling. Not worth over-engineering a shared constant for two call sites, but worth knowing about if ChatStatus ever gains new values.
Problem
The
/agentspage frequently shows "Response startup is taking longer than expected" even while the agent is actively working and messages are appearing in the transcript.Root Cause
There's an inconsistency between
isActiveChatStatusandshouldApplyMessagePartduring"pending"status (the state between agent tool-call turns):"pending"as...isActiveChatStatus"running"and"pending"shouldApplyMessagePartmessage_partevents during"pending"streamStatetonullon"pending"This creates a dead state during multi-turn tool-call cycles:
"pending"→streamStatecleared tonullselectIsAwaitingFirstStreamChunkreturnstrue(status is "active", stream is null, latest message isn't assistant)"starting"→ 15s timer startsshouldApplyMessagePart()returnsfalsefor"pending")streamStatestaysnull— phase is stuck at"starting"Fix
Narrow
selectIsAwaitingFirstStreamChunkto only checkchatStatus === "running"instead ofisActiveChatStatus(chatStatus)."running"is the only status where the transport actually accepts stream parts, so it's the only status where we should be showing the "starting" indicator.isActiveChatStatusis left unchanged since its other caller (shouldSurfaceReconnectState) correctly needs to include"pending".