Skip to content

Commit 2d61cb6

Browse files
voidborne-dcopybara-github
authored andcommitted
fix: preserve empty-string text parts in A2A converter
Merge #5343 ## Summary Fixes #5341 — `convert_genai_part_to_a2a_part()` drops `Part(text='')` because the truthiness check `if part.text:` treats empty strings as falsy. ## Root Cause `Part(text='')` is valid and is produced in at least two places in the ADK: 1. **`code_executors/code_execution_utils.py`** — when code execution completes with `None` output 2. **`models/interactions_utils.py`** — when the Interactions API returns `None` text content Gemini 2.5 Flash (thinking mode) also emits empty text parts. When the converter drops all parts the A2A message ends up with zero parts and the client sees "broken thinking" with no content. ## Fix Change line 182 from `if part.text:` to `if part.text is not None:` so that empty strings are correctly wrapped as `TextPart` while `None` is still skipped. ## Test Added `test_convert_empty_text_part` — verifies that `Part(text='')` produces a valid `TextPart(text='')` instead of returning `None`. COPYBARA_INTEGRATE_REVIEW=#5343 from voidborne-d:fix/part-converter-empty-text dbb2f20 PiperOrigin-RevId: 905370961
1 parent 784350d commit 2d61cb6

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

src/google/adk/a2a/converters/part_converter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def convert_genai_part_to_a2a_part(
179179
) -> Optional[a2a_types.Part]:
180180
"""Convert a Google GenAI Part to an A2A Part."""
181181

182-
if part.text:
182+
if part.text is not None:
183183
a2a_part = a2a_types.TextPart(text=part.text)
184184
if part.thought is not None:
185185
a2a_part.metadata = {_get_adk_metadata_key('thought'): part.thought}

tests/unittests/a2a/converters/test_part_converter.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,23 @@ def test_convert_text_part_with_thought(self):
297297
assert result.root.metadata is not None
298298
assert result.root.metadata[_get_adk_metadata_key("thought")]
299299

300+
def test_convert_empty_text_part(self):
301+
"""Test that Part(text='') is preserved, not dropped.
302+
303+
Regression test for #5341: empty-string text parts are valid and
304+
must not fall through to the unsupported-part warning.
305+
"""
306+
# Arrange
307+
genai_part = genai_types.Part(text="")
308+
309+
# Act
310+
result = convert_genai_part_to_a2a_part(genai_part)
311+
312+
# Assert — should produce a valid TextPart, not None
313+
assert result is not None
314+
assert isinstance(result.root, a2a_types.TextPart)
315+
assert result.root.text == ""
316+
300317
def test_convert_file_data_part(self):
301318
"""Test conversion of GenAI file_data Part to A2A Part."""
302319
# Arrange

0 commit comments

Comments
 (0)