Skip to content

Virtual tool grouping silently drops tools mid-session; error blames the user ("currently disabled by the user") #324113

Description

@wycats

Summary

In a long agent session with a large toolset (~106 registered tools), the virtual tools packer recomputed its grouping at a turn boundary and dropped a tool from the request toolset entirely — it was neither top-level nor inside any activate_* virtual group. The same tool had been called successfully 12 times in the minutes immediately before. Subsequent calls failed with:

Tool exo-run is currently disabled by the user, and cannot be called.

No user action had occurred (no Configure Tools interaction at all)

Evidence

From the session's debug logs (debug-logs/<sessionId>/tools_N.json snapshots plus main.jsonl):

Snapshot Time exo-run status
tools_0.json 20:25 Present as a top-level tool; 12 successful tool_call events follow (20:49–20:53)
tools_1.json 21:00 Absent from the entire payloadcontent.includes("exo-run") === false. Not top-level, not in any virtual group, not even mentioned in group prose
tools_2.json 21:04 Still absent (mentioned only inside a sibling tool's description text)

The tools_0 / tools_1 diff shows the repack was lossy in both directions: 5 tools dropped from the top level (exo-run, exo-ping, and three tools from a browser-automation extension), while 7 different tools from the same browser extension surfaced. A sibling tool (exo-ping) survived by being folded into an activate_diagnostic_tools group description — exo-run just vanished.

A second occurrence exists in the same session log: tools_5.json (previous day) is missing all five exo-* tools the same way.

Reproduced on: VS Code stable, macOS, default github.copilot.chat.virtualTools.threshold (not set by user). Notably, grouping was active at ~106 tools even though the setting's documented default threshold is 128.

Problems

Needless to say, this is a pretty broken and confusing experience for both the agent and the user. The problems compound on each other.

  1. The repack loses tools outright. A registered, enabled tool ended up neither top-level nor inside any virtual group after regrouping.
  2. Recency/usage does not pin tools. The dropped tool was in active, successful use in the same session minutes before the repack.
  3. The error message misattributes the failure to the user. "Currently disabled by the user" sent both me and the agent down a false debugging path (toggling tools in Configure Tools, running tool-reset commands, reloading). The actual state was "not present in this turn's assembled toolset."
  4. Each repack changes the serialized tool list, which sits at the front of the prompt — invalidating provider-side prompt caches on every regroup even when no tools actually changed. With Anthropic-style prefix caching this is a full re-ingestion of the conversation.

Suggested fixes

  • Treat "successfully called this session" as a pinning signal so in-use tools survive regrouping.
  • Guarantee the packer is lossless: every registered tool must be reachable either top-level or via some activate_* group.
  • Reword the error to distinguish "tool not in this turn's toolset (regrouped/dropped)" from "disabled by the user."
  • Consider stabilizing the grouping across turns within a session unless the underlying tool registrations actually change (also helps prompt-cache hit rates).

Happy to attach sanitized tools_N.json diffs and main.jsonl excerpts if they would be helpful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions