Repository navigation
fix(adapters/langgraph): honour the declared output format, not its shape - #42
Merged
spichen merged 1 commit intoSep 22, 2026
Merged
Conversation
…hape
A single string output is treated as the agent's free text and skips
structured generation. That heuristic cannot tell two different things
apart, because both produce the identical outputs list:
text agent outputs: [{title: "output", type: "string"}]
JSON, one string field outputs: [{title: "sentiment", type: "string"}]
A caller that declares one JSON field therefore gets prose, with no tool
registered and nothing in the request telling the model a schema was
wanted. Adding a second field changes nothing about the model or the
prompt, yet works, which is what makes the failure so hard to place.
Gate on the caller's declared format when there is one. `metadata`
carries `outputFormat` (`TEXT` or `JSON`); when it is absent the previous
shape heuristic still applies, so callers that declare no format keep
today's behaviour.
Weak models stay protected: a single string output still satisfies
is_single_string_output, so extract_outputs_from_invoke_result continues
to fall back to the final message when structured generation returns
nothing. The worst case is the prose that is returned today, never an
empty output.
Refs OA-1681
Author
|
Closing — wrong base. This was branched from c83e113 (the commit agentfabric pins), which is not an ancestor of main, so the diff swept in unrelated commits. Reopening against the correct base shortly. |
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.
Fixes the case where an agent that asks for JSON output gets prose instead.
The problem
is_single_string_outputtreats one string output as the agent's free text and skips structured generation. It cannot distinguish two different intents, because both produce an identicaloutputslist:So a caller declaring a one-field JSON schema gets no structured-output tool in the request at all — the model is never told a schema was wanted, and answers in prose. Adding a second field changes nothing about the model, endpoint or prompt, yet works.
Verified against a vLLM deployment (
nvidia/GLM-5.3-NVFP4) which supportsjson_schema,json_objectand forced tool calls:AgentOutputModelIn a flow it is worse than cosmetic: the declared property is absent, so the downstream node raises
Expected node ... to have a value for property ..., but none was foundand the flow dies.The change
Gate on the caller's declared format when one is given.
metadata["outputFormat"]carriesTEXTorJSON.When no format is declared the previous shape heuristic still applies, so existing callers keep today's behaviour.
Why weak models stay safe
The heuristic exists so a string output works on models without structured-output support. That protection is unchanged: a single string output still satisfies
is_single_string_output, soextract_outputs_from_invoke_resultstill falls back to the final message when structured generation returns nothing. The worst case is the prose returned today — never an empty output.Note that
oracle/agent-specmain has no such heuristic; it always builds the response model and forcesToolStrategy. This moves the fork back toward that behaviour for callers that declare a format.Refs OA-1681