Agent executes thousands of tool calls from one model response without a per-response limit
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Type: Bug
## Environment
- VS Code Insiders: `1.138.0-insider`
- GitHub Copilot: `0.66.2026091503`
- Remote: WSL
## Summary
During a long-running Agent chat with memory enabled, one assistant response contained **3,871 `memory` tool requests**. VS Code accepted the response, executed **3,870** of those requests, and rendered each request as a separate **Read memory** row in Chat.
The model/backend produced the pathological request batch, but the client had no effective per-response limit or circuit breaker before dispatching and rendering it.
## Diagnostic evidence
The persisted transcript and direct debug log agree:
- One `assistant.message` contained 3,871 `toolRequests`; all were calls to the memory tool.
- The requests referenced 3,781 distinct paths (90 duplicate requests).
- 2,253 requests belonged to one recursively expanding family of synthesized `.md` paths, with suffixes repeatedly appended to earlier candidates.
- None of those 2,253 candidate files existed: 1,302 completed with `No memories found`, and the remaining 951 were canceled.
- The client spent nearly 14 minutes executing the complete batch before interruption.
- No bogus memory files were created; this was a runaway sequence of reads.
The response was unusually large, but it was successfully parsed and persisted as one assistant message. This was not a client-side duplication of a small set of tool calls—the message itself contained the full batch.
## Steps to reproduce
This has been intermittent rather than intentionally reproducible:
1. Use Agent mode in a long-running chat with the memory tool available and a small number of real memory files.
2. Submit another task after substantial prior chat history.
3. If the model emits a very large parallel batch of speculative memory reads, observe that VS Code dispatches all of them and adds thousands of **Read memory** rows.
## Expected
VS Code should treat model-produced tool calls as bounded input and prevent a single response from scheduling an unbounded batch. For example:
- Enforce a sane hard limit on tool calls per assistant response, independent of the normal multi-turn request limit.
- Reject or truncate an oversized batch before execution and surface a clear recoverable error.
- Deduplicate identical requests before dispatch.
- Consider stopping a speculative read batch after repeated `not found` results.
- Avoid rendering thousands of individual progress rows for a rejected batch.
## Actual
VS Code dispatched nearly every call in the 3,871-call response, flooded Chat with progress rows, performed thousands of nonexistent-path lookups, and kept the turn busy for almost 14 minutes.
The existing request/continuation limit did not prevent this because the calls arrived together in one model response.
I cannot attach the raw screenshot or transcript because they include private workspace context, but I can provide additional sanitized diagnostics if needed.
Contributor guide
Assessment
This issue has not been assessed yet.