This commit is contained in:
Rohan Dedhia 2026-11-06 00:07:32 +00:00 • committed by GitHub
commit c7754877cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 125 additions and 2 deletions

View file

@ -57,6 +57,7 @@ class GroqChatConfig(OpenAILikeChatConfig):
response_format: dict | None = None
tools: list | None = None
tool_choice: str | dict | None = None
reasoning_format: str | None = None
def __init__(
self,
@ -73,6 +74,7 @@ class GroqChatConfig(OpenAILikeChatConfig):
response_format: dict | None = None,
tools: list | None = None,
tool_choice: str | dict | None = None,
reasoning_format: str | None = None,
) -> None:
locals_: Final[Mapping[str, object]] = dict(locals())
for key, value in locals_.items():
@ -113,13 +115,49 @@ class GroqChatConfig(OpenAILikeChatConfig):
base_params.remove("web_search_options")
try:
if litellm.supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider):
base_params.append("reasoning_effort")
if self._supports_reasoning(model):
base_params.append("reasoning_format")
if self._model_supports_reasoning_effort(model):
base_params.append("reasoning_effort")
except Exception as e:
verbose_logger.debug("Error checking if model supports reasoning: %s", e)
return base_params
@classmethod
def _model_supports_reasoning_effort(cls, model: str) -> bool:
"""
Check if the model accepts reasoning_effort on Groq.
First consults the model catalog (if an explicit flag like supports_reasoning_effort is present),
and falls back to excluding DeepSeek R1 models which reason unconditionally and reject this parameter.
"""
try:
from litellm.utils import get_model_info
model_info = get_model_info(model=model, custom_llm_provider="groq")
if model_info.get("supports_reasoning_effort") is False:
return False
if model_info.get("supports_reasoning_effort") is True:
return True
except Exception:
pass
return not cls._is_deepseek_r1_model(model)
@staticmethod
def _is_deepseek_r1_model(model: str) -> bool:
clean_model = model.removeprefix("groq/").lower()
return "deepseek-r1" in clean_model
@classmethod
def _supports_reasoning(cls, model: str) -> bool:
clean_model = model.removeprefix("groq/").lower()
if "deepseek-r1" in clean_model or "qwq" in clean_model:
return True
try:
return litellm.supports_reasoning(model=model, custom_llm_provider="groq")
except Exception:
return False
@staticmethod
def _is_compound_model(model: str) -> bool:
return model.removeprefix("groq/") in GROQ_COMPOUND_MODELS
@ -278,6 +316,22 @@ class GroqChatConfig(OpenAILikeChatConfig):
"response_format", None
) # only remove if it's a json_schema - handled via using groq's tool calling params.
# else: model supports native json_schema, let response_format pass through
reasoning_format: Final = non_default_params.pop("reasoning_format", None)
if reasoning_format is not None:
optional_params["reasoning_format"] = reasoning_format
if not self._model_supports_reasoning_effort(model) and "reasoning_effort" in non_default_params:
if drop_params or litellm.drop_params:
verbose_logger.warning(
f"Dropping reasoning_effort={non_default_params['reasoning_effort']} for model={model} because Groq does not support reasoning_effort on this model."
)
non_default_params.pop("reasoning_effort", None)
else:
raise litellm.UnsupportedParamsError(
message=f"reasoning_effort is not supported for {model} on Groq. To drop unsupported params set `litellm.drop_params = True`",
status_code=400,
)
web_search_options: Final = non_default_params.pop("web_search_options", None)
optional_params = super().map_openai_params(non_default_params, optional_params, model, drop_params)
if web_search_options is None:

View file

@ -606,3 +606,72 @@ def test_groq_request_drops_null_assistant_fields_without_touching_the_callers_m
assert body["messages"][1] == {"role": "assistant", "content": "Hello"}
assert messages == messages_before
class TestGroqReasoningParams:
"""Tests for Groq reasoning_effort and reasoning_format handling (Issue #49875)."""
@pytest.mark.parametrize(
"model",
[
"groq/deepseek-r1-distill-llama-70b",
"deepseek-r1-distill-llama-70b",
"groq/qwen/qwen3.8-27b",
"groq/openai/gpt-oss-120b",
],
)
def test_reasoning_format_in_supported_params_for_reasoning_models(self, model: str):
config = GroqChatConfig()
supported = config.get_supported_openai_params(model=model)
assert "reasoning_format" in supported
def test_reasoning_format_not_in_supported_params_for_non_reasoning_models(self):
config = GroqChatConfig()
supported = config.get_supported_openai_params(model="llama-3.3-70b-versatile")
assert "reasoning_format" not in supported
@pytest.mark.parametrize(
"model",
[
"groq/deepseek-r1-distill-llama-70b",
"deepseek-r1-distill-llama-70b",
],
)
def test_reasoning_effort_not_in_supported_params_for_deepseek_r1(self, model: str):
config = GroqChatConfig()
supported = config.get_supported_openai_params(model=model)
assert "reasoning_effort" not in supported
def test_deepseek_r1_reasoning_effort_raises_without_drop_params(self):
config = GroqChatConfig()
with pytest.raises(litellm.UnsupportedParamsError) as exc_info:
config.map_openai_params(
non_default_params={"reasoning_effort": "low"},
optional_params={},
model="groq/deepseek-r1-distill-llama-70b",
drop_params=False,
)
assert "reasoning_effort is not supported" in str(exc_info.value)
def test_deepseek_r1_reasoning_effort_dropped_with_drop_params(self):
config = GroqChatConfig()
optional_params = {}
result = config.map_openai_params(
non_default_params={"reasoning_effort": "low"},
optional_params=optional_params,
model="groq/deepseek-r1-distill-llama-70b",
drop_params=True,
)
assert "reasoning_effort" not in result
@pytest.mark.parametrize("format_value", ["raw", "parsed", "hidden"])
def test_reasoning_format_maps_to_optional_params(self, format_value: str):
config = GroqChatConfig()
optional_params = {}
result = config.map_openai_params(
non_default_params={"reasoning_format": format_value},
optional_params=optional_params,
model="groq/deepseek-r1-distill-llama-70b",
drop_params=False,
)
assert result.get("reasoning_format") == format_value