Skip to content

fix(langgraph): pass the recursion limit of the flow run on to AgentNode agents - #261

Open
fede-kamel wants to merge 1 commit into
oracle:mainfrom
fede-kamel:fix/langgraph-agentnode-recursion-limit
Open

fix(langgraph): pass the recursion limit of the flow run on to AgentNode agents#261
fede-kamel wants to merge 1 commit into
oracle:mainfrom
fede-kamel:fix/langgraph-agentnode-recursion-limit

Conversation

@fede-kamel

Copy link
Copy Markdown
Member

Relates to #227.

Root cause

Two things combine in the CTS failures reported in #227:

  1. The non-termination itself: the adapter enables response_format=ToolStrategy(...) for any agent with declared outputs. With no tools, LangChain's create_agent routes from the model back to the model until a structured_response exists, so a model that answers in prose (the CTS deterministic LLM server, or any provider ignoring the structured-output tool) loops until GraphRecursionError. Reproduced deterministically with a fake chat model (agent with outputs and no tools: recursion error after 12 model calls; same agent without outputs: terminates in 2 calls). Open PR feat(adapters/langgraph): make agent structured output not hang or silently vanish #210 addresses this part and, applied locally, makes the CTS case terminate in 2 calls.
  2. What this PR fixes: create_agent binds recursion_limit=9999 to the agents it compiles, and AgentNodeExecutor invoked the nested agent with the loader config only. The limit configured for the enclosing flow run therefore never applied inside an AgentNode: with recursion_limit=12 on the flow run, a non-terminating nested agent made 9999 model calls before failing.

Changes

  • langgraph/_node_execution.py: AgentNodeExecutor reads the config of the current run and passes an explicitly configured recursion limit (any value other than LangChain's default of 25) on to the nested agent. A limit set in the loader config still takes precedence, and runs using the default limit keep the agent's own limit so tool-heavy agents are not cut at 25 steps.
  • tests/adapters/langgraph/flows/test_agentnode_recursion_limit.py: sync and async runs with recursion_limit=6 stop the nested agent after 3 model calls (5000 calls on main before the test was capped), the loader config wins over the run config, and a run with the default limit keeps the agent's limit. Fake chat model, no LLM calls.
  • Changelog entry under Bug fixes.

Verification

  • SKIP_LLM_TESTS=1 pytest tests/adapters/langgraph: 113 passed, 89 skipped.
  • Public CI steps (black, isort, flake8 + copyright, bandit, mypy, tests/run_tests.sh) reproduced locally on Python 3.10 through 3.14.
  • Live check against OCI Generative AI models: a compliant model terminates in one turn with the structured-output tool call, so the loop only shows with models or servers that answer in prose.

Notes for reviewers

…ode agents

create_agent binds recursion_limit=9999 to the agents it compiles. The
AgentNodeExecutor invoked that agent with the loader config only, so
the limit configured for the enclosing flow run never applied to the
nested agent: an agent that did not terminate made thousands of model
calls before failing (5000 calls with a fake model in the new test on
the previous code), whatever recursion_limit the caller had set.

The executor now reads the config of the current run and passes on a
recursion limit that was explicitly configured (any value other than
LangChain's default of 25). A recursion limit set in the loader config
still takes precedence, and runs using the default limit keep the
agent's own limit so tool-heavy agents are not cut at 25 steps.

Investigation notes for oracle#227: the non-termination
itself comes from create_agent's structured-output loop (ToolStrategy
with no tools routes back to the model until a structured response
exists), which the adapter enables for any agent with outputs; the
CTS deterministic LLM server answers in prose, so such agents loop
until the recursion limit. Open PR oracle#210 addresses that part.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
@fede-kamel
fede-kamel requested a review from a team September 11, 2026 16:22
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant