Skip to content

Commit ee4b7c1

Browse files
seanzhougooglecopybara-github
authored andcommitted
fix: Using base event's invocation id when merge multiple function response event
fix #1531 PiperOrigin-RevId: 795638800
1 parent ba6e85e commit ee4b7c1

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ def merge_parallel_function_response_events(
682682

683683
# Create the new merged event
684684
merged_event = Event(
685-
invocation_id=Event.new_id(),
685+
invocation_id=base_event.invocation_id,
686686
author=base_event.author,
687687
branch=base_event.branch,
688688
content=types.Content(role='user', parts=merged_parts),

tests/unittests/flows/llm_flows/test_functions_simple.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from google.adk.agents.llm_agent import Agent
2020
from google.adk.events.event import Event
2121
from google.adk.flows.llm_flows.functions import find_matching_function_call
22+
from google.adk.flows.llm_flows.functions import merge_parallel_function_response_events
2223
from google.adk.tools.function_tool import FunctionTool
2324
from google.adk.tools.tool_context import ToolContext
2425
from google.genai import types
@@ -931,6 +932,119 @@ async def yielding_async_function() -> dict:
931932
assert execution_order == ['non_yield_A', 'non_yield_B', 'yield_C', 'yield_D']
932933

933934

935+
def test_merge_parallel_function_response_events_preserves_invocation_id():
936+
"""Test that merge_parallel_function_response_events preserves the base event's invocation_id."""
937+
# Create multiple function response events with different invocation IDs
938+
invocation_id = "base_invocation_123"
939+
940+
function_response1 = types.FunctionResponse(
941+
id="func_123", name="test_function1", response={"result": "success1"}
942+
)
943+
944+
function_response2 = types.FunctionResponse(
945+
id="func_456", name="test_function2", response={"result": "success2"}
946+
)
947+
948+
event1 = Event(
949+
invocation_id=invocation_id,
950+
author="test_agent",
951+
content=types.Content(
952+
role="user", parts=[types.Part(function_response=function_response1)]
953+
),
954+
)
955+
956+
event2 = Event(
957+
invocation_id="different_invocation_456", # Different invocation ID
958+
author="test_agent",
959+
content=types.Content(
960+
role="user", parts=[types.Part(function_response=function_response2)]
961+
),
962+
)
963+
964+
# Merge the events
965+
merged_event = merge_parallel_function_response_events([event1, event2])
966+
967+
# Should preserve the base event's (first event's) invocation_id
968+
assert merged_event.invocation_id == invocation_id
969+
assert merged_event.invocation_id != "different_invocation_456"
970+
971+
# Should contain both function responses
972+
assert len(merged_event.content.parts) == 2
973+
974+
# Verify the responses are preserved
975+
response_ids = {part.function_response.id for part in merged_event.content.parts}
976+
assert "func_123" in response_ids
977+
assert "func_456" in response_ids
978+
979+
980+
def test_merge_parallel_function_response_events_single_event():
981+
"""Test that merge_parallel_function_response_events returns single event unchanged."""
982+
invocation_id = "single_invocation_123"
983+
984+
function_response = types.FunctionResponse(
985+
id="func_123", name="test_function", response={"result": "success"}
986+
)
987+
988+
event = Event(
989+
invocation_id=invocation_id,
990+
author="test_agent",
991+
content=types.Content(
992+
role="user", parts=[types.Part(function_response=function_response)]
993+
),
994+
)
995+
996+
# Merge single event
997+
merged_event = merge_parallel_function_response_events([event])
998+
999+
# Should return the same event object
1000+
assert merged_event is event
1001+
assert merged_event.invocation_id == invocation_id
1002+
1003+
1004+
def test_merge_parallel_function_response_events_preserves_other_attributes():
1005+
"""Test that merge_parallel_function_response_events preserves other attributes from base event."""
1006+
invocation_id = "base_invocation_123"
1007+
base_author = "base_agent"
1008+
base_branch = "main_branch"
1009+
1010+
function_response1 = types.FunctionResponse(
1011+
id="func_123", name="test_function1", response={"result": "success1"}
1012+
)
1013+
1014+
function_response2 = types.FunctionResponse(
1015+
id="func_456", name="test_function2", response={"result": "success2"}
1016+
)
1017+
1018+
event1 = Event(
1019+
invocation_id=invocation_id,
1020+
author=base_author,
1021+
branch=base_branch,
1022+
content=types.Content(
1023+
role="user", parts=[types.Part(function_response=function_response1)]
1024+
),
1025+
)
1026+
1027+
event2 = Event(
1028+
invocation_id="different_invocation_456",
1029+
author="different_agent", # Different author
1030+
branch="different_branch", # Different branch
1031+
content=types.Content(
1032+
role="user", parts=[types.Part(function_response=function_response2)]
1033+
),
1034+
)
1035+
1036+
# Merge the events
1037+
merged_event = merge_parallel_function_response_events([event1, event2])
1038+
1039+
# Should preserve base event's attributes
1040+
assert merged_event.invocation_id == invocation_id
1041+
assert merged_event.author == base_author
1042+
assert merged_event.branch == base_branch
1043+
1044+
# Should contain both function responses
1045+
assert len(merged_event.content.parts) == 2
1046+
1047+
9341048
@pytest.mark.asyncio
9351049
async def test_yielding_async_functions_run_concurrently():
9361050
"""Test that async functions with proper yields run concurrently."""

0 commit comments

Comments
 (0)