Skip to content

fix(site): prevent spurious startup warning during pending status#23805

Merged
kylecarbs merged 1 commit into
mainfrom
fix/startup-warning-pending-status
Mar 30, 2026
Merged

fix(site): prevent spurious startup warning during pending status#23805
kylecarbs merged 1 commit into
mainfrom
fix/startup-warning-pending-status

Conversation

@kylecarbs
Copy link
Copy Markdown
Member

Problem

The /agents page 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 isActiveChatStatus and shouldApplyMessagePart during "pending" status (the state between agent tool-call turns):

Component Treats "pending" as...
isActiveChatStatus active — includes both "running" and "pending"
shouldApplyMessagePart inactive — drops all message_part events during "pending"
Status handler clears streamState to null on "pending"

This creates a dead state during multi-turn tool-call cycles:

  1. Agent finishes a turn → status = "pending"streamState cleared to null
  2. selectIsAwaitingFirstStreamChunk returns true (status is "active", stream is null, latest message isn't assistant)
  3. Phase = "starting" → 15s timer starts
  4. Stream parts from the server are silently dropped (shouldApplyMessagePart() returns false for "pending")
  5. streamState stays null — phase is stuck at "starting"
  6. Meanwhile, durable messages (tool calls, tool results) appear normally in the transcript
  7. After 15s → "Response startup is taking longer than expected" fires

Fix

Narrow selectIsAwaitingFirstStreamChunk to only check chatStatus === "running" instead of isActiveChatStatus(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.

isActiveChatStatus is left unchanged since its other caller (shouldSurfaceReconnectState) correctly needs to include "pending".

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.
Copy link
Copy Markdown
Member Author

@kylecarbs kylecarbs left a comment

Choose a reason for hiding this comment

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

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" &&
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Obs Implicit coupling with transport gate (Edge Case Analyst, Contract Auditor)

shouldApplyMessagePart() in useChatStore.ts:362 decides which statuses block part delivery (pending, waiting), while selectIsAwaitingFirstStreamChunk here decides which statuses mean "we're expecting parts" (running only). 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.

@kylecarbs kylecarbs merged commit 953c3bd into main Mar 30, 2026
29 checks passed
@kylecarbs kylecarbs deleted the fix/startup-warning-pending-status branch March 30, 2026 16:46
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants