feat(config): accept STRIX_REASONING_EFFORT=max for providers that support it (#956)

Co-authored-by: Ahmed Allam <allam@usestrix.com>
This commit is contained in:
devin-ai-integration[bot]
2026-08-01 17:10:01 -07:00
committed by GitHub
co-authored by Ahmed Allam
parent 22d668d538
commit 2e7040240d
6 changed files with 39 additions and 9 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ Configure Strix using environment variables or a config file.
</ParamField> </ParamField>
<ParamField path="STRIX_REASONING_EFFORT" default="high" type="string"> <ParamField path="STRIX_REASONING_EFFORT" default="high" type="string">
Control thinking effort for reasoning models. Valid values: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. Defaults to `medium` for quick scan mode. Control thinking effort for reasoning models. Valid values: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Defaults to `medium` for quick scan mode.
</ParamField> </ParamField>
<ParamField path="STRIX_MEMORY_COMPRESSOR_TIMEOUT" default="30" type="integer"> <ParamField path="STRIX_MEMORY_COMPRESSOR_TIMEOUT" default="30" type="integer">
+7 -4
View File
@@ -83,10 +83,13 @@ class _CodexResponsesModel(OpenAIResponsesModel):
effort = self._reasoning_effort effort = self._reasoning_effort
if effort and effort != "none": if effort and effort != "none":
# Clamp to efforts the backend accepts. # Clamp to efforts the backend accepts.
if effort == "minimal": match effort:
effort = "low" case "minimal":
elif effort == "xhigh": effort = "low"
effort = "high" case "xhigh" | "max":
effort = "high"
case _:
pass
overrides = overrides.resolve(ModelSettings(reasoning=Reasoning(effort=effort))) overrides = overrides.resolve(ModelSettings(reasoning=Reasoning(effort=effort)))
return model_settings.resolve(overrides) return model_settings.resolve(overrides)
+1 -1
View File
@@ -8,7 +8,7 @@ from pydantic import AliasChoices, Field
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
ReasoningEffort = Literal["none", "minimal", "low", "medium", "high", "xhigh"] ReasoningEffort = Literal["none", "minimal", "low", "medium", "high", "xhigh", "max"]
_BASE_CONFIG = SettingsConfigDict( _BASE_CONFIG = SettingsConfigDict(
case_sensitive=False, case_sensitive=False,
+17 -1
View File
@@ -147,7 +147,7 @@ def make_model_settings(
and model_supports_reasoning(model_name) and model_supports_reasoning(model_name)
): ):
model_settings = model_settings.resolve( model_settings = model_settings.resolve(
ModelSettings(reasoning=Reasoning(effort=reasoning_effort)), _reasoning_settings(reasoning_effort, model_settings.extra_args),
) )
if force_required_tool_choice and _accepts_required_tool_choice(model_name): if force_required_tool_choice and _accepts_required_tool_choice(model_name):
model_settings = model_settings.resolve(ModelSettings(tool_choice="required")) model_settings = model_settings.resolve(ModelSettings(tool_choice="required"))
@@ -162,6 +162,22 @@ def make_model_settings(
return model_settings return model_settings
def _reasoning_settings(
effort: ReasoningEffort,
extra_args: dict[str, Any] | None,
) -> ModelSettings:
"""``max`` is not in the OpenAI SDK's ``Reasoning.effort`` enum, so send it as
a raw body field instead — also keeping it clear of LiteLLM's DeepSeek mapping,
which collapses every ``reasoning_effort`` level to plain thinking-enabled.
Providers that don't support ``max`` reject the request.
"""
if effort != "max":
return ModelSettings(reasoning=Reasoning(effort=effort))
return ModelSettings(
extra_args={**(extra_args or {}), "extra_body": {"reasoning_effort": "max"}},
)
def _prompt_cache_extra_args(model_name: str) -> dict[str, Any] | None: def _prompt_cache_extra_args(model_name: str) -> dict[str, Any] | None:
"""LiteLLM ``cache_control_injection_points`` for Claude prompt caching. """LiteLLM ``cache_control_injection_points`` for Claude prompt caching.
+2 -2
View File
@@ -171,8 +171,8 @@ def validate_environment() -> None:
error_text.append("", style="white") error_text.append("", style="white")
error_text.append("STRIX_REASONING_EFFORT", style="bold cyan") error_text.append("STRIX_REASONING_EFFORT", style="bold cyan")
error_text.append( error_text.append(
" - Reasoning effort level: none, minimal, low, medium, high, xhigh " " - Reasoning effort level: none, minimal, low, medium, high, xhigh, "
"(default: high)\n", "max (default: high)\n",
style="white", style="white",
) )
+11
View File
@@ -129,6 +129,17 @@ def test_prompt_cache_kept_for_non_bedrock_claude_even_if_unmapped(monkeypatch:
] ]
def test_max_reasoning_effort_sent_as_raw_body_field() -> None:
# "max" is absent from the OpenAI SDK's Reasoning enum, and LiteLLM's DeepSeek
# mapping collapses every effort to thinking-enabled, so it has to ride along
# as a raw body field to reach the provider.
settings = make_model_settings(
"max", model_name="deepseek/deepseek-v4-flash", request_timeout=30
)
assert settings.reasoning is None
assert settings.extra_args == {"timeout": 30, "extra_body": {"reasoning_effort": "max"}}
def test_conversation_tail_breakpoint_moves_with_appended_transcript() -> None: def test_conversation_tail_breakpoint_moves_with_appended_transcript() -> None:
# LiteLLM must place the index=-1 cache_control on the last message however # LiteLLM must place the index=-1 cache_control on the last message however
# long the transcript grows. # long the transcript grows.