-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Parallel tool calls: state_delta list values silently overwritten during merge #5190
Copy link
Copy link
Open
Description
Description
When multiple tool calls run in parallel and each writes to the same state_delta key containing a list value, merge_parallel_function_response_events silently drops all but the last value.
Root Cause
deep_merge_dicts in flows/llm_flows/functions.py (line ~822) only recurses into dict values. Lists hit the else branch and get overwritten:
def deep_merge_dicts(d1: dict, d2: dict) -> dict:
for key, value in d2.items():
if key in d1 and isinstance(d1[key], dict) and isinstance(value, dict):
d1[key] = deep_merge_dicts(d1[key], value)
else:
d1[key] = value # <-- lists are overwritten here
return d1Reproduction
- Create a tool that appends to a list in
tool_context.state:
def my_tool(tool_context, item):
items = tool_context.state.get("items") or []
items = list(items)
items.append(item)
tool_context.state["items"] = items- Have the LLM call this tool multiple times in a single response (parallel execution via
asyncio.gatherinhandle_function_calls_live) - Each parallel call gets its own
ToolContextwith a separatestate_delta - Tool A's delta:
{"state_delta": {"items": ["a"]}} - Tool B's delta:
{"state_delta": {"items": ["b"]}} - After merge:
{"state_delta": {"items": ["b"]}}— item "a" is lost
Impact
Any application that accumulates list state across parallel tool calls loses data. In our case, drafting multiple emails in a single agent turn results in only ~2 out of 10 emails persisting.
Suggested Fix
deep_merge_dicts should concatenate lists instead of overwriting:
def deep_merge_dicts(d1: dict, d2: dict) -> dict:
for key, value in d2.items():
if key in d1 and isinstance(d1[key], dict) and isinstance(value, dict):
d1[key] = deep_merge_dicts(d1[key], value)
elif key in d1 and isinstance(d1[key], list) and isinstance(value, list):
d1[key] = d1[key] + value
else:
d1[key] = value
return d1Environment
google-adk1.18.0- Python 3.12
- Using
DatabaseSessionServicewithLiteLLM+ OpenAI models
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels