From 08a148c99ab219c1defe4d593c9e3d60c6a81e4b Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Wed, 15 Apr 2026 12:11:50 +0000 Subject: [PATCH 1/3] fix: preserve empty-string text parts in A2A converter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #5341 --- src/google/adk/a2a/converters/part_converter.py | 2 +- .../a2a/converters/test_part_converter.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/google/adk/a2a/converters/part_converter.py b/src/google/adk/a2a/converters/part_converter.py index ef4a94fd5d..cb7eb688cd 100644 --- a/src/google/adk/a2a/converters/part_converter.py +++ b/src/google/adk/a2a/converters/part_converter.py @@ -179,7 +179,7 @@ def convert_genai_part_to_a2a_part( ) -> Optional[a2a_types.Part]: """Convert a Google GenAI Part to an A2A Part.""" - if part.text: + if part.text is not None: a2a_part = a2a_types.TextPart(text=part.text) if part.thought is not None: a2a_part.metadata = {_get_adk_metadata_key('thought'): part.thought} diff --git a/tests/unittests/a2a/converters/test_part_converter.py b/tests/unittests/a2a/converters/test_part_converter.py index 446e118534..f921b7e061 100644 --- a/tests/unittests/a2a/converters/test_part_converter.py +++ b/tests/unittests/a2a/converters/test_part_converter.py @@ -297,6 +297,23 @@ def test_convert_text_part_with_thought(self): assert result.root.metadata is not None assert result.root.metadata[_get_adk_metadata_key("thought")] + def test_convert_empty_text_part(self): + """Test that Part(text='') is preserved, not dropped. + + Regression test for #5341: empty-string text parts are valid and + must not fall through to the unsupported-part warning. + """ + # Arrange + genai_part = genai_types.Part(text="") + + # Act + result = convert_genai_part_to_a2a_part(genai_part) + + # Assert — should produce a valid TextPart, not None + assert result is not None + assert isinstance(result.root, a2a_types.TextPart) + assert result.root.text == "" + def test_convert_file_data_part(self): """Test conversion of GenAI file_data Part to A2A Part.""" # Arrange From ae61e3d5d4bcc5207ddee4b8ef6287d6ddffc073 Mon Sep 17 00:00:00 2001 From: voidborne-d Date: Tue, 21 Apr 2026 03:08:04 +0000 Subject: [PATCH 2/3] style: run autoformat.sh on test file --- tests/unittests/a2a/converters/test_part_converter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unittests/a2a/converters/test_part_converter.py b/tests/unittests/a2a/converters/test_part_converter.py index f921b7e061..203c7ac247 100644 --- a/tests/unittests/a2a/converters/test_part_converter.py +++ b/tests/unittests/a2a/converters/test_part_converter.py @@ -943,9 +943,9 @@ def test_a2a_function_call_with_thought_signature_to_genai(self): _get_adk_metadata_key( A2A_DATA_PART_METADATA_TYPE_KEY ): A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL, - _get_adk_metadata_key("thought_signature"): ( - base64.b64encode(b"restored_signature").decode("utf-8") - ), + _get_adk_metadata_key("thought_signature"): base64.b64encode( + b"restored_signature" + ).decode("utf-8"), }, ) ) From d9a7b943f911ee48329e1b1ff7ae47579c3283f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?d=20=F0=9F=94=B9?= Date: Fri, 24 Apr 2026 02:51:44 +0800 Subject: [PATCH 3/3] style: apply pyink formatting to thought_signature literal Addresses pyink-check failure flagged by @DeanChensj on PR #5343. --- tests/unittests/a2a/converters/test_part_converter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unittests/a2a/converters/test_part_converter.py b/tests/unittests/a2a/converters/test_part_converter.py index 203c7ac247..f921b7e061 100644 --- a/tests/unittests/a2a/converters/test_part_converter.py +++ b/tests/unittests/a2a/converters/test_part_converter.py @@ -943,9 +943,9 @@ def test_a2a_function_call_with_thought_signature_to_genai(self): _get_adk_metadata_key( A2A_DATA_PART_METADATA_TYPE_KEY ): A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL, - _get_adk_metadata_key("thought_signature"): base64.b64encode( - b"restored_signature" - ).decode("utf-8"), + _get_adk_metadata_key("thought_signature"): ( + base64.b64encode(b"restored_signature").decode("utf-8") + ), }, ) )