Description
convert_genai_part_to_a2a_part() in src/google/adk/a2a/converters/part_converter.py uses a truthiness check on part.text:
if part.text: # line 182
a2a_part = a2a_types.TextPart(text=part.text)
...
In Python, '' (empty string) is falsy, so a Part(text='') falls through this check and every subsequent type check (file_data, inline_data, function_call, etc.), reaching the catch-all warning at line 298:
Cannot convert unsupported part for Google GenAI part: media_resolution=None code_execution_result=None executable_code=None file_data=None function_call=None function_response=None inline_data=None text='' thought=None thought_signature=None video_metadata=None tool_call=None tool_response=None part_metadata=None
The converter returns None, the part is dropped, and when all parts in a response are empty the A2A message ends up with zero parts — the client sees "broken thinking" with no actual response.
Root Cause
Part(text='') is produced in at least two places in the ADK itself:
-
code_executors/code_execution_utils.py — when code execution completes with None output:
content.parts[-1] = types.Part(text='')
-
models/interactions_utils.py — when the Interactions API returns a text output with None content:
return types.Part.from_text(text=output.text or '')
Gemini 2.5 Flash (thinking model) also appears to produce Part(text='') in some thinking-mode responses.
Proposed Fix
Change line 182 from:
to:
if part.text is not None:
This preserves the existing behavior for text=None (skip) while correctly handling text='' as a valid text part.
Impact
This affects any A2A integration using a thinking model (e.g., Gemini 2.5 Flash/Pro) where the model occasionally returns empty text parts. The user experience is a "broken thinking" indicator with no response content.
Workaround
We implemented an after_model_callback plugin that strips Part(text='') entries before they reach the converter and returns a fallback message when all parts are empty. This prevents the broken state but cannot transparently retry the model call since the ADK plugin API doesn't support re-invocation from after_model_callback.
Environment
google-adk installed from PyPI (version in use with Python 3.12/3.13)
- Model:
gemini-2.5-flash
- Transport: A2A protocol (JSON-RPC / SSE)
Description
convert_genai_part_to_a2a_part()insrc/google/adk/a2a/converters/part_converter.pyuses a truthiness check onpart.text:In Python,
''(empty string) is falsy, so aPart(text='')falls through this check and every subsequent type check (file_data,inline_data,function_call, etc.), reaching the catch-all warning at line 298:The converter returns
None, the part is dropped, and when all parts in a response are empty the A2A message ends up with zero parts — the client sees "broken thinking" with no actual response.Root Cause
Part(text='')is produced in at least two places in the ADK itself:code_executors/code_execution_utils.py— when code execution completes withNoneoutput:models/interactions_utils.py— when the Interactions API returns a text output withNonecontent:Gemini 2.5 Flash (thinking model) also appears to produce
Part(text='')in some thinking-mode responses.Proposed Fix
Change line 182 from:
to:
This preserves the existing behavior for
text=None(skip) while correctly handlingtext=''as a valid text part.Impact
This affects any A2A integration using a thinking model (e.g., Gemini 2.5 Flash/Pro) where the model occasionally returns empty text parts. The user experience is a "broken thinking" indicator with no response content.
Workaround
We implemented an
after_model_callbackplugin that stripsPart(text='')entries before they reach the converter and returns a fallback message when all parts are empty. This prevents the broken state but cannot transparently retry the model call since the ADK plugin API doesn't support re-invocation fromafter_model_callback.Environment
google-adkinstalled from PyPI (version in use with Python 3.12/3.13)gemini-2.5-flash