Skip to content

Commit 3537416

Browse files
giulio-leonegiulio-leone
authored andcommitted
fix(graph): prevent reset_executor_state from corrupting MultiAgentBase state
GraphNode.reset_executor_state() checked hasattr(self.executor, 'state') but did not verify the state type before overwriting it with AgentState. When the executor is a MultiAgentBase (e.g. a nested Graph), its state is a GraphState, and overwriting it with AgentState corrupts the executor. The __post_init__ method already had the correct guard: hasattr(self.executor.state, 'get') but reset_executor_state() was missing it. This affected two call sites: - _execute_node (when reset_on_revisit is enabled with nested graphs) - deserialize_state (unconditionally resets all nodes on completed runs) Fixes #1775
1 parent fca208b commit 3537416

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

src/strands/multiagent/graph.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def reset_executor_state(self) -> None:
188188
if hasattr(self.executor, "messages"):
189189
self.executor.messages = copy.deepcopy(self._initial_messages)
190190

191-
if hasattr(self.executor, "state"):
191+
if hasattr(self.executor, "state") and hasattr(self.executor.state, "get"):
192192
self.executor.state = AgentState(self._initial_state.get())
193193

194194
# Reset execution status

tests/strands/multiagent/test_graph.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,3 +2405,37 @@ async def stream_async(self, prompt=None, **kwargs):
24052405
assert result.completed_nodes == 2
24062406
assert "custom_node" in result.results
24072407
assert "regular_node" in result.results
2408+
2409+
2410+
@pytest.mark.asyncio
2411+
async def test_reset_executor_state_preserves_graph_state_for_nested_graph():
2412+
"""Verify reset_executor_state does not corrupt MultiAgentBase state.
2413+
2414+
When a GraphNode wraps a MultiAgentBase executor (e.g. a nested Graph),
2415+
reset_executor_state() must not overwrite GraphState with AgentState.
2416+
Regression test for #1775.
2417+
"""
2418+
inner_agent = create_mock_agent("inner", "inner response")
2419+
inner_builder = GraphBuilder()
2420+
inner_builder.add_node(inner_agent, "inner_node")
2421+
inner_builder.set_entry_point("inner_node")
2422+
inner_graph = inner_builder.build()
2423+
2424+
# inner_graph.state is a GraphState, not AgentState
2425+
assert isinstance(inner_graph.state, GraphState)
2426+
2427+
node = GraphNode(node_id="nested", executor=inner_graph)
2428+
2429+
# Simulate a completed execution
2430+
node.execution_status = Status.COMPLETED
2431+
node.result = NodeResult(result=MagicMock(), status=Status.COMPLETED)
2432+
2433+
# Reset should NOT corrupt the nested graph's state
2434+
node.reset_executor_state()
2435+
2436+
# After reset, the executor's state must still be GraphState
2437+
assert isinstance(inner_graph.state, GraphState), (
2438+
"reset_executor_state overwrote GraphState with AgentState"
2439+
)
2440+
assert node.execution_status == Status.PENDING
2441+
assert node.result is None

0 commit comments

Comments
 (0)