-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
Summary
OpenRouter agent blocks with a response format and tools enabled were not applying the response format when the model returned no tool calls. This is an OpenRouter-wide behavior (not just Grok), and it explains why structured output fields (for example file_key) were missing and why fallback warnings appeared.
Root cause
In the OpenRouter provider, the final structured-output call was only made when tools were configured AND toolCalls.length > 0. If the model decided not to use any tools, the structured-output pass was skipped and the raw model response was returned, bypassing the response format entirely.
Expected behavior
When responseFormat is configured, the final response should be coerced into the structured schema even if no tools were called, as long as the model supports structured output. When tool calls are present, the existing structured-output behavior should remain unchanged.
Actual behavior
If no tool calls were returned:
- The structured-output pass was skipped
- The model returned its own freeform output
- Required fields (e.g.,
file_key) were missing - The system emitted a structured-output fallback warning
Fix
I fixed it by applying the structured-output pass when tools are configured even if no tool calls were returned. When tool calls are present, the existing structured-output path is unchanged.
// If responseFormat is set and tools were configured, perform a final structured output call.
// This handles both cases: when tools were used (toolCalls.length > 0) and when the model
// decided not to use any tools.
if (request.responseFormat && hasActiveTools) {
const noToolCallsUsed = toolCalls.length === 0
if (noToolCallsUsed) {
logger.info(
'Tools configured but model returned no tool calls; applying responseFormat for structured output'
)
}
const finalPayload: any = {
model: payload.model,
messages: [...currentMessages],
response_format: request.responseFormat,
}
// ...
timeSegments.push({
type: 'model',
name: noToolCallsUsed ? 'Structured output (no tool calls)' : 'Final structured response',
startTime: finalStartTime,
endTime: finalEndTime,
duration: finalDuration,
})
}Notes on OpenRouter model support
OpenRouter includes models that do not support structured output, so those will still warn/fallback. This fix ensures that models which do support structured output now receive the response format correctly even when they skip tool calls.
Reproduction
- Create an agent block using any OpenRouter model
- Enable tools and set a custom
responseFormatwith a field likefile_key - Run a prompt where the model decides not to call tools
- Observe the missing field / fallback warning prior to the fix