microsoft / microsoft/agent-host-protocol
summaryStatus reports Idle while queued messages are pending, causing status flicker
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 344
- Forks
- 122
- Avg merge
- 14h 12m
- Merged PRs (30d)
- 22
Description
Summary
summaryStatus reports SessionStatus.Idle as soon as a turn ends, even when the chat still has queuedMessages that the host is about to drain into a new turn. Clients therefore observe a spurious InProgress -> Idle -> InProgress flicker on every queued turn.
Where
types/channels-chat/reducer.ts:144:
} else if (state.activeTurn) {
activity = SessionStatus.InProgress;
} else {
activity = SessionStatus.Idle;
}
There is no consideration of state.queuedMessages, so the gap between one turn completing and the next queued turn starting is reported as an idle session.
Impact
In VS Code this surfaces as a spurious "session finished" OS notification while the user still has messages queued. It is most visible when a session is open in one window but only listed in another (e.g. the editor window vs. the Agents window).
Clients cannot work around this on their own for unsubscribed sessions, because the queue is not visible at summary level:
queuedMessages/steeringMessageexist only on the fullChatState(types/channels-chat/state.ts).ChatSummarycarries onlystatus— no queue fields.SessionState.chatscontains summaries only.
So a client that has not subscribed to a chat has no signal at all that work is queued. VS Code is shipping a time-based debounce as a stopgap, which is a heuristic and can still leak a notification when a drain is slow.
Suggested fix
Report InProgress when there is no active turn but a drainable queued message exists.
"Drainable" must mirror the host's actual admission conditions, otherwise a session can get stuck reporting InProgress for a queue that will never drain. In the VS Code host implementation those conditions are: no active turn, queuedMessages non-empty, no steeringMessage, and the latest turn is not an Error with resumable: true.
Two edge cases worth deciding explicitly:
- Cancellation. The VS Code host does not auto-drain on cancel (its turn-end hook only drains on success), but a later queue action does drain. A naive predicate reports
InProgressfor a queue nothing is currently going to drain. - Truncation. Drainability derived from
turns.at(-1)becomes unknowable once turns are truncated, since the history the predicate depends on is gone.
Both suggest the queue's drainability may deserve to be explicit state rather than something re-derived from turn history.
An alternative (or complement) is to expose minimal queue information on ChatSummary — e.g. a queued-message count — so clients can reason about it without subscribing.
Context
Found while fixing spurious agent-session notifications in microsoft/vscode. The reducer is vendored into that repo via scripts/sync-agent-host-protocol.ts, so the fix has to land here first and then be re-synced.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the status calculation at types/channels-chat/reducer.ts:144, then read types/channels-chat/state.ts and the ChatSummary shape to understand which queue state is available. Compare the reducer behavior with the VS Code host's drain conditions, including cancellation and truncated turns. Done means queued work no longer produces a spurious Idle status, and the protocol change can be resynced through scripts/sync-agent-host-protocol.ts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100