Skip to content

Commit 8846be5

Browse files
xuanyang15copybara-github
authored andcommitted
fix: Prevent LoopAgent from resetting sub-agent state on pause
Related: #3716 Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 901000453
1 parent 48b7a64 commit 8846be5

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

src/google/adk/agents/loop_agent.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ async def _run_async_impl(
108108
if should_exit or pause_invocation:
109109
break # break inner for loop
110110

111-
# Restart from the beginning of the loop.
112-
start_index = 0
113-
times_looped += 1
114-
# Reset the state of all sub-agents in the loop.
115-
ctx.reset_sub_agent_states(self.name)
111+
if not pause_invocation:
112+
# Restart from the beginning of the loop.
113+
start_index = 0
114+
times_looped += 1
115+
# Reset the state of all sub-agents in the loop.
116+
ctx.reset_sub_agent_states(self.name)
116117

117118
# If the invocation is paused, we should not yield the end of agent event.
118119
if pause_invocation:

tests/unittests/agents/test_loop_agent.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Testings for the SequentialAgent."""
1616

1717
from typing import AsyncGenerator
18+
from unittest.mock import patch
1819

1920
from google.adk.agents.base_agent import BaseAgent
2021
from google.adk.agents.invocation_context import InvocationContext
@@ -249,3 +250,38 @@ async def test_run_async_with_escalate_action(
249250
),
250251
]
251252
assert simplified_events == expected_events
253+
254+
255+
@pytest.mark.asyncio
256+
async def test_run_async_with_pause_preserves_sub_agent_state(
257+
request: pytest.FixtureRequest,
258+
):
259+
"""Test that the sub-agent state is preserved when the loop agent pauses."""
260+
agent = _TestingAgent(name=f'{request.function.__name__}_test_agent')
261+
loop_agent = LoopAgent(
262+
name=f'{request.function.__name__}_test_loop_agent',
263+
max_iterations=2,
264+
sub_agents=[agent],
265+
)
266+
parent_ctx = await _create_parent_invocation_context(
267+
request.function.__name__, loop_agent, resumable=True
268+
)
269+
270+
# Set some dummy state for the sub-agent
271+
parent_ctx.agent_states[agent.name] = {'some_key': 'some_value'}
272+
273+
# Mock should_pause_invocation to return True for the agent's event
274+
def mock_should_pause(event):
275+
return event.author == agent.name
276+
277+
with patch.object(
278+
InvocationContext,
279+
'should_pause_invocation',
280+
side_effect=mock_should_pause,
281+
):
282+
async for _ in loop_agent.run_async(parent_ctx):
283+
pass # Consume the async generator
284+
285+
# Verify that the sub-agent state was NOT reset
286+
assert agent.name in parent_ctx.agent_states
287+
assert parent_ctx.agent_states[agent.name] == {'some_key': 'some_value'}

0 commit comments

Comments
 (0)