Files
crewAI/lib
João Moura 66ef97c73e
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
fix(llms): send reasoning_effort to every openai reasoning model (#7187)
* fix(llms): send reasoning_effort to every openai reasoning model

The completions path gated the parameter behind
is_o1_model = "o1" in model.lower(), a literal substring test. gpt-5, o3 and
o4-mini contain no "o1", so an explicitly configured effort was dropped and the
model thought at the server default. The request still succeeded, so nothing
surfaced -- one measured extraction ran 6.2s with the setting applied against
149.7s with it dropped.

The gate could not be widened: is_o1_model also drives
supports_function_calling, supports_stop_words and the system->user message
rewrite, so marking gpt-5 as an o1 model would report that it cannot call
tools. The parameter is forwarded unconditionally instead, matching the
responses path, and a model that genuinely does not support it says so in a 400
that is retried once without the key.

Also adds "minimal" to LLM.reasoning_effort, which gpt-5 accepts and the
Literal omitted, so the cheapest setting was unreachable on the typed surface.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(llms): gate reasoning_effort on model shape, not every model

Forwarding to every model made a non-reasoning model pay a rejected request
and a retry on every call. `_supports_reasoning_effort` matches on shape
instead -- the o-series, and GPT generation 5 onwards -- so gpt-4o and gpt-4.1
never send the parameter at all.

Matched by shape rather than by a list of names so a new member of an existing
family works without a release here; gpt-6 and o5 already classify correctly.
The unsupported-parameter retry stays as a safety net for the case the shape
match is wrong for a future family, where it costs nothing when the match is
right.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(llms): honour reasoning_effort on compatible servers and fine-tunes

Review follow-ups. A fine-tune (ft:<base>:...) is judged by its base model.
On an OpenAI-compatible server -- anything whose effective base URL is not
api.openai.com, whether set explicitly, via env, or by a provider subclass --
the model name is the server's namespace and says nothing about support, so an
explicit setting is sent as configured; a 400 naming the parameter, in whatever
words the server uses, is recovered by retrying without it, unless it reads as
a complaint about the value. A model that rejected the parameter is remembered
per (endpoint, model) for the process so the rejected call is paid once, and
the drop is logged as a warning since a configured setting is not being
applied. The Literal also gains "xhigh", the remaining value the SDK accepts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(llms): recover reasoning_effort only on evidence the parameter is unknown

Two review follow-ups. The endpoint check now uses the same base URL precedence
as the client itself, so a `client_params` override selects the server. And a
rejection is recovered only when the message says the field is not one the
server knows -- OpenAI's two shapes plus the common compatible-server wordings
("unknown field", "Extra inputs are not permitted") -- rather than any 400 that
lacks a value-sounding word. A pydantic enum complaint such as "Input should be
'low', 'medium' or 'high'" names the parameter but is about its value, and
surfaces instead of being dropped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(llms): remember a reasoning_effort rejection only after the retry succeeds

Two review points on the reasoning_effort fallback. The rejection was recorded
before the retry ran, so a retry that died for an unrelated reason (a dropped
connection, say) silently stopped sending the configured effort for the rest of
the process even though a call without it had never succeeded; the (endpoint,
model) is now remembered only once the retry returns. And _effective_base_url
accepted only a str override in client_params while the SDK, and
_get_client_params, accept httpx.URL too, so a compatible deployment configured
with a URL object was detected as OpenAI and its rejection keyed under the wrong
endpoint; both forms are normalised to the string the client calls.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 19:14:39 +00:00
..