fix: send reasoning_effort="none" so gpt-5.6 models accept function tools - #479
fix: send reasoning_effort="none" so gpt-5.6 models accept function tools#479ivancrneto wants to merge 1 commit into
Conversation
…ools OpenAI rejects function tools on /v1/chat/completions for every gpt-5.6 variant while reasoning is on: Function tools with reasoning_effort are not supported for gpt-5.6-luna in /v1/chat/completions. To use function tools, use /v1/responses or set reasoning_effort to 'none'. That makes gpt-5.6 unusable for the extraction agent, which is a tool loop on chat/completions, and there is currently no way to reach the parameter from configuration. The failure is easy to misread: non-tool calls to the same model keep succeeding, so extraction fails while generation looks healthy. LiteLLM compounds it by masking the provider message behind a TypeError of its own (BadRequestError.__init__() missing 2 required positional arguments: 'model' and 'llm_provider'). Add TOOLS_REQUIRE_REASONING_DISABLED_MODELS alongside the existing TEMPERATURE_RESTRICTED_MODELS set, with a matching _tools_require_reasoning_disabled helper that strips provider routing prefixes the same way. When a request carries tools and the model is in that set, default reasoning_effort to "none". setdefault, placed before params.update(kwargs), so an explicit caller-supplied reasoning_effort still wins. Non-tool calls to gpt-5.6 keep reasoning enabled, and no other model is affected.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughThe change detects GPT-5.6 model variants when function tools are used and injects ChangesTool reasoning compatibility
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to Tool-enabled GPT-5.6 chat-completion requests now disable reasoning by default to avoid provider rejection, while explicit settings and other request types retain their existing behavior. The change is ready to merge. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Your free Security trial is over. An organization admin can upgrade to Advanced for continuous pull request security review or dismiss this notice. Comment |
The problem
OpenAI rejects function tools on
/v1/chat/completionsfor everygpt-5.6variant while reasoning is on:The extraction agent is a tool loop on chat/completions, so this makes the whole gpt-5.6 family unusable for extraction — and there is currently no way to reach
reasoning_effortfrom configuration (noLLMConfigfield, noextra_body, no kwargs passthrough).Two things make it unpleasant to diagnose:
TypeErrorof its own —BadRequestError.__init__() missing 2 required positional arguments: 'model' and 'llm_provider'— so the logs never show the sentence above.I hit this on a self-hosted deployment: pointing the org config at
gpt-5.6-lunafailed 9 extraction runs in ~9 minutes before I rolled back, with only that TypeError to go on.The fix
Follows the existing
TEMPERATURE_RESTRICTED_MODELSidiom rather than inventing a new one:TOOLS_REQUIRE_REASONING_DISABLED_MODELS = {"gpt-5.6"}, declared next toTEMPERATURE_RESTRICTED_MODELSwith the API error quoted in a comment._tools_require_reasoning_disabled(), mirroring_is_temperature_restricted_model()— same prefix-strip for provider routing (openrouter/openai/gpt-5.6-luna), samestartswithmatching._build_completion_params, when the request carriestoolsand the model matches, defaultreasoning_effortto"none".Scope is deliberately narrow:
setdefault, placed beforeparams.update(kwargs), so an explicit caller-suppliedreasoning_effortstill wins.Verification
Against the live OpenAI API through LiteLLM (1.89.3), using the same
drop_params=Truethe client sets — that mattered, because if LiteLLM stripped the parameter the fix would be inert:gpt-5.6-luna+ tools +reasoning_effort="none"gpt-5.6-luna+ tools, noreasoning_effortgpt-5.6-terra+ tools, noreasoning_effortgpt-5.5+ toolsAdded 16 unit tests in
TestToolsRequireReasoningDisabled, mirroringTestTemperatureRestriction: affected/unaffected model matching, provider-prefix stripping, and four param-level tests drivinggenerate_chat_responsethrough a patchedlitellm.completion— tools set it, no-tools does not, unaffected models are untouched, and an explicit caller value survives.pytest tests/server/llm/→ 719 passed, all 16 new tests among them.Two caveats on my local run, since I would rather state them than let them look like passes:
test_litellm_client.py::test_installed_litellm_transport_round_tripfails on a clean checkout ofmainhere too — pre-existing in my environment, unrelated.test_embedding_service_model_contract.pyfailures vary between runs in my environment (1 of 3 on cleanmain, 3 of 3 with this branch, 0 of 3 in isolation on both). They also collect before the file I touched, so they cannot be affected by these tests. I believe it is local flakiness around the HF model download, but I could not fully rule it out locally — worth a glance at CI.Alternatives considered
/v1/responses, as the error suggests. Correct long-term, but a much larger change than making the completions path work.reasoning_effortas anLLMConfigfield. Useful on its own, but it would leave the default broken — callers would have to know to set it. Happy to add it as well, or instead, if you would prefer that shape.Summary by CodeRabbit