diff --git a/litellm/llms/gigachat/chat/transformation.py b/litellm/llms/gigachat/chat/transformation.py index c047dc0c881..b8738a9541d 100644 --- a/litellm/llms/gigachat/chat/transformation.py +++ b/litellm/llms/gigachat/chat/transformation.py @@ -142,7 +142,6 @@ class GigaChatConfig(BaseConfig): "top_p", "max_tokens", "max_completion_tokens", - "stop", "tools", "tool_choice", "functions", @@ -171,9 +170,6 @@ class GigaChatConfig(BaseConfig): optional_params["top_p"] = value elif param in ("max_tokens", "max_completion_tokens"): optional_params["max_tokens"] = value - elif param == "stop": - # GigaChat doesn't support stop sequences - pass elif param == "tools": # Convert tools to functions format if isinstance(value, Sequence): @@ -212,6 +208,21 @@ class GigaChatConfig(BaseConfig): ] optional_params["function_call"] = {"name": schema_name} # mutable-ok: request payload optional_params["_structured_output"] = True + elif not (isinstance(value, Mapping) and (value.get("type") in (None, "text", "json_schema"))): + # Only json_schema is actually mapped above; other response_format + # values (e.g. json_object) would otherwise be silently ignored. + if not drop_params: + from litellm.utils import UnsupportedParamsError + + raise UnsupportedParamsError( + status_code=400, + message=( + "GigaChat does not support response_format=" + f"{value!r}. Use response_format={{'type': 'json_schema', " + "'json_schema': {...}}} instead, or set `drop_params=True` " + "to drop it." + ), + ) return optional_params diff --git a/tests/unit/llms/gigachat/chat/test_gigachat_chat_transformation.py b/tests/unit/llms/gigachat/chat/test_gigachat_chat_transformation.py index b1307f56336..26f13472ebb 100644 --- a/tests/unit/llms/gigachat/chat/test_gigachat_chat_transformation.py +++ b/tests/unit/llms/gigachat/chat/test_gigachat_chat_transformation.py @@ -19,6 +19,7 @@ from litellm.llms.gigachat.chat.transformation import ( is_valid_json, ) from litellm.types.utils import ModelResponse, Usage +from litellm.utils import UnsupportedParamsError, get_optional_params TRANSFORM_MODULE = "litellm.llms.gigachat.chat.transformation" @@ -174,7 +175,6 @@ class TestGetSupportedOpenAiParams: "top_p", "max_tokens", "max_completion_tokens", - "stop", "tools", "tool_choice", "functions", @@ -243,12 +243,30 @@ class TestMapOpenAiParams: ) assert result["max_tokens"] == 200 - def test_stop_is_dropped(self): - result = self.config.map_openai_params( - non_default_params={"stop": ["\n\n"]}, - optional_params={}, - model="GigaChat", - drop_params=False, + def test_stop_not_declared_supported(self): + params = self.config.get_supported_openai_params("GigaChat") + assert "stop" not in params + + def test_stop_raises_unsupported_params_error(self): + # stop is not supported by the GigaChat API; with drop_params=False + # (the default) litellm must surface that instead of silently ignoring it + with pytest.raises(UnsupportedParamsError): + get_optional_params( + model="GigaChat-Pro", + custom_llm_provider="gigachat", + stop=["\n\n"], + request_timeout=10, + num_retries=0, + ) + + def test_stop_dropped_with_drop_params_true(self): + result = get_optional_params( + model="GigaChat-Pro", + custom_llm_provider="gigachat", + stop=["\n\n"], + request_timeout=10, + num_retries=0, + drop_params=True, ) assert "stop" not in result @@ -354,6 +372,35 @@ class TestMapOpenAiParams: assert result["function_call"] == {"name": "test_schema"} assert result["_structured_output"] is True + def test_response_format_json_object_raises_unsupported(self): + with pytest.raises(UnsupportedParamsError): + self.config.map_openai_params( + non_default_params={"response_format": {"type": "json_object"}}, + optional_params={}, + model="GigaChat", + drop_params=False, + ) + + def test_response_format_json_object_dropped_with_drop_params(self): + result = self.config.map_openai_params( + non_default_params={"response_format": {"type": "json_object"}}, + optional_params={}, + model="GigaChat", + drop_params=True, + ) + assert "functions" not in result + assert "function_call" not in result + + def test_response_format_text_is_a_noop(self): + result = self.config.map_openai_params( + non_default_params={"response_format": {"type": "text"}}, + optional_params={}, + model="GigaChat", + drop_params=False, + ) + assert "functions" not in result + assert "function_call" not in result + class TestConvertToolsToFunctions: def setup_method(self):