Skip to content

Commit aad4f63

Browse files
committed
fix: fix self-loop in workflow (microsoft#6677)
1 parent c3754ab commit aad4f63

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_graph/_digraph_group_chat.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ def get_parents(self) -> Dict[str, List[str]]:
112112
parents: Dict[str, List[str]] = {node: [] for node in self.nodes}
113113
for node in self.nodes.values():
114114
for edge in node.edges:
115-
parents[edge.target].append(node.name)
115+
if edge.target != node.name:
116+
parents[edge.target].append(node.name)
116117
return parents
117118

118119
def get_start_nodes(self) -> Set[str]:

python/packages/autogen-agentchat/tests/test_group_chat_graph.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,65 @@ async def test_digraph_group_chat_loop_with_exit_condition_3(runtime: AgentRunti
835835
assert result.messages[-1].source == _DIGRAPH_STOP_AGENT_NAME
836836

837837

838+
@pytest.mark.asyncio
839+
async def test_digraph_group_chat_loop_with_exit_condition_2(runtime: AgentRuntime | None) -> None:
840+
# Agents A and C: Echo Agents
841+
agent_a = _EchoAgent("A", description="Echo agent A")
842+
agent_c = _EchoAgent("C", description="Echo agent C")
843+
844+
# Replay model client for agent B
845+
model_client = ReplayChatCompletionClient(
846+
chat_completions=[
847+
"loop", # First time B will ask to loop
848+
"loop", # Second time B will ask to loop
849+
"exit", # Third time B will say exit
850+
]
851+
)
852+
# Agent B: Assistant Agent using Replay Client
853+
agent_b = AssistantAgent("B", description="Decision agent B", model_client=model_client)
854+
855+
# DiGraph: A → B(self loop) → C (conditional back to A or terminate)
856+
graph = DiGraph(
857+
nodes={
858+
"A": DiGraphNode(name="A", edges=[DiGraphEdge(target="B")]),
859+
"B": DiGraphNode(
860+
name="B", edges=[DiGraphEdge(target="C", condition="exit"), DiGraphEdge(target="B", condition="loop")]
861+
),
862+
"C": DiGraphNode(name="C", edges=[]),
863+
},
864+
default_start_node="A",
865+
)
866+
867+
team = GraphFlow(
868+
participants=[agent_a, agent_b, agent_c],
869+
graph=graph,
870+
runtime=runtime,
871+
termination_condition=MaxMessageTermination(20),
872+
)
873+
874+
# Run
875+
result = await team.run(task="Start")
876+
877+
# Assert message order
878+
expected_sources = [
879+
"user",
880+
"A",
881+
"B", # 1st loop
882+
"B", # 2nd loop
883+
"B",
884+
"C",
885+
_DIGRAPH_STOP_AGENT_NAME,
886+
]
887+
888+
actual_sources = [m.source for m in result.messages]
889+
890+
assert actual_sources == expected_sources
891+
assert result.stop_reason is not None
892+
assert result.messages[-2].source == "C"
893+
assert any(m.content == "exit" for m in result.messages[:-1]) # type: ignore[attr-defined,union-attr]
894+
assert result.messages[-1].source == _DIGRAPH_STOP_AGENT_NAME
895+
896+
838897
@pytest.mark.asyncio
839898
async def test_digraph_group_chat_parallel_join_any_1(runtime: AgentRuntime | None) -> None:
840899
agent_a = _EchoAgent("A", description="Echo agent A")

0 commit comments

Comments
 (0)