From b8a2b6c57080ae29d7a02df7d9fcc2f961d422d2 Mon Sep 17 00:00:00 2001 From: Kevin Qian Date: Thu, 30 Oct 2025 14:26:07 -0700 Subject: [PATCH] fix: include delimiter when matching events from parent nodes in content processor Previously we only do a simple prefix string matching, thus `agent_00` will match with `agent_0` With this new change, we either check directly equality, or must expect seeing `agent_0.`. See added test for branches we now match / skip. TBF `.` is also not a perfect delimiter (I would imagine users might put dot in agent names). We might consider a follow up that bans such agent names. Tested with script in the linked issue (I updated prompt so we see which agent they see from): Before: ``` [agent_8]: 73 [agent_0]: 97 [agent_1]: 73 [agent_5]: 97 [agent_4]: 73 [agent_2]: 73 [agent_3]: 73 [agent_9]: 93 [agent_6]: 73 [agent_7]: 1 [agent_70]: 1 (agent_7) [agent_20]: 73 (agent_2) [agent_30]: 73 (agent_3) [agent_00]: 97 (agent_0) [agent_40]: 73 (agent_4) [agent_80]: 73 (agent_8) [agent_50]: 97 (agent_5) [agent_90]: 93 (agent_9) [agent_10]: 73 (agent_1) [agent_60]: 73 (agent_6) ``` After: ``` [agent_9]: 73 [agent_6]: 73 [agent_2]: 73 [agent_7]: 93 [agent_4]: 73 [agent_1]: 73 [agent_3]: 73 [agent_5]: 97 [agent_0]: 73 [agent_8]: 87 [agent_50]: 0 [agent_80]: 0 [agent_10]: 0 [agent_90]: 0 [agent_30]: 0 [agent_20]: 0 [agent_60]: 0 [agent_00]: 0 [agent_40]: 0 [agent_70]: 0 ``` Closes #2948 Co-authored-by: Kevin Qian PiperOrigin-RevId: 826187198 --- src/google/adk/flows/llm_flows/contents.py | 7 ++++++- .../flows/llm_flows/test_contents_branch.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/google/adk/flows/llm_flows/contents.py b/src/google/adk/flows/llm_flows/contents.py index 899f819a..da4cee94 100644 --- a/src/google/adk/flows/llm_flows/contents.py +++ b/src/google/adk/flows/llm_flows/contents.py @@ -594,7 +594,12 @@ def _is_event_belongs_to_branch( """ if not invocation_branch or not event.branch: return True - return invocation_branch.startswith(event.branch) + # We use dot to delimit branch nodes. To avoid simple prefix match + # (e.g. agent_0 unexpectedly matching agent_00), require either perfect branch + # match, or match prefix with an additional explicit '.' + return invocation_branch == event.branch or invocation_branch.startswith( + f'{event.branch}.' + ) def _is_function_call_event(event: Event, function_name: str) -> bool: diff --git a/tests/unittests/flows/llm_flows/test_contents_branch.py b/tests/unittests/flows/llm_flows/test_contents_branch.py index 736909fb..23473541 100644 --- a/tests/unittests/flows/llm_flows/test_contents_branch.py +++ b/tests/unittests/flows/llm_flows/test_contents_branch.py @@ -58,6 +58,18 @@ async def test_branch_filtering_child_sees_parent(): content=types.ModelContent("Child agent response"), branch="parent_agent.child_agent", # Current branch - should be included ), + Event( + invocation_id="inv4", + author="child_agent", + content=types.ModelContent("Excluded response 1"), + branch="parent_agent.child_agent000", # Prefix match BUT not itself/ancestor - should be excluded + ), + Event( + invocation_id="inv5", + author="child_agent", + content=types.ModelContent("Excluded response 2"), + branch="parent_agent.child", # Prefix match BUT not itself/ancestor - should be excluded + ), ] invocation_context.session.events = events