[BREAKING] Python: Remove workflow register factory methods. Update tests and samples (#3781)

* Remove workflow register factory methods. Update tests and samples

* Address Copilot feedback
This commit is contained in:
Evan Mattson
2026-02-10 22:16:17 +00:00
committed by GitHub
parent f407f726a7
commit a4c9e43afb
46 changed files with 650 additions and 3660 deletions
@@ -240,12 +240,9 @@ class TestGroupChatBuilder:
builder.build()
def test_build_without_participants_raises_error(self) -> None:
"""Test that constructing without participants raises ValueError."""
with pytest.raises(
ValueError,
match=r"Either participants or participant_factories must be provided\.",
):
GroupChatBuilder()
"""Test that constructing with empty participants raises ValueError."""
with pytest.raises(ValueError):
GroupChatBuilder(participants=[])
def test_duplicate_manager_configuration_raises_error(self) -> None:
"""Test that configuring multiple orchestrator options raises ValueError."""
@@ -775,150 +772,6 @@ def test_group_chat_builder_with_request_info_returns_self():
assert result2 is builder2
# region Participant Factory Tests
def test_group_chat_builder_rejects_empty_participant_factories():
"""Test that GroupChatBuilder rejects empty participant_factories list."""
def selector(state: GroupChatState) -> str:
return list(state.participants.keys())[0]
with pytest.raises(ValueError, match=r"participant_factories cannot be empty"):
GroupChatBuilder(participant_factories=[])
with pytest.raises(
ValueError,
match=r"Either participants or participant_factories must be provided\.",
):
GroupChatBuilder()
def test_group_chat_builder_rejects_mixing_participants_and_factories():
"""Test that passing both participants and participant_factories to the constructor raises an error."""
alpha = StubAgent("alpha", "reply from alpha")
with pytest.raises(ValueError, match="Cannot provide both participants and participant_factories"):
GroupChatBuilder(
participants=[alpha],
participant_factories=[lambda: StubAgent("beta", "reply from beta")],
)
def test_group_chat_builder_rejects_both_factories_and_participants():
"""Test that passing both participant_factories and participants raises an error."""
with pytest.raises(ValueError, match="Cannot provide both participants and participant_factories"):
GroupChatBuilder(
participant_factories=[lambda: StubAgent("alpha", "reply from alpha")],
participants=[StubAgent("beta", "reply from beta")],
)
def test_group_chat_builder_rejects_both_participants_and_factories():
"""Test that passing both participants and participant_factories raises an error."""
with pytest.raises(ValueError, match="Cannot provide both participants and participant_factories"):
GroupChatBuilder(
participants=[StubAgent("alpha", "reply from alpha")],
participant_factories=[lambda: StubAgent("beta", "reply from beta")],
)
async def test_group_chat_with_participant_factories():
"""Test workflow creation using participant_factories."""
call_count = 0
def create_alpha() -> StubAgent:
nonlocal call_count
call_count += 1
return StubAgent("alpha", "reply from alpha")
def create_beta() -> StubAgent:
nonlocal call_count
call_count += 1
return StubAgent("beta", "reply from beta")
selector = make_sequence_selector()
workflow = GroupChatBuilder(
participant_factories=[create_alpha, create_beta],
max_rounds=2,
selection_func=selector,
).build()
# Factories should be called during build
assert call_count == 2
outputs: list[WorkflowEvent] = []
async for event in workflow.run("coordinate task", stream=True):
if event.type == "output":
outputs.append(event)
assert len(outputs) == 1
async def test_group_chat_participant_factories_reusable_builder():
"""Test that the builder can be reused to build multiple workflows with factories."""
call_count = 0
def create_alpha() -> StubAgent:
nonlocal call_count
call_count += 1
return StubAgent("alpha", "reply from alpha")
def create_beta() -> StubAgent:
nonlocal call_count
call_count += 1
return StubAgent("beta", "reply from beta")
selector = make_sequence_selector()
builder = GroupChatBuilder(participant_factories=[create_alpha, create_beta], max_rounds=2, selection_func=selector)
# Build first workflow
wf1 = builder.build()
assert call_count == 2
# Build second workflow
wf2 = builder.build()
assert call_count == 4
# Verify that the two workflows have different agent instances
assert wf1.executors["alpha"] is not wf2.executors["alpha"]
assert wf1.executors["beta"] is not wf2.executors["beta"]
async def test_group_chat_participant_factories_with_checkpointing():
"""Test checkpointing with participant_factories."""
storage = InMemoryCheckpointStorage()
def create_alpha() -> StubAgent:
return StubAgent("alpha", "reply from alpha")
def create_beta() -> StubAgent:
return StubAgent("beta", "reply from beta")
selector = make_sequence_selector()
workflow = GroupChatBuilder(
participant_factories=[create_alpha, create_beta],
checkpoint_storage=storage,
max_rounds=2,
selection_func=selector,
).build()
outputs: list[WorkflowEvent] = []
async for event in workflow.run("checkpoint test", stream=True):
if event.type == "output":
outputs.append(event)
assert outputs, "Should have workflow output"
checkpoints = await storage.list_checkpoints()
assert checkpoints, "Checkpoints should be created during workflow execution"
# endregion
# region Orchestrator Factory Tests
@@ -1129,77 +982,4 @@ def test_group_chat_orchestrator_factory_invalid_return_type():
GroupChatBuilder(participants=[alpha], orchestrator_agent=invalid_factory).build()
def test_group_chat_with_both_participant_and_orchestrator_factories():
"""Test workflow creation using both participant_factories and orchestrator_factory."""
participant_factory_call_count = 0
agent_factory_call_count = 0
def create_alpha() -> StubAgent:
nonlocal participant_factory_call_count
participant_factory_call_count += 1
return StubAgent("alpha", "reply from alpha")
def create_beta() -> StubAgent:
nonlocal participant_factory_call_count
participant_factory_call_count += 1
return StubAgent("beta", "reply from beta")
def agent_factory() -> ChatAgent:
nonlocal agent_factory_call_count
agent_factory_call_count += 1
return cast(ChatAgent, StubManagerAgent())
workflow = GroupChatBuilder(
participant_factories=[create_alpha, create_beta],
orchestrator_agent=agent_factory,
).build()
# All factories should be called during build
assert participant_factory_call_count == 2
assert agent_factory_call_count == 1
# Verify all executors are present in the workflow
assert "alpha" in workflow.executors
assert "beta" in workflow.executors
assert "manager_agent" in workflow.executors
async def test_group_chat_factories_reusable_for_multiple_workflows():
"""Test that both factories are reused correctly for multiple workflow builds."""
participant_factory_call_count = 0
agent_factory_call_count = 0
def create_alpha() -> StubAgent:
nonlocal participant_factory_call_count
participant_factory_call_count += 1
return StubAgent("alpha", "reply from alpha")
def create_beta() -> StubAgent:
nonlocal participant_factory_call_count
participant_factory_call_count += 1
return StubAgent("beta", "reply from beta")
def agent_factory() -> ChatAgent:
nonlocal agent_factory_call_count
agent_factory_call_count += 1
return cast(ChatAgent, StubManagerAgent())
builder = GroupChatBuilder(participant_factories=[create_alpha, create_beta], orchestrator_agent=agent_factory)
# Build first workflow
wf1 = builder.build()
assert participant_factory_call_count == 2
assert agent_factory_call_count == 1
# Build second workflow
wf2 = builder.build()
assert participant_factory_call_count == 4
assert agent_factory_call_count == 2
# Verify that the workflows have different agent and orchestrator instances
assert wf1.executors["alpha"] is not wf2.executors["alpha"]
assert wf1.executors["beta"] is not wf2.executors["beta"]
assert wf1.executors["manager_agent"] is not wf2.executors["manager_agent"]
# endregion