Skip to content

Commit 54344ed

Browse files
DeanChensjcopybara-github
authored andcommitted
fix(agents): skip output_key processing on intermediate conversational text in task-mode LlmAgent
Task-mode LlmAgents produce intermediate conversational text responses (such as clarification questions or greetings) before completing their task via finish_task. When output_key and output_schema were configured on a task-mode agent, ADK attempted to validate intermediate conversational text against output_schema during state_delta processing, causing a ValidationError crash on non-JSON text. - Skip output_key state_delta processing on intermediate text responses for task-mode agents (mode="task") in __maybe_save_output_to_state and _save_output_to_state. - Preserve output_schema validation for non-task agents. - Ensure task-mode finish_task validated output is written to output_key state_delta on task completion. - Add unit tests for task-mode output_key handling. Co-authored-by: Shangjie Chen <deanchen@google.com> PiperOrigin-RevId: 949357458
1 parent d4804e2 commit 54344ed

3 files changed

Lines changed: 40 additions & 0 deletions

File tree

src/google/adk/agents/llm_agent.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,11 @@ def __maybe_save_output_to_state(self, event: Event) -> None:
967967
if not self.output_key:
968968
return
969969

970+
# Task mode agents deliver their final output via finish_task, not intermediate
971+
# conversational text turns. Skip output_key processing on text responses for task mode.
972+
if getattr(self, 'mode', None) == 'task':
973+
return
974+
970975
# Handle text responses
971976
if event.is_final_response() and event.content and event.content.parts:
972977

@@ -1016,6 +1021,7 @@ def __maybe_accumulate_streaming_output(
10161021
"""
10171022
if (
10181023
not self.output_key
1024+
or getattr(self, 'mode', None) == 'task'
10191025
or self.output_schema
10201026
or event.author != self.name
10211027
or event.partial

src/google/adk/workflow/_llm_agent_wrapper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ async def run_llm_agent_as_node(
429429
event.output = pending_fc_args[wrapper_key]
430430
else:
431431
event.output = pending_fc_args
432+
if getattr(agent, 'output_key', None) and event.output is not None:
433+
ctx.actions.state_delta[agent.output_key] = event.output
432434
yield event
433435
return
434436

tests/unittests/agents/test_llm_agent_output_save.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,38 @@ def test_maybe_save_output_to_state_with_output_schema(self):
150150
expected_output = {"message": "Hello", "confidence": 0.95}
151151
assert event.actions.state_delta["result"] == expected_output
152152

153+
def test_maybe_save_output_to_state_task_mode_skips_intermediate_text(self):
154+
"""Test that intermediate conversational text in task mode is skipped for output_key."""
155+
agent = LlmAgent(
156+
name="test_agent",
157+
mode="task",
158+
output_key="result",
159+
output_schema=MockOutputSchema,
160+
)
161+
162+
# Conversational text (not JSON) emitted during clarification
163+
event = create_test_event(
164+
author="test_agent",
165+
content_text="Please describe your data domain.",
166+
)
167+
168+
agent._LlmAgent__maybe_save_output_to_state(event)
169+
170+
# Task mode skips intermediate text events for output_key
171+
assert "result" not in event.actions.state_delta
172+
173+
def test_maybe_accumulate_streaming_output_task_mode_skips(self):
174+
"""Test that streaming accumulation skips task-mode agents."""
175+
agent = LlmAgent(name="test_agent", mode="task", output_key="result")
176+
event = create_test_event(
177+
author="test_agent", content_text="Streaming chunk"
178+
)
179+
180+
accum = agent._LlmAgent__maybe_accumulate_streaming_output(event, "")
181+
182+
assert accum == ""
183+
assert "result" not in event.actions.state_delta
184+
153185
def test_maybe_save_output_to_state_multiple_parts(self):
154186
"""Test that multiple text parts are concatenated."""
155187
agent = LlmAgent(name="test_agent", output_key="result")

0 commit comments

Comments
 (0)