feat(ollama): pass think=false to custom providers when reasoning_effort is none

When a custom/Ollama provider is used and reasoning_effort is set to 'none'
(or enabled: false), inject 'think': false into the request extra_body.

Ollama does not recognise the OpenRouter-style 'reasoning' extra_body field,
so thinking-capable models (Qwen3, etc.) generate <think> blocks regardless
of the reasoning_effort setting. This produces empty-response errors that
corrupt session state.

The fix adds a provider-specific block in _build_api_kwargs() that sets
think=false in extra_body whenever self.provider == 'custom' and reasoning
is explicitly disabled.

Closes #3191
This commit is contained in:
Mibayy
2026-03-26 12:10:27 +00:00
committed by Teknium
parent 8011aa31ba
commit 3522a7aa13
2 changed files with 53 additions and 0 deletions

View File

@@ -6688,6 +6688,18 @@ class AIAgent:
options["num_ctx"] = self._ollama_num_ctx
extra_body["options"] = options
# Ollama / custom provider: pass think=false when reasoning is disabled.
# Ollama does not recognise the OpenRouter-style `reasoning` extra_body
# field, so we use its native `think` parameter instead.
# This prevents thinking-capable models (Qwen3, etc.) from generating
# <think> blocks and producing empty-response errors when the user has
# set reasoning_effort: none.
if self.provider == "custom" and self.reasoning_config and isinstance(self.reasoning_config, dict):
_effort = (self.reasoning_config.get("effort") or "").strip().lower()
_enabled = self.reasoning_config.get("enabled", True)
if _effort == "none" or _enabled is False:
extra_body["think"] = False
if self._is_qwen_portal():
extra_body["vl_high_resolution_images"] = True

View File

@@ -928,6 +928,7 @@ class TestBuildApiKwargs:
kwargs = agent._build_api_kwargs(messages)
assert kwargs["max_tokens"] == 4096
def test_qwen_portal_formats_messages_and_metadata(self, agent):
agent.base_url = "https://portal.qwen.ai/v1"
agent._base_url_lower = agent.base_url.lower()
@@ -983,6 +984,46 @@ class TestBuildApiKwargs:
messages = [{"role": "system", "content": "sys"}, {"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert kwargs["max_tokens"] == 65536
=======
def test_ollama_think_false_on_effort_none(self, agent):
"""Custom (Ollama) provider with effort=none should inject think=false."""
agent.provider = "custom"
agent.base_url = "http://localhost:11434/v1"
agent._base_url_lower = agent.base_url.lower()
agent.reasoning_config = {"effort": "none"}
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert kwargs.get("extra_body", {}).get("think") is False
def test_ollama_think_false_on_enabled_false(self, agent):
"""Custom (Ollama) provider with enabled=false should inject think=false."""
agent.provider = "custom"
agent.base_url = "http://localhost:11434/v1"
agent._base_url_lower = agent.base_url.lower()
agent.reasoning_config = {"enabled": False}
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert kwargs.get("extra_body", {}).get("think") is False
def test_ollama_no_think_param_when_reasoning_enabled(self, agent):
"""Custom provider with reasoning enabled should NOT inject think=false."""
agent.provider = "custom"
agent.base_url = "http://localhost:11434/v1"
agent._base_url_lower = agent.base_url.lower()
agent.reasoning_config = {"enabled": True, "effort": "medium"}
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert kwargs.get("extra_body", {}).get("think") is None
def test_non_custom_provider_unaffected(self, agent):
"""OpenRouter provider with effort=none should NOT inject think=false."""
agent.provider = "openrouter"
agent.model = "qwen/qwen3.5-plus-02-15"
agent.reasoning_config = {"effort": "none"}
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
assert kwargs.get("extra_body", {}).get("think") is None
class TestBuildAssistantMessage: