Skip to content

Commit fe595fd

Browse files
fix: prevent state_delta overwrite on function_response-only events
When skip_summarization is True and an event only contains function_response parts (no text), __maybe_save_output_to_state would join zero text parts into an empty string and overwrite the state_delta value already set by after_tool_callback. Skip writing to state_delta when result is empty and no output_schema is configured. Fixes #3178
1 parent 1206add commit fe595fd

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/google/adk/agents/llm_agent.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,12 @@ def __maybe_save_output_to_state(self, event: Event):
841841
result = self.output_schema.model_validate_json(result).model_dump(
842842
exclude_none=True
843843
)
844+
elif not result:
845+
# No text parts found and no output_schema. Skip to avoid
846+
# overwriting state_delta values already set by callbacks
847+
# (e.g. after_tool_callback with skip_summarization on
848+
# function_response-only events).
849+
return
844850
event.actions.state_delta[self.output_key] = result
845851

846852
@model_validator(mode='after')

tests/unittests/agents/test_llm_agent_output_save.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,34 @@ def test_maybe_save_output_to_state_handles_empty_final_chunk_with_schema(
276276
# ASSERT: Because the method should return early, the state_delta
277277
# should remain empty.
278278
assert len(event.actions.state_delta) == 0
279+
280+
def test_maybe_save_output_to_state_skips_function_response_only_event(self):
281+
"""Test that state_delta set by callback is not overwritten when event
282+
only has function_response parts and no text."""
283+
agent = LlmAgent(name="test_agent", output_key="result")
284+
285+
# Simulate a function_response-only event (no text parts)
286+
parts = [
287+
types.Part(
288+
function_response=types.FunctionResponse(
289+
name="my_tool",
290+
response={"status": "success", "data": [1, 2, 3]},
291+
)
292+
)
293+
]
294+
content = types.Content(role="user", parts=parts)
295+
296+
event = Event(
297+
invocation_id="test_invocation",
298+
author="test_agent",
299+
content=content,
300+
actions=EventActions(
301+
skip_summarization=True,
302+
state_delta={"result": [1, 2, 3]},
303+
),
304+
)
305+
306+
agent._LlmAgent__maybe_save_output_to_state(event)
307+
308+
# The callback-set value should be preserved, not overwritten with ""
309+
assert event.actions.state_delta["result"] == [1, 2, 3]

0 commit comments

Comments
 (0)