fix(llm): pin claude-cli output to a JSON schema when supported (#2076)#2095
Open
Yyunozor wants to merge 1 commit into
Open
fix(llm): pin claude-cli output to a JSON schema when supported (#2076)#2095Yyunozor wants to merge 1 commit into
Yyunozor wants to merge 1 commit into
Conversation
…hify-Labs#2076) The claude-cli backend delivers the extraction schema in the user turn and trusts the model to emit raw JSON. Newer Claude Code releases treat that prompt as an agentic task and report the result in prose instead ("Knowledge graph extracted — 21 nodes, 20 edges…"), so the graph parses empty, reads as truncation, and adaptive-retry bisects without ever converging. Pass --json-schema (structured output) when the CLI advertises it — probed once via `claude --help` and cached — so the object shape is constrained regardless of prompt framing. Older CLIs that predate the flag keep the user-turn prompt as a fallback. The `result` envelope still carries the JSON string, so the parse path is unchanged.
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.
Summary
The
claude-clibackend puts the extraction schema in the user turn and trusts the model to emit raw JSON (thellm.py:1376workaround, "verified against Claude Code 2.1.197"). On newer Claude Code the model treats that prompt as an agentic task and reports the result in prose instead —Knowledge graph extracted — 21 nodes, 20 edges…. That parses to zero nodes,_response_is_hollowreads truncation, and adaptive-retry bisects the chunk without ever converging, so the graph comes out empty (#2076).Why this is version-robust, and how it was checked
We run Claude Code as this backend's harness, so the failing component is directly testable here. On 2.1.207 the current user-turn workaround still returns JSON — the empty-graph break does not reproduce there, so the regression is version-gated, consistent with the 2.1.216 report. But the failure mode is easy to force and to fix on a live CLI: a prompt that invites prose makes
claude -p --output-format jsonput a conversational summary inresult, while adding--json-schemamakes the same call return the object regardless of framing (also surfaced in astructured_outputenvelope field). Structured output is a structural guarantee independent of the model's discretion, so it survives the prompt-behaviour drift that broke the prompt-shape workaround.Fix
Pass
--json-schema— a schema pinning the top-level{nodes, edges}shape graphify consumes, item internals left loose so valid extractions are never rejected — when the CLI advertises the flag, probed once viaclaude --helpand cached. Older CLIs that predate the flag keep the user-turn prompt as a fallback, unchanged. Theresultenvelope still carries the JSON string, so the_parse_llm_jsonpath is untouched.The issue's second suggestion — routing a successful-sounding prose response away from the bisect path — is complementary and left out of scope; with structured output the prose case no longer arises on supported CLIs.
Validation
tests/test_claude_cli_backend.py: 28 passed, 5 new (flag present when supported, absent when not, the--helpcapability probe, safe fallback on probe error). Full suite: 3317 passed on the branch vs 3312 on the parente32c9f4, same environment — delta is exactly these 5 tests. (13 failures in unrelated suites — terraform/ollama/manifest/install-references — are pre-existing, identical on the parent, from optional deps absent locally.)ruff checkclean.