fix: preserve empty-string text parts in A2A converter#5343
fix: preserve empty-string text parts in A2A converter#5343voidborne-d wants to merge 6 commits intogoogle:mainfrom
Conversation
e141980 to
20f7177
Compare
|
Hi @voidborne-d, Thank you for your contribution! We appreciate you taking the time to submit this pull request. Your PR has been received by the team and is currently under review. We will provide feedback as soon as we have an update to share. |
|
Hi @DeanChensj , can you please review this. |
fac8136 to
8b9c374
Compare
Part(text='') is valid — it is produced by code_execution_utils.py when code execution returns None, and by interactions_utils.py when the Interactions API returns None text. Gemini 2.5 Flash thinking mode also emits empty text parts. The truthiness check `if part.text:` treats '' as falsy, causing the converter to skip the part entirely. When all parts in a response are empty the A2A message ends up with zero parts and the client sees "broken thinking" with no content. Change the check to `if part.text is not None:` so that empty strings are correctly wrapped as TextPart while None is still skipped. Add a regression test for the empty-string case. Fixes google#5341
8b9c374 to
ae61e3d
Compare
|
Hi @voidborne-d , could you fix the formatting and lint issue? |
Addresses pyink-check failure flagged by @DeanChensj on PR google#5343.
|
Thanks for the ping @DeanChensj — pushed d9a7b94 applying the pyink reformat (pyink 25.12.0 wanted the implicit-paren grouping on the |
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
|
Thank you @voidborne-d for your contribution! 🎉 Your changes have been successfully imported and merged via Copybara in commit 2d61cb6. Closing this PR as the changes are now in the main branch. |
Summary
Fixes #5341 —
convert_genai_part_to_a2a_part()dropsPart(text='')because the truthiness checkif part.text:treats empty strings as falsy.Root Cause
Part(text='')is valid and is produced in at least two places in the ADK:code_executors/code_execution_utils.py— when code execution completes withNoneoutputmodels/interactions_utils.py— when the Interactions API returnsNonetext contentGemini 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:toif part.text is not None:so that empty strings are correctly wrapped asTextPartwhileNoneis still skipped.Test
Added
test_convert_empty_text_part— verifies thatPart(text='')produces a validTextPart(text='')instead of returningNone.