Summary
A browser clickElement tool call can get stuck in Preparing after the Agent Host removes the active client. The click never reaches Playwright; the workbench invokes the browser tool with {} parameters and crashes during tool preparation.
Observed
In an Agents/Copilot CLI session using built-in browser tools:
openBrowserPage succeeds.
clickElement on the initial Start button succeeds.
screenshotPage succeeds.
- The next
clickElement on the board's Run button stays stuck at Preparing.
The session event stream ends with:
tool.execution_start clickElement
permission.requested clickElement
# no permission.completed
# no tool.execution_complete
Key log evidence
The model requested valid arguments:
{
"element": "Run button on Research Agent",
"pageId": "<page-id>",
"ref": "e200"
}
But the workbench invoked the underlying browser tool with empty parameters:
[AgentHost] Invoking client tool: clickElement
[LanguageModelToolsService#invokeTool] Invoking tool click_element with parameters {}
[error] Cannot read properties of undefined (reading 'toString')
at createBrowserPageLink(...)
at ClickBrowserTool.prepareToolInvocation(...)
The AHP sequence for the same tool call was:
chat/toolCallStart clickElement
chat/toolCallReady confirmed="not-needed" # no toolInput
chat/toolCallComplete success=false error="Client <client-id> disconnected before completing clickElement"
chat/toolCallReady confirmation UI with real toolInput
About 6 seconds earlier, the same session received:
session/activeClientRemoved clientId=<client-id>
Suspected cause
This looks like an Agent Host/client-tool lifecycle race:
- The active client is removed from session state while the UI/client connection is still participating in the turn.
- A later client-contributed browser tool call is treated as orphaned/disconnected.
- The synthetic
toolCallReady without toolInput is consumed by the workbench client-tool handler.
- The handler falls back to
{} and invokes click_element before the later toolCallReady containing the real toolInput arrives.
ClickBrowserTool.prepareToolInvocation assumes pageId is present, calls createBrowserPageLink(undefined), throws, and the original Copilot tool execution remains stuck waiting for completion/permission state.
Relevant code paths:
src/vs/platform/agentHost/node/protocolServerHandler.ts
- disconnected client tool call handling emits synthetic ready/complete events
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionHandler.ts
- missing
toolInput falls back to {} once status is not Streaming
src/vs/workbench/contrib/browserView/electron-browser/tools/clickBrowserTool.ts
prepareToolInvocation assumes pageId is defined
Expected
A disconnected/orphaned client-tool call should fail cleanly and unblock the model/UI, or be retried with a replacement active client. It should not invoke the local browser tool with {} parameters or leave the tool call stuck in Preparing.
Possible fixes
- Do not invoke client tools from
toolCallReady events that lack toolInput when the tool has required arguments or _meta.toolArguments exists.
- Ensure disconnected-client synthetic
toolCallReady/toolCallComplete ordering cannot race with later confirmation UI events for the same tool call.
- Harden browser tool
prepareToolInvocation against missing pageId so malformed protocol state becomes a clean tool error.
- Investigate why
session/activeClientRemoved fired while the client was still successfully confirming/completing tool calls in the same session.
Summary
A browser
clickElementtool call can get stuck inPreparingafter the Agent Host removes the active client. The click never reaches Playwright; the workbench invokes the browser tool with{}parameters and crashes during tool preparation.Observed
In an Agents/Copilot CLI session using built-in browser tools:
openBrowserPagesucceeds.clickElementon the initialStartbutton succeeds.screenshotPagesucceeds.clickElementon the board'sRunbutton stays stuck atPreparing.The session event stream ends with:
Key log evidence
The model requested valid arguments:
{ "element": "Run button on Research Agent", "pageId": "<page-id>", "ref": "e200" }But the workbench invoked the underlying browser tool with empty parameters:
The AHP sequence for the same tool call was:
About 6 seconds earlier, the same session received:
Suspected cause
This looks like an Agent Host/client-tool lifecycle race:
toolCallReadywithouttoolInputis consumed by the workbench client-tool handler.{}and invokesclick_elementbefore the latertoolCallReadycontaining the realtoolInputarrives.ClickBrowserTool.prepareToolInvocationassumespageIdis present, callscreateBrowserPageLink(undefined), throws, and the original Copilot tool execution remains stuck waiting for completion/permission state.Relevant code paths:
src/vs/platform/agentHost/node/protocolServerHandler.tssrc/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionHandler.tstoolInputfalls back to{}once status is notStreamingsrc/vs/workbench/contrib/browserView/electron-browser/tools/clickBrowserTool.tsprepareToolInvocationassumespageIdis definedExpected
A disconnected/orphaned client-tool call should fail cleanly and unblock the model/UI, or be retried with a replacement active client. It should not invoke the local browser tool with
{}parameters or leave the tool call stuck inPreparing.Possible fixes
toolCallReadyevents that lacktoolInputwhen the tool has required arguments or_meta.toolArgumentsexists.toolCallReady/toolCallCompleteordering cannot race with later confirmation UI events for the same tool call.prepareToolInvocationagainst missingpageIdso malformed protocol state becomes a clean tool error.session/activeClientRemovedfired while the client was still successfully confirming/completing tool calls in the same session.