@@ -177,15 +177,17 @@ def _create_event(
177177 actions : Optional [EventActions ] = None ,
178178 long_running_function_ids : Optional [set [str ]] = None ,
179179 partial : bool = False ,
180+ event_metadata : Optional [dict [str , Any ]] = None ,
180181) -> Optional [Event ]:
181182 """Creates an ADK event from parts and metadata."""
182183 event_actions = actions or EventActions ()
183- if not output_parts and not event_actions .model_dump (
184- exclude_none = True , exclude_defaults = True
185- ):
184+ has_actions = bool (
185+ event_actions .model_dump (exclude_none = True , exclude_defaults = True )
186+ )
187+ if not output_parts and not has_actions and not event_metadata :
186188 return None
187189
188- event = Event (
190+ event_kwargs : dict [ str , Any ] = dict (
189191 invocation_id = (
190192 invocation_context .invocation_id
191193 if invocation_context
@@ -208,7 +210,10 @@ def _create_event(
208210 partial = partial ,
209211 )
210212
211- return event
213+ if event_metadata :
214+ event_kwargs .update (event_metadata )
215+
216+ return Event (** event_kwargs )
212217
213218
214219def _parse_adk_metadata_value (value : Any ) -> Any :
@@ -248,6 +253,74 @@ def _extract_event_actions(
248253 return EventActions ()
249254
250255
256+ def _extract_event_metadata (
257+ metadata : Optional [dict [str , Any ]],
258+ ) -> dict [str , Any ]:
259+ """Extracts ADK event metadata fields from A2A metadata.
260+
261+ Restores fields like custom_metadata, usage_metadata, error_code, and
262+ grounding_metadata that were serialized into A2A metadata by the outbound
263+ converter.
264+
265+ Args:
266+ metadata: The A2A metadata dictionary.
267+
268+ Returns:
269+ A dictionary of event keyword arguments to apply to the Event.
270+ """
271+ if not metadata :
272+ return {}
273+
274+ event_kwargs : dict [str , Any ] = {}
275+
276+ # Simple fields that can be restored directly
277+ simple_fields = ["error_code" ]
278+ for field_name in simple_fields :
279+ raw_value = metadata .get (_get_adk_metadata_key (field_name ))
280+ if raw_value is not None :
281+ event_kwargs [field_name ] = _parse_adk_metadata_value (raw_value )
282+
283+ # Dict fields that need parsing
284+ dict_fields = ["custom_metadata" ]
285+ for field_name in dict_fields :
286+ raw_value = metadata .get (_get_adk_metadata_key (field_name ))
287+ if raw_value is not None :
288+ parsed = _parse_adk_metadata_value (raw_value )
289+ if isinstance (parsed , dict ):
290+ event_kwargs [field_name ] = parsed
291+ else :
292+ logger .warning (
293+ "Ignoring invalid ADK %s metadata of type %s" ,
294+ field_name ,
295+ type (parsed ).__name__ ,
296+ )
297+
298+ # Pydantic model fields that need validation
299+ model_fields = {
300+ "usage_metadata" : genai_types .GenerateContentResponseUsageMetadata ,
301+ "grounding_metadata" : genai_types .GroundingMetadata ,
302+ }
303+ for field_name , model_class in model_fields .items ():
304+ raw_value = metadata .get (_get_adk_metadata_key (field_name ))
305+ if raw_value is not None :
306+ parsed = _parse_adk_metadata_value (raw_value )
307+ if isinstance (parsed , dict ):
308+ try :
309+ event_kwargs [field_name ] = model_class (** parsed )
310+ except (ValidationError , TypeError ) as error :
311+ logger .warning (
312+ "Ignoring invalid ADK %s metadata: %s" , field_name , error
313+ )
314+ else :
315+ logger .warning (
316+ "Ignoring invalid ADK %s metadata of type %s" ,
317+ field_name ,
318+ type (parsed ).__name__ ,
319+ )
320+
321+ return event_kwargs
322+
323+
251324def _merge_top_level_dicts (
252325 base : dict [str , Any ], new_values : dict [str , Any ]
253326) -> dict [str , Any ]:
@@ -304,6 +377,7 @@ def convert_a2a_task_to_event(
304377
305378 try :
306379 event_actions = EventActions ()
380+ event_metadata : dict [str , Any ] = {}
307381 output_parts = []
308382 long_running_function_ids = set ()
309383 if a2a_task .artifacts :
@@ -314,6 +388,7 @@ def convert_a2a_task_to_event(
314388 event_actions = _merge_event_actions (
315389 event_actions , _extract_event_actions (artifact .metadata )
316390 )
391+ event_metadata .update (_extract_event_metadata (artifact .metadata ))
317392 output_parts , _ = _convert_a2a_parts_to_adk_parts (
318393 artifact_parts , part_converter
319394 )
@@ -325,6 +400,9 @@ def convert_a2a_task_to_event(
325400 event_actions ,
326401 _extract_event_actions (a2a_task .status .message .metadata ),
327402 )
403+ event_metadata .update (
404+ _extract_event_metadata (a2a_task .status .message .metadata )
405+ )
328406 parts , ids = _convert_a2a_parts_to_adk_parts (
329407 a2a_task .status .message .parts , part_converter
330408 )
@@ -337,6 +415,7 @@ def convert_a2a_task_to_event(
337415 author ,
338416 event_actions ,
339417 long_running_function_ids ,
418+ event_metadata = event_metadata or None ,
340419 )
341420
342421 except Exception as e :
@@ -380,6 +459,7 @@ def convert_a2a_message_to_event(
380459 invocation_context ,
381460 author ,
382461 _extract_event_actions (a2a_message .metadata ),
462+ event_metadata = _extract_event_metadata (a2a_message .metadata ),
383463 )
384464
385465 except Exception as e :
@@ -412,10 +492,15 @@ def convert_a2a_status_update_to_event(
412492 output_parts = []
413493 long_running_function_ids = set ()
414494 event_actions = EventActions ()
495+ event_metadata : Optional [dict [str , Any ]] = None
415496 if a2a_status_update .status .message :
416497 event_actions = _extract_event_actions (
417498 a2a_status_update .status .message .metadata
418499 )
500+ event_metadata = (
501+ _extract_event_metadata (a2a_status_update .status .message .metadata )
502+ or None
503+ )
419504 parts , ids = _convert_a2a_parts_to_adk_parts (
420505 a2a_status_update .status .message .parts , part_converter
421506 )
@@ -428,6 +513,7 @@ def convert_a2a_status_update_to_event(
428513 author ,
429514 event_actions ,
430515 long_running_function_ids ,
516+ event_metadata = event_metadata ,
431517 )
432518 except Exception as e :
433519 logger .error ("Failed to convert A2A status update to event: %s" , e )
@@ -466,6 +552,10 @@ def convert_a2a_artifact_update_to_event(
466552 author ,
467553 _extract_event_actions (a2a_artifact_update .artifact .metadata ),
468554 partial = not a2a_artifact_update .last_chunk ,
555+ event_metadata = _extract_event_metadata (
556+ a2a_artifact_update .artifact .metadata
557+ )
558+ or None ,
469559 )
470560 except Exception as e :
471561 logger .error ("Failed to convert A2A artifact update to event: %s" , e )
0 commit comments