Skip to content

Commit 8e7d990

Browse files
speedstorm1copybara-github
authored andcommitted
feat: Add MALFORMED_RESPONSE to FinishReason
Java: GenerateContentResponse.text(), parts() and the other helpers that call checkFinishReason() now throw IllegalArgumentException for MALFORMED_RESPONSE, as they already do for MALFORMED_FUNCTION_CALL. Previously the value mapped to FINISH_REASON_UNSPECIFIED and did not throw. fixes #2937 PiperOrigin-RevId: 1003216252
1 parent 0f688a6 commit 8e7d990

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

‎google/genai/tests/types/test_types.py‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import sys
2020
import typing
2121
from typing import Optional, assert_never
22+
import warnings
2223
import PIL.Image
2324
import pydantic
2425
import pytest
@@ -1095,7 +1096,6 @@ def func_under_test(
10951096
assert actual_schema_mldev == expected_schema
10961097

10971098

1098-
10991099
@pytest.mark.skip(
11001100
reason=(
11011101
'AFC is in progress of refactoring, this test is failing python 3.14'
@@ -2768,6 +2768,28 @@ def test_unknown_enum_value_in_nested_dict():
27682768
assert schema.category.value == 'NEW_CATEGORY'
27692769

27702770

2771+
def test_finish_reason_malformed_response():
2772+
"""MALFORMED_RESPONSE from the API parses into a real member, unwarned."""
2773+
with warnings.catch_warnings(record=True) as caught:
2774+
warnings.simplefilter('always')
2775+
response = types.GenerateContentResponse._from_response(
2776+
response={'candidates': [{'finish_reason': 'MALFORMED_RESPONSE'}]},
2777+
kwargs={},
2778+
)
2779+
assert not [w for w in caught if 'is not a valid' in str(w.message)]
2780+
assert 'MALFORMED_RESPONSE' in types.FinishReason.__members__
2781+
assert response.candidates[0].finish_reason in list(types.FinishReason)
2782+
2783+
2784+
def test_finish_reason_malformed_response_case_insensitive():
2785+
"""A lowercase value resolves to the same member without a warning."""
2786+
with warnings.catch_warnings(record=True) as caught:
2787+
warnings.simplefilter('always')
2788+
reason = types.FinishReason('malformed_response')
2789+
assert not [w for w in caught if 'is not a valid' in str(w.message)]
2790+
assert reason is types.FinishReason.MALFORMED_RESPONSE
2791+
2792+
27712793
# Tests that TypedDict types from types.py are compatible with pydantic
27722794
# pydantic requires TypedDict from typing_extensions for Python <3.12
27732795
def test_typed_dict_pydantic_field():
@@ -2969,4 +2991,3 @@ def test_computer_use_types():
29692991
assert c.enable_prompt_injection_detection is True
29702992
assert len(c.disabled_safety_policies) == 2
29712993
assert types.SafetyPolicy.FINANCIAL_TRANSACTIONS in c.disabled_safety_policies
2972-

‎google/genai/types.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ class FinishReason(_common.CaseInSensitiveEnum):
558558
"""Image generation stopped for a reason not otherwise specified."""
559559
CONTINUATION = 'CONTINUATION'
560560
"""Token generation stopped because the response reached the per-request token limit, but generation is not yet complete. The response can be continued by passing the returned `continuation_token` in a subsequent request."""
561+
MALFORMED_RESPONSE = 'MALFORMED_RESPONSE'
562+
"""Token generation stopped because the response was malformed."""
561563

562564

563565
class HarmProbability(_common.CaseInSensitiveEnum):

0 commit comments

Comments
 (0)