You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(web): stop sending prompts into a busy turn on the web UI (#1522)
* fix(web): prevent duplicate first prompts and keep goal drives from looking idle
- Guard startSessionAndSendPrompt with a per-workspace reentry lock so a
double-click / repeated Enter during draft-session creation cannot fire
two concurrent first prompts into the same new session.
- Track goal.active in the agent event projector so turn.ended between
goal-driven continuation turns keeps the session 'running' instead of
projecting a false 'idle' that drains the local queue into a still-busy
core (turn.agent_busy).
- Show a 'starting conversation…' loading state on the empty-session
landing while the first prompt is being created and submitted.
- Persist the resolved model in startSessionAndActivateSkill so the first
skill turn on a fresh session does not fail with 'Model not set'.
* chore: add changeset for web first-prompt fixes
* fix(web): close remaining first-prompt and goal-settle gaps
- Pass the starting guard through the dock composer: draft-session
creation selects the new session before submit, which swaps the empty
composer for the dock; disabling both composers closes the last path
to a concurrent first POST. Also take the workspace lock in
startSessionAndActivateSkill / startSessionAndOpenSideChat.
- Emit the owed idle when a goal settles (blocked/paused/completed) in
the inter-turn gap after a turn.ended was projected as 'running', so
sending state, in-flight flags and queued prompts flush instead of
the session staying 'running' forever.
* style(web): fix eqeqeq lint error in first-prompt guard
* fix(web): clear owed idle when a new goal turn starts
The idle debt from a 'running' projection survived turn.started, so an
UpdateGoal('complete'|'blocked') landing mid-turn in the NEXT goal turn
synthesized an early idle. onSessionIdle could then drain queued prompts
into a core that was mid-turn again, re-opening the turn.agent_busy race
for multi-turn goals. Clear the debt on turn.started: from that point the
turn's own turn.ended carries the idle with goalActive already false.
* fix(web): make first-prompt starting state workspace-id-agnostic
isStartingFirstPrompt now reads from the lock set directly (size > 0)
instead of the current activeWorkspaceId. createDraftSession can swap
activeWorkspaceId to a registered id mid-flight; a workspace-keyed read
would then return false while the first prompt is still in the create/
select/submit window, re-enabling the composer and reopening the
duplicate first-submit race.
* revert(web): drop goal-aware idle projection from agentEventProjector
The goalActive / idleOwed shadow state machine grew through multiple
review rounds and still leaves edge cases (snapshot-seeded turns, mid-
turn goal updates). Roll it back to the simple 'turn.ended projects idle'
behavior. Goal-driven sessions can once again race a queued prompt into a
busy core; this is accepted as a known limitation to be resolved properly
in a follow-up that has the core emit an authoritative idle signal.
* chore: align changeset with actual fix scope
* test(web): update profile-patch expectation for model field
web: Fix an occasional "another turn is active" error when sending the first message of a new conversation, and show a starting state while it is being sent.
0 commit comments