mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-27 17:49:22 +00:00
Any tool-using agent on gpt-5.4 or newer fails with a hard 400 on the default
endpoint:
Function tools with reasoning_effort are not supported for gpt-5.5 in
/v1/chat/completions. To use function tools, use /v1/responses or set
reasoning_effort to 'none'.
`_prepare_completion_params` gated `reasoning_effort` behind o1, but the value
still reaches the payload for any model through `params.update(self.additional_params)`,
which bypasses the typed field. Tools are then attached unconditionally.
Probed against the live endpoint rather than inferred from the report:
model tools + 'high' tools + 'none'
gpt-5.6/-sol/... rejected accepted
gpt-5.5 rejected accepted
gpt-5.4/-mini/-nano rejected accepted
gpt-5.2 and earlier accepted accepted
o1 / o3 / o4-mini accepted rejected
The boundary is gpt-5.4, not 5.6. Note the last row: "none" is not a safe blanket
fallback either.
The 400 is the source of truth: catch it, drop reasoning_effort, retry once, and
remember the model so the round trip is paid once per process. The known families
are a fast path only, so OpenAI extending the restriction doesn't need a release
here. Detection matches the structured `param` field plus the message, so the
unsupported-value 400 that o1/o3 return for "none" doesn't trigger a useless retry.
Logged at warning, not debug -- silently downgrading a requested reasoning effort
should be visible.
Composed with the responses-only fallback from #6656 in a single handler in
_call_completions / _acall_completions, covering sync, async, streaming and
non-streaming. Verified both recoveries still work live after rebasing:
gpt-5.5 + tools + reasoning_effort -> tool call returned (was 400)
gpt-5-pro -> 'PONG', learned {'gpt-5-pro'}
Tests: 28 cases covering the fast path, error classification, sync + async retry,
no-retry on unrelated 400s, and a guard against the drop tests passing vacuously
(the typed reasoning_effort field is gated behind is_o1_model, so additional_params
is the path that actually leaks). tests/llms/openai -> 149 passed, 1 skipped.