Skip to content

Commit 0cb9ae9

Browse files
GWealecopybara-github
authored andcommitted
fix(models): treat empty GenerateContentResponse without prompt feedback as successful
Previously, an empty `candidates` list without `prompt_feedback` resulted in an `UNKNOWN_ERROR`. This change updates the logic to handle such cases as a successful completion with no generated content, which is valid for certain model interactions like tool-driven turns. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 916115022
1 parent 0524797 commit 0cb9ae9

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

src/google/adk/models/llm_response.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from __future__ import annotations
1616

17+
import logging
1718
from typing import Any
1819
from typing import Optional
1920

@@ -216,9 +217,15 @@ def create(
216217
model_version=generate_content_response.model_version,
217218
)
218219
else:
220+
# Some model backends can legitimately complete a turn without
221+
# candidates (for example, tool-driven UI turns with no text). Treat
222+
# this as an empty successful response rather than an unknown error.
223+
logging.warning(
224+
'Received empty candidates and no prompt feedback in model '
225+
'response. Treating as a successful empty response.'
226+
)
219227
return LlmResponse(
220-
error_code='UNKNOWN_ERROR',
221-
error_message='Unknown error.',
228+
content=types.Content(role='model', parts=[]),
222229
usage_metadata=usage_metadata,
223230
model_version=generate_content_response.model_version,
224231
)

tests/unittests/models/test_llm_response.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ def test_llm_response_create_no_candidates():
107107
assert response.error_message == 'Prompt blocked for safety'
108108

109109

110+
def test_llm_response_create_no_candidates_without_prompt_feedback():
111+
"""Test LlmResponse.create() for empty successful model responses."""
112+
usage_metadata = types.GenerateContentResponseUsageMetadata(
113+
prompt_token_count=10,
114+
candidates_token_count=0,
115+
total_token_count=10,
116+
)
117+
generate_content_response = types.GenerateContentResponse(
118+
candidates=[],
119+
usage_metadata=usage_metadata,
120+
model_version='gemini-2.5-flash',
121+
)
122+
123+
response = LlmResponse.create(generate_content_response)
124+
125+
assert response.error_code is None
126+
assert response.error_message is None
127+
assert response.finish_reason is None
128+
assert response.content is not None
129+
assert response.content.role == 'model'
130+
assert not response.content.parts
131+
assert response.usage_metadata == usage_metadata
132+
assert response.model_version == 'gemini-2.5-flash'
133+
134+
110135
def test_llm_response_create_with_concrete_logprobs_result():
111136
"""Test LlmResponse.create() with detailed logprobs_result containing actual token data."""
112137
# Create realistic logprobs data

0 commit comments

Comments
 (0)