Skip to content

Send strict: false for function tools on the Responses API to preserve Chat Completions behavior#844

Open
bdegomme wants to merge 1 commit into
crmne:mainfrom
bdegomme:fix/responses-non-strict-tools-by-default
Open

Send strict: false for function tools on the Responses API to preserve Chat Completions behavior#844
bdegomme wants to merge 1 commit into
crmne:mainfrom
bdegomme:fix/responses-non-strict-tools-by-default

Conversation

@bdegomme

@bdegomme bdegomme commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #843

This is AI generated but I understand every line. I'm also fine with accepting the new default strict true, but then it should be mentioned in the upcoming 2.0 upgrading guide.

What this PR does

Explicitly sends strict: false in function tool definitions rendered by Protocols::Responses::Tools.tool_for, restoring the tool-calling behavior applications had on Chat Completions. Tools can opt into strict validation per class with provider_options strict: true.

The problem

OpenAI's two APIs have opposite server-side defaults for function tool strict:

  • Chat Completions FunctionObject.strict: default false (OpenAPI spec)
  • Responses FunctionTool.strict: default true ("Whether to enforce strict parameter validation. Default true.")

RubyLLM never sends the strict field, so when OpenAI switched to defaulting to the Responses API, every existing tool silently flipped into strict mode. Under strict mode the model's output is grammar-constrained to emit every property in the schema — parameters left out of required stop being optional (strict mode expresses optionality as nullable types + membership in required instead).

Concretely: a search tool with a dozen optional filters that previously received only the relevant ones now gets a value for every filter on every call, changing tool behavior without any application code change. The upgrade guide covers the Responses API switch but doesn't mention this side effect, and there's no way to notice it except by observing degraded tool calls.

The fix

tool_for now always includes strict: false in the flat function definition. provider_options is merged after, so provider_options strict: true on a tool class opts back in for schemas that meet the strict-mode requirements.

Docs updated:

  • docs/_reference/upgrading.md — note under "OpenAI now defaults to the Responses API" explaining tools stay non-strict and how to opt in.
  • docs/_core_features/tool-parameters.md — new "Strict Mode on the OpenAI Responses API" subsection with an opt-in example (nullable optional params, all properties in required).

Tests

  • Updated the flat-function-definition expectation in spec/ruby_llm/protocols/responses/chat_spec.rb and added an opt-in test for provider_options strict: true.
  • Existing OpenAI VCR cassettes still match (default VCR matching is method + URI), verified with CI=true bundle exec rspec spec/ruby_llm/chat_tools_spec.rb -e openai — 18 examples, 0 failures.

The Responses API defaults function tool strict to true, unlike Chat
Completions where it defaults to false. Since RubyLLM never sent the
field, switching OpenAI to the Responses API silently enabled strict
mode for every tool: the model becomes grammar-constrained to emit all
schema properties on each call, so parameters left out of 'required'
stop being optional.

Send strict: false explicitly to preserve the 1.x Chat Completions
behavior. Tools can opt back into strict validation with
'provider_options strict: true'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bdegomme bdegomme force-pushed the fix/responses-non-strict-tools-by-default branch from 81712be to 966014e Compare July 13, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Responses API silently enables strict tool validation — optional tool parameters are always filled in

1 participant