Subagent delegation bypasses ToolCallLimitMiddleware, degenerate queries followed

I hit something worth flagging here, since it directly interacts with the ToolCallLimitMiddleware fix discussed above, and shows a real gap in where that protection actually applies.

Setup:
I have a create_deep_agent orchestrator with ToolCallLimitMiddleware(tool_name="sigma_search", run_limit=2, exit_behavior="continue") on the main agent, plus one explicitly defined custom subagent (research-agent) scoped to a separate web-search tool only, not sigma_search.

Expected behavior:
Once the main agent’s sigma_search limit is hit, any further attempt should get intercepted with the corrective ToolMessage and the model should stop trying.

What actually happened:
The limit worked correctly for the main agent’s own direct calls. But at a later point in the same run, the trace shows a call to sigma_search originating from "lc_agent_name": "general-purpose", "ls_agent_type": "subagent", this is deepagents’ own default built-in subagent, not the research-agent I explicitly defined. That default subagent apparently inherited sigma_search from the parent’s tool list, and inside its own execution, it fired three parallel sigma_search calls in a single turn, each with a badly degenerate query, the same phrase (“client IP address source IP address”) repeated roughly 15 times in one string. This happened at langgraph_step: 112, with a 41,148-token prompt at that point, real evidence of coherence breakdown under accumulated context, not just a normal repeat.

Why the limit didn’t catch it:
A subagent runs as its own separate subgraph. Per the customization docs, “There is no SubAgentMiddleware inside a subagent graph”, meaning middleware attached to the parent agent doesn’t automatically extend into a subgraph’s internal execution. The sigma_search limit is real and enforced for the main agent’s own calls, but a tool call made from inside a delegated subagent runs in a separate scope the parent’s middleware instance never sees.

Open questions for the community:

  1. Is there a way to prevent the model from delegating to the default general-purpose subagent at all, short of a prompt instruction (which is unreliable on its own, per everything else in this thread)? Something like an explicit flag to disable/omit the default subagent entirely?
  2. Is there a supported way to make a ToolCallLimitMiddleware instance (or an equivalent) apply within a subagent’s own execution scope, not just the parent’s?
  3. Has anyone else seen a model effectively route around a tool-call limit by delegating the same intent to a subagent instead of calling the tool directly? Whether or not this was “intentional” workaround-seeking by the model versus incidental, the practical effect is the same, the limit didn’t hold everywhere it needed to.

Happy to share the full trace if useful.

Hello @PluckyLemur20 , welcome to Langchain community.

Nice find, this one’s a sneaky gap. I don’t think it’s a bug though, just how subagents are set up. The default general-purpose subagent gets all the parent’s tools (so sigma_search comes along for the ride), and isolated subagents don’t inherit the parent’s custom middleware. Your limiter only ever sees the main agent’s own calls.

For your questions:

Disabling the default: Yes, there’s a supported way. Set general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False) on the harness profile. Your research-agent still works, and the default one is gone.

Limits inside a subagent: Each subagent spec takes its own middleware list, so you can put a limiter there. You can also define your own subagent named general-purpose, which replaces the default completely. That also lets you control its tools:

subagents=[{
    "name": "general-purpose",
    "description": "General multi-step tasks",
    "system_prompt": "...",
    "tools": [],  # no sigma_search
}]

One heads-up, and this is my read of the docs: a limiter inside a subagent counts that subagent’s own run, so the budget resets every time the parent calls task. If you want a hard cap, I’d just keep sigma_search out of the subagent’s tools. Prompt instructions alone won’t hold.

Models routing around limits: I haven’t seen anyone report that specifically, but delegation is an obvious loophole.

The 15x repeated query at ~41k tokens looks like its own context-degradation problem. A per-subagent call limit would at least stop it from spiraling.

Did the bad queries come from the default general-purpose subagent picking up sigma_search? If so, a cap on the tool itself would hold no matter which agent calls it.