feat(adapters/langgraph): make agent structured output not hang or silently vanish - #210
Open
spichen wants to merge 1 commit into
Open
feat(adapters/langgraph): make agent structured output not hang or silently vanish#210spichen wants to merge 1 commit into
spichen wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
create_agent(response_format=...)ties the agent's exit condition to getting a parseable structured response. The adapter set it for any agent with declared outputs, so a model that won't produce one broke two ways.With no tools the agent loops.
create_agentsetsrecursion_limit=9999where LangGraph's default is 25, so it burns thousands of model calls and then raises aGraphRecursionErrornaming neither the agent nor the schema.With tools it's quieter and worse. Routing treats a turn with no tool calls as done, so the agent exits,
structured_responseis never set, and a two-output agent returns zero outputs with no error (langchain#36349, open).Nothing upstream bounds this.
ToolStrategy.handle_errorsonly covers malformed tool calls;True,Falseand a custom message all still hang. See also langgraph#6731 (closed, not planned) and this forum thread.setup.pyallowslangchain>=1.2.0unbounded, so it isn't one bad version.Fix
An agent whose only declared output is a string needs no structured generation, so
response_formatis skipped and the value read from the final message.LlmNodeExecutoralready worked this way;AgentNodenow matches it.Everything else keeps
response_formatplus aStructuredOutputGuardmiddleware.after_modelbounds the loop by counting consecutive turns that end in anAIMessagewith no tool calls.after_agentcatches the silent exit, which that budget never sees. Turns with tool calls don't count, since underToolStrategythe structured response is itself a tool call.is_single_string_outputmoved toadapters/_utils.py, replacing two copies of the predicate inLlmNodeExecutor, one of them dead.AgentMiddlewarenow comes from_types.pyas aLazyType, so the guard is a plain module-level class and the module still imports without thelanggraphextra.Testing
Against a model that ignores structured output:
GraphRecursionError(9999 calls){'answer': '42'}GraphRecursionError(9999 calls)That last row is the one that matters: neither hook may fire on a model that does produce the response.
454 passing across
tests/adapters,tests/serializationandtests/validationunderSKIP_LLM_TESTS=1, pinned toconstraints/constraints.txt; failures and skips unchanged frommain.black,isort,pyflakes,mypyclean. The 10 new tests build no LLM config, so they run offline instead of skipping.