Skip to content

Commit c7757de

Browse files
authored
FIX: GraphFlow serialize/deserialize and adding test (#6434)
## Why are these changes needed? ❗ Before Previously, GraphFlow.__init__() modified the inner_chats and termination_condition for internal execution logic (e.g., constructing _StopAgent or composing OrTerminationCondition). However, these modified values were also used during dump_component(), meaning the serialized config no longer matched the original inputs. As a result: 1. dump_component() → load_component() → dump_component() produced non-idempotent configs. 2. Internal-only constructs like _StopAgent were mistakenly serialized, even though they should only exist in runtime. ⸻ ✅ After This patch changes the behavior to: • Store original inner_chats and termination_condition as-is at initialization. • During to_config(), serialize only the original unmodified versions. • Avoid serializing _StopAgent or other dynamically built agents. • Ensure deserialization (from_config) produces a logically equivalent object without additional nesting or duplication. This ensures that: • GraphFlow.dump_component() → load_component() round-trip produces consistent, minimal configs. • Internal execution logic and serialized component structure are properly separated. <!-- Please give a short summary of the change and the problem this solves. --> ## Related issue number <!-- For example: "Closes #1234" --> Closes #6431 ## Checks - [ ] I've included any doc changes needed for <https://microsoft.github.io/autogen/>. See <https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to build and test documentation locally. - [x] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [x] I've made sure all auto checks have passed.
1 parent 8efa1f1 commit c7757de

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,9 @@ def __init__(
646646
runtime: AgentRuntime | None = None,
647647
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
648648
) -> None:
649+
self._input_participants = participants
650+
self._input_termination_condition = termination_condition
651+
649652
stop_agent = _StopAgent()
650653
stop_agent_termination = StopMessageTermination()
651654
termination_condition = (
@@ -700,8 +703,10 @@ def _factory() -> GraphFlowManager:
700703

701704
def _to_config(self) -> GraphFlowConfig:
702705
"""Converts the instance into a configuration object."""
703-
participants = [participant.dump_component() for participant in self._participants]
704-
termination_condition = self._termination_condition.dump_component() if self._termination_condition else None
706+
participants = [participant.dump_component() for participant in self._input_participants]
707+
termination_condition = (
708+
self._input_termination_condition.dump_component() if self._input_termination_condition else None
709+
)
705710
return GraphFlowConfig(
706711
participants=participants,
707712
termination_condition=termination_condition,

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
)
1414
from autogen_agentchat.base import Response, TaskResult
1515
from autogen_agentchat.conditions import MaxMessageTermination
16-
from autogen_agentchat.messages import BaseChatMessage, ChatMessage, MessageFactory, TextMessage
16+
from autogen_agentchat.messages import BaseChatMessage, ChatMessage, MessageFactory, StopMessage, TextMessage
1717
from autogen_agentchat.messages import BaseTextChatMessage as TextChatMessage
1818
from autogen_agentchat.teams import (
1919
DiGraphBuilder,
@@ -1399,3 +1399,51 @@ async def test_graph_builder_with_filter_agent(runtime: AgentRuntime | None) ->
13991399
result = await team.run(task="Hello")
14001400
assert any(m.source == "X" and m.content == "Hello" for m in result.messages) # type: ignore[union-attr]
14011401
assert result.stop_reason is not None
1402+
1403+
1404+
@pytest.mark.asyncio
1405+
async def test_graph_flow_serialize_deserialize() -> None:
1406+
client_a = ReplayChatCompletionClient(list(map(str, range(10))))
1407+
client_b = ReplayChatCompletionClient(list(map(str, range(10))))
1408+
a = AssistantAgent("A", model_client=client_a)
1409+
b = AssistantAgent("B", model_client=client_b)
1410+
1411+
builder = DiGraphBuilder()
1412+
builder.add_node(a).add_node(b)
1413+
builder.add_edge(a, b)
1414+
builder.set_entry_point(a)
1415+
1416+
team = GraphFlow(
1417+
participants=builder.get_participants(),
1418+
graph=builder.build(),
1419+
runtime=None,
1420+
termination_condition=MaxMessageTermination(5),
1421+
)
1422+
1423+
serialized = team.dump_component()
1424+
deserialized_team = GraphFlow.load_component(serialized)
1425+
serialized_deserialized = deserialized_team.dump_component()
1426+
1427+
results = await team.run(task="Start")
1428+
de_results = await deserialized_team.run(task="Start")
1429+
1430+
assert serialized == serialized_deserialized
1431+
assert results == de_results
1432+
assert results.stop_reason is not None
1433+
assert results.stop_reason == de_results.stop_reason
1434+
assert results.messages == de_results.messages
1435+
assert isinstance(results.messages[0], TextMessage)
1436+
assert results.messages[0].source == "user"
1437+
assert results.messages[0].content == "Start"
1438+
assert isinstance(results.messages[1], TextMessage)
1439+
assert results.messages[1].source == "A"
1440+
assert results.messages[1].content == "0"
1441+
assert isinstance(results.messages[2], TextMessage)
1442+
assert results.messages[2].source == "A"
1443+
assert results.messages[2].content == "1"
1444+
assert isinstance(results.messages[3], TextMessage)
1445+
assert results.messages[3].source == "B"
1446+
assert results.messages[3].content == "0"
1447+
assert isinstance(results.messages[-1], StopMessage)
1448+
assert results.messages[-1].source == _DIGRAPH_STOP_AGENT_NAME
1449+
assert results.messages[-1].content == "Digraph execution is complete"

0 commit comments

Comments
 (0)