Stop on an agent host turn can immediately restart the same turn
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
I pressed Stop on a stuck agent host chat. The request ended, and then the client immediately started a new request for the same turn and kept spinning.
These three lines are 22ms apart in the log:
```
[AgentHost] Cancellation requested for , dispatching turnCancelled
[AgentHost] Server-initiated turn detected:
[AgentHost] Server-initiated request started
```
### What happens
All of this is in `src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionHandler.ts`.
`_handleTurn` adds the turn id to `_clientDispatchedTurnIds` before it dispatches, and removes it in `onTurnEnded`.
On cancel, `_observeTurn` calls `finish()` right away. That queues a microtask which runs `onTurnEnded` and removes the id. But the `ChatTurnCancelled` dispatch has to round trip to the host, so state can still come back with that turn active. By then the id is already gone from the set, so `_watchForServerInitiatedTurns` decides it must be a server initiated turn and calls `startServerRequest` for the turn you just cancelled.
`lastSeenTurnId` normally catches this, but it only gets set when the client sees the turn go active. In my case no state update ever arrived for the turn while it was running, so it was never set and the guard did nothing.
### Possible fix
Either keep the turn id around for a short time after cancel, or leave it in the set until the host actually reports the turn as finished.
Worth noting the trigger was a stale agent host build on the remote, filed separately. But the race itself looks general. Any time state updates lag behind the cancel, Stop can restart the work it just stopped.
Contributor guide
Assessment
This issue has not been assessed yet.