Repository navigation
fix(output): send responseFormat only on calls that offer no tools - #660
Merged
Merged
Conversation
LinuxDevil
force-pushed
the
fix/structured-output-tools-loop
branch
2 times, most recently
from
October 16, 2026 20:49
14a1bb5 to
ad1f2ab
Compare
A strict json_schema response format next to tools made
openai/gpt-4o-mini via OpenRouter call tools on every step until maxSteps.
responseFormat now goes only on calls without tools (no-tool agents, the
forced answer at maxSteps, the repair step); tool-offering calls answer
from the in-prompt schema with the existing parse/repair.
output: { schema, responseFormat: 'always' } restores the old behavior and
is the default with promptSchema: false. object.delta no longer depends on
responseFormat being set. Docs: structured output, durable execution
(resume() returns a result; pending() lists runs active elsewhere),
installation (TS 6+ needs "types": ["node"]).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LinuxDevil
force-pushed
the
fix/structured-output-tools-loop
branch
from
October 16, 2026 20:51
ad1f2ab to
7fc68c1
Compare
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
With
output(a zod schema) and tools, every model call sent a strictjson_schemaresponseFormat, including calls that offered tools.openai/gpt-4o-minivia OpenRouter then kept calling tools and never answered: a consumer harness hitmaxStepsin 18 of 18 runs. That is the setup the docs lead with. When a captured sub-agent request was replayed against OpenRouter, it returnedtool_calls6/6 withresponse_formatandstopwith valid JSON 6/6 without it.Fix
responseFormatis sent only on calls that offer no tools: an agent with no tools, the forced "answer now" call atmaxSteps(toolChoice: 'none'counts as no tools), and the repair step, which is flagged on the run state. Calls that offer tools answer from the schema in the prompt, and the existing parse/repair still applies.output: { schema, responseFormat: 'final' | 'always' }. The default is'final', or'always'withpromptSchema: false, because the response format is then the only copy of the schema. An invalid value throwsConfigurationError.object.deltastreaming was keyed onrequest.responseFormat. It now depends on the run havingoutput, so it still streams on tool-offering steps.responseFormatis sent, how it interacts with tools, a table of modes), upgrading (behavior-change row with opt-out), durable-execution (agent.resume()resolves with a result rather than a stream,agent.stream([], { sessionId })streams a resumed run,pending()also lists runs active in other processes), installation (TS 6+ needs"types": ["node"], since the root.d.mtsusesBufferand importsnode:crypto/node:http/node:net). CHANGELOG, api reports, llms.txt.Verification
structuredOutput.test.ts: noresponseFormaton tool steps, prose with embedded JSON parses with no repair, a plain-text answer gets repaired by a call that carriesresponseFormat, later steps go without it again, the forced answer andtoolChoice: 'none'carry it,'always'mode, thepromptSchema: falsedefault, invalid mode rejected,object.deltaon a tool step.npx tsc --noEmit,npm run lint,npm run build,api:check,docs:llms:checkall clean. Full vitest: the only failures are Windows/env ones (create-lousho-agent template e2e, sqlite lock timing, http timeouts).src/execution/structuredOutputTools.live.test.ts(gpt-4o-mini, one tool, zod output) passed 3 of 3 runs, each in 2 steps with a valid object. A/B against real npm/GitHub tools with the harness's researcher prompt:'always'(old behavior) and'final'(new) both took 3 steps in this setup. The loop shows up in the captured-request replay above (6/6 vs 0/6), not in these fresh runs.🤖 Generated with Claude Code