mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
Merge 64b00d8190 into 58896e2009
This commit is contained in:
commit
c7754877cc
2 changed files with 125 additions and 2 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue