From 8543247c91df4d5ca343fa85d0899304bdffe04f Mon Sep 17 00:00:00 2001 From: JingHao-Leon <102573344+JingHao-Leon@users.noreply.github.com> Date: Tue, 29 Sep 2026 04:03:27 +0800 Subject: [PATCH 1/2] fix(gigachat): surface unsupported stop and json_object response_format instead of silently dropping them get_supported_openai_params declared 'stop' as supported while map_openai_params explicitly discarded it, so stop sequences vanished without error even with drop_params=False. response_format={'type': 'json_object'} had the same problem: declared supported, but only json_schema was mapped. - remove 'stop' from the supported list so get_optional_params raises UnsupportedParamsError by default (explicit drop with drop_params=True, consistent with litellm's contract) - raise UnsupportedParamsError for non-json_schema response_format values (json_object etc.) unless drop_params=True; 'text' stays a no-op - replace the test that locked the silent drop in as expected behavior; add contract tests for both params Fixes #43606 --- litellm/llms/gigachat/chat/transformation.py | 22 +++++-- .../chat/test_gigachat_chat_transformation.py | 61 ++++++++++++++++--- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/litellm/llms/gigachat/chat/transformation.py b/litellm/llms/gigachat/chat/transformation.py index c047dc0c881..e8d9adf909a 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,24 @@ 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): From 8b6321b66c2e0269ad68b0e80c7dce8cf9443d41 Mon Sep 17 00:00:00 2001 From: JingHao-Leon <102573344+JingHao-Leon@users.noreply.github.com> Date: Tue, 29 Sep 2026 04:22:18 +0800 Subject: [PATCH 2/2] style: ruff format transformation.py --- litellm/llms/gigachat/chat/transformation.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/litellm/llms/gigachat/chat/transformation.py b/litellm/llms/gigachat/chat/transformation.py index e8d9adf909a..b8738a9541d 100644 --- a/litellm/llms/gigachat/chat/transformation.py +++ b/litellm/llms/gigachat/chat/transformation.py @@ -208,10 +208,7 @@ 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")) - ): + 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: