Skip to content

Commit cdb3ff4

Browse files
vishwa180copybara-github
authored andcommitted
fix: Handle merging lists in deep_merge_dicts
The deep_merge_dicts function will now extend lists when merging dictionaries, instead of overwriting them. Co-authored-by: Vishwa Murugan <vishwamurugan@google.com> PiperOrigin-RevId: 890531331
1 parent 5df03f1 commit cdb3ff4

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/google/adk/flows/llm_flows/functions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,10 +1151,12 @@ def __build_response_event(
11511151

11521152

11531153
def deep_merge_dicts(d1: dict, d2: dict) -> dict:
1154-
"""Recursively merges d2 into d1."""
1154+
"""Recursively merges d2 into d1, extending lists where keys collide."""
11551155
for key, value in d2.items():
11561156
if key in d1 and isinstance(d1[key], dict) and isinstance(value, dict):
11571157
d1[key] = deep_merge_dicts(d1[key], value)
1158+
elif key in d1 and isinstance(d1[key], list) and isinstance(value, list):
1159+
d1[key].extend(value)
11581160
else:
11591161
d1[key] = value
11601162
return d1
@@ -1195,7 +1197,7 @@ def merge_parallel_function_response_events(
11951197
author=base_event.author,
11961198
branch=base_event.branch,
11971199
content=types.Content(role='user', parts=merged_parts),
1198-
actions=merged_actions, # Optionally merge actions if required
1200+
actions=merged_actions, # Aggregated from all parallel events
11991201
)
12001202

12011203
# Use the base_event as the timestamp

tests/unittests/flows/llm_flows/test_functions_simple.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
from google.adk.agents.llm_agent import Agent
2020
from google.adk.events.event import Event
21+
from google.adk.events.event_actions import EventActions
22+
from google.adk.events.ui_widget import UiWidget
2123
from google.adk.flows.llm_flows.functions import find_matching_function_call
2224
from google.adk.flows.llm_flows.functions import handle_function_calls_async
2325
from google.adk.flows.llm_flows.functions import handle_function_calls_live
@@ -1138,6 +1140,45 @@ async def yielding_async() -> dict:
11381140
]
11391141

11401142

1143+
def test_merge_parallel_function_response_events_merges_ui_widgets():
1144+
"""Test that merge_parallel_function_response_events merges render_ui_widgets."""
1145+
invocation_id = 'base_invocation_123'
1146+
1147+
widget1 = UiWidget(
1148+
id='widget_1', provider='mcp', payload={'resource_uri': 'ui://widget1'}
1149+
)
1150+
widget2 = UiWidget(
1151+
id='widget_2', provider='mcp', payload={'resource_uri': 'ui://widget2'}
1152+
)
1153+
widget3 = UiWidget(
1154+
id='widget_3', provider='mcp', payload={'resource_uri': 'ui://widget3'}
1155+
)
1156+
1157+
event1 = Event(
1158+
invocation_id=invocation_id,
1159+
author='test_agent',
1160+
actions=EventActions(render_ui_widgets=[widget1]),
1161+
)
1162+
1163+
event2 = Event(
1164+
invocation_id='different_invocation_456',
1165+
author='different_agent',
1166+
actions=EventActions(render_ui_widgets=[widget2, widget3]),
1167+
)
1168+
1169+
# Merge the events
1170+
merged_event = merge_parallel_function_response_events([event1, event2])
1171+
1172+
# Should contain all ui widgets
1173+
assert merged_event.actions.render_ui_widgets is not None
1174+
assert len(merged_event.actions.render_ui_widgets) == 3
1175+
1176+
widget_ids = {widget.id for widget in merged_event.actions.render_ui_widgets}
1177+
assert 'widget_1' in widget_ids
1178+
assert 'widget_2' in widget_ids
1179+
assert 'widget_3' in widget_ids
1180+
1181+
11411182
@pytest.mark.asyncio
11421183
@pytest.mark.parametrize(
11431184
'handle_function_calls',

0 commit comments

Comments
 (0)