Skip to content

Eager tool execution loops to the recursion limit for agents with large custom/MCP tool arguments #14371

Description

@louislusesese

What happened

Agents whose tools emit large arguments (long MCP query SQL, multi-line bash_tool/openpyxl scripts) intermittently fail a run with:

Tool call changed after eager execution started; refusing to re-run the tool to avoid duplicate side effects.

The model treats the guard error as a failed tool call and retries. Because the tool arguments are large, the eager-prestarted arguments and the finally-assembled arguments differ again on the retry, re-triggering the same guard. The loop consumes the recursion limit and the run ends with Recursion limit of 50 reached after a long wall-clock time.

Root cause

eagerEventToolExecution prestarts a tool as soon as its arguments parse from the stream. stream.ts's isEagerToolExecutionEnabledForBatch gates the whole batch on graph.eagerEventToolExecution?.enabled === true, and ToolNode compares the prestarted args to the final args with recordArgsEqual; any difference returns the "changed after eager execution started" error instead of running the tool.

main already excludes the highest-risk tools via excludeToolNames (create_file, edit_file, execute_code, bash_tool, ask_user_question). That covers file/code tools, but not custom or MCP tools that also emit large arguments — e.g. a run_select_query-style MCP tool with a long SQL string still trips the guard and loops.

Proposal

Make eager tool execution disablable per agent. Some agents (customer-analytics/QA agents that build large SQL and spreadsheets) benefit from turning it off entirely; most agents should keep it on for the latency win.

Concretely: an optional eager_execution boolean on the agent (mirroring the existing recursion_limit field), read when building the run config:

eagerEventToolExecution: {
  enabled: agents[0]?.eager_execution !== false,
  excludeToolNames: [ /* unchanged */ ],
},
  • Unset (default) → enabled: true — no behavioural change for any existing agent.
  • false → eager prestart skipped for the run; tools run once full arguments are assembled.

This composes with the existing excludeToolNames list rather than replacing it, and gives operators a switch for agents whose custom/MCP tools aren't (and can't easily be) enumerated in excludeToolNames.

Happy to open a PR (schema → validation → data-provider → run config → an "Eager Tool Execution" toggle in the agent Advanced panel), following the recursion_limit field as the pattern.

Environment

  • Repro seen on agents backed by Bedrock (Claude Sonnet) at temperature 1 with an MCP query tool and the bash/create_file code tools.
  • Higher temperature makes the eager-vs-final argument mismatch more frequent, which is why it presents as "worked before, fails now" after a temperature change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions