From b4c878b76d1a7305ec91b0d20c3f459d97b0cd34 Mon Sep 17 00:00:00 2001 From: Brandon Zarnitz Date: Tue, 5 May 2026 17:24:51 -0400 Subject: [PATCH] fix(llm): forward `thinking` param to LiteLLM completion for all providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `thinking` field was declared on the `LLM` model but never added to the `params` dict in `_prepare_completion_params`, causing it to be silently dropped for OpenRouter, DeepSeek, Ollama, and every other provider that goes through LiteLLM directly. Only the native AnthropicCompletion path included `thinking`. Add `"thinking": self.thinking` alongside `reasoning_effort` in `_prepare_completion_params` so that LLM(model="openrouter/anthropic/…", thinking={...}) propagates the extended-thinking config correctly. Closes #5537 Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/crewai/src/crewai/llm.py | 1 + lib/crewai/tests/test_llm.py | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py index 52e3b0b9f6..23eb749493 100644 --- a/lib/crewai/src/crewai/llm.py +++ b/lib/crewai/src/crewai/llm.py @@ -706,6 +706,7 @@ def _prepare_completion_params( "stream": self.stream, "tools": tools, "reasoning_effort": self.reasoning_effort, + "thinking": self.thinking, **self.additional_params, } diff --git a/lib/crewai/tests/test_llm.py b/lib/crewai/tests/test_llm.py index b4002b8e9a..e33834b6ea 100644 --- a/lib/crewai/tests/test_llm.py +++ b/lib/crewai/tests/test_llm.py @@ -1196,3 +1196,28 @@ async def _ret(*args, **kwargs): assert isinstance(result, list) assert len(result) == 1 assert result[0].function.name == "search" + + +def test_thinking_param_included_in_completion_params(): + """Verify that the `thinking` field is forwarded to litellm completion params. + + Regression test for: https://github.com/crewAIInc/crewAI/issues/5537 + The `thinking` field was defined on LLM but never added to the params dict + built by _prepare_completion_params, causing it to be silently dropped for + OpenRouter (and other non-Anthropic) providers. + """ + thinking_config = {"type": "enabled", "budget_tokens": 5000} + llm = LLM( + model="openrouter/anthropic/claude-sonnet-4-5", + thinking=thinking_config, + is_litellm=True, + ) + + params = llm._prepare_completion_params( + messages=[{"role": "user", "content": "Hello"}] + ) + + assert params.get("thinking") == thinking_config, ( + "The 'thinking' field must be forwarded to the LiteLLM completion params " + "so that OpenRouter and other compatible providers can enable extended thinking." + )