Skip to content

[BREAKING] Python: Move single-config fluent methods to constructor parameters#3693

Open
moonbox3 wants to merge 1 commit intomicrosoft:mainfrom
moonbox3:3552-implement
Open

[BREAKING] Python: Move single-config fluent methods to constructor parameters#3693
moonbox3 wants to merge 1 commit intomicrosoft:mainfrom
moonbox3:3552-implement

Conversation

@moonbox3
Copy link
Contributor

@moonbox3 moonbox3 commented Feb 5, 2026

Motivation and Context

  • Migrates 14 fluent methods across 6 builders to constructor parameters
  • Removes fluent methods entirely to avoid duplicate configuration paths
  • Updates all samples and tests to use new constructor syntax

Breaking Changes

An (simple, omitting some config) example of a change:

# Before (no longer works):
builder = SequentialBuilder().with_checkpointing(storage).with_intermediate_outputs().build()

# After:
builder = SequentialBuilder(checkpoint_storage=storage, intermediate_outputs=True).build()

Methods removed (in favor of constructor arguments):

  • WorkflowBuilder: set_start_executor(), with_checkpointing(), with_output_from()
  • SequentialBuilder: with_checkpointing(), with_intermediate_outputs()
  • ConcurrentBuilder: with_checkpointing(), with_intermediate_outputs()
  • GroupChatBuilder: with_termination_condition(), with_max_rounds(), with_checkpointing(), with_intermediate_outputs()
  • HandoffBuilder: with_checkpointing(), with_termination_condition()
  • MagenticBuilder: with_plan_review(), with_checkpointing(), with_intermediate_outputs()

Description

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@moonbox3 moonbox3 self-assigned this Feb 5, 2026
Copilot AI review requested due to automatic review settings February 5, 2026 10:50
@moonbox3 moonbox3 added python workflows Related to Workflows in agent-framework breaking change Introduces changes that are not backward compatible and may require updates to dependent code. labels Feb 5, 2026
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation lab Agent Framework Lab labels Feb 5, 2026
@markwallace-microsoft
Copy link
Member

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework/_workflows
   _orchestration_request_info.py540100% 
   _workflow.py2681992%89, 267–269, 271–272, 290, 294, 322, 424, 705, 747, 752, 755, 774–776, 789, 857
   _workflow_builder.py2683885%250, 258, 528, 626, 633–634, 734, 737, 742, 744, 751, 754–758, 760, 821, 895, 898, 924–925, 972, 985, 999–1006, 1008, 1011, 1013–1015, 1023
packages/orchestrations/agent_framework_orchestrations
   _concurrent.py1822884%51, 60–61, 69–70, 89–90, 95, 122, 127, 132–133, 139, 161, 171, 178, 358, 361, 389, 445, 457, 487, 489–490, 492, 497, 519, 523
   _group_chat.py2713587%171, 332, 339, 366, 377–378, 384, 389, 405, 432–437, 439, 472–475, 477, 482–486, 665, 670, 684, 765, 771, 845, 864, 883, 893
   _handoff.py3745784%109–110, 112, 141–142, 162–172, 174, 176, 178, 183, 283, 337, 362, 390, 398–399, 413, 462–463, 495, 542–544, 738, 745, 750, 837, 840, 849–852, 862, 867, 874, 880–883, 918, 923, 1036, 1039, 1047, 1065, 1072, 1147
   _magentic.py6079185%66–75, 80, 84–95, 260, 271, 275, 295, 356, 365, 367, 409, 426, 435–436, 438–440, 442, 453, 595, 597, 637, 687, 723–725, 727, 735–738, 742–745, 788, 815–818, 909, 915, 921, 960, 998, 1027, 1044, 1055, 1109–1110, 1114–1116, 1140, 1161–1162, 1175, 1191, 1213, 1261–1262, 1300–1301, 1472, 1481, 1484, 1489, 1789, 1831, 1846, 1875
   _sequential.py1031288%73, 177, 195, 206, 212, 244, 246–247, 249, 254, 276, 280
TOTAL16291191588% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
3991 221 💤 0 ❌ 0 🔥 1m 7s ⏱️

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a breaking change that converts 14 fluent builder methods across 6 orchestration builders into constructor parameters. The change eliminates duplicate configuration paths by removing methods like set_start_executor(), with_checkpointing(), with_max_rounds(), with_termination_condition(), with_intermediate_outputs(), and with_plan_review() in favor of constructor parameters.

Changes:

  • Moves single-configuration fluent methods to constructor parameters for WorkflowBuilder, SequentialBuilder, ConcurrentBuilder, GroupChatBuilder, HandoffBuilder, and MagenticBuilder
  • Updates all samples (60+ files) and tests (20+ files) to use the new constructor syntax
  • Converts set_start_executor() to private _set_start_executor() method and adds start_executor constructor parameter
  • Updates error messages and documentation to reflect the new API

Reviewed changes

Copilot reviewed 103 out of 103 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
_workflow_builder.py Adds constructor parameters (start_executor, checkpoint_storage, output_executors), removes fluent methods, makes set_start_executor private
_sequential.py Adds checkpoint_storage and intermediate_outputs constructor parameters, removes corresponding fluent methods
_concurrent.py Adds checkpoint_storage and intermediate_outputs constructor parameters, removes corresponding fluent methods
_group_chat.py Adds termination_condition, max_rounds, checkpoint_storage, and intermediate_outputs constructor parameters
_handoff.py Adds checkpoint_storage and termination_condition constructor parameters
_magentic.py Adds enable_plan_review, checkpoint_storage, and intermediate_outputs constructor parameters
Sample files (60+) Updates all workflow construction to use new constructor parameter syntax
Test files (20+) Updates all test code to use new constructor parameter syntax
_declarative_builder.py Updates to use WorkflowBuilder constructor parameters but calls private _set_start_executor()
_workflow.py, _orchestration_request_info.py Updates documentation and usage examples

.register_executor(lambda: database_access, name="database_access")
)

workflow_builder._start_executor = "store_email" # Set start executor
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct assignment to private attribute _start_executor bypasses the validation and wrapping logic in _set_start_executor. This could lead to bugs if the start_executor is an Agent or a string reference that needs to be resolved. Consider using builder._set_start_executor(...) instead to ensure proper validation and wrapping.

Copilot uses AI. Check for mistakes.
Comment on lines 148 to 217
@@ -163,13 +161,8 @@ def test_register_multiple_executors():
builder.register_executor(lambda: MockExecutor(id="ExecutorC"), name="ExecutorC")

# Build workflow with edges using registered names
workflow = (
builder
.set_start_executor("ExecutorA")
.add_edge("ExecutorA", "ExecutorB")
.add_edge("ExecutorB", "ExecutorC")
.build()
)
builder._start_executor = "ExecutorA"
workflow = builder.add_edge("ExecutorA", "ExecutorB").add_edge("ExecutorB", "ExecutorC").build()

# Verify all executors are present
assert "ExecutorA" in workflow.executors
@@ -193,7 +186,8 @@ def make_executor():
builder.register_executor(make_executor, name=["ExecutorA", "ExecutorB"])

# Set up workflow
workflow = builder.set_start_executor("ExecutorA").add_edge("ExecutorA", "ExecutorB").build()
builder._start_executor = "ExecutorA"
workflow = builder.add_edge("ExecutorA", "ExecutorB").build()

# Verify both executors are present
assert "ExecutorA" in workflow.executors
@@ -220,7 +214,7 @@ def test_register_duplicate_id_raises_error():
# Register first executor
builder.register_executor(lambda: MockExecutor(id="executor"), name="MyExecutor1")
builder.register_executor(lambda: MockExecutor(id="executor"), name="MyExecutor2")
builder.set_start_executor("MyExecutor1")
builder._start_executor = "MyExecutor1"
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple direct assignments to private attribute _start_executor bypass the validation and wrapping logic in _set_start_executor. This pattern appears throughout the test file and could lead to bugs if the start_executor is an Agent or a string reference that needs to be resolved. While acceptable in test code, consider documenting why the private API is being used directly, or preferably use the constructor parameter start_executor consistently.

Copilot uses AI. Check for mistakes.
if not self._start_executor:
raise ValueError("Starting executor must be set using set_start_executor before building the workflow.")
raise ValueError(
"Starting executor must be set using the start_executor constructor parameter before building."
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should be updated to match the new API. Instead of "using the start_executor constructor parameter", it should say "via the start_executor constructor parameter" to be consistent with Python conventions and clearer.

Suggested change
"Starting executor must be set using the start_executor constructor parameter before building."
"Starting executor must be set via the start_executor constructor parameter before building."

Copilot uses AI. Check for mistakes.
Comment on lines +163 to +167
builder._set_start_executor(entry_node)
# Use _add_sequential_edge which knows how to wire to structures
self._add_sequential_edge(builder, entry_node, entry_executor)
else:
builder.set_start_executor(entry_executor)
builder._set_start_executor(entry_executor)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _set_start_executor method is being made internal (prefixed with underscore) but is being called in user-facing code in the declarative builder. This creates an inconsistency - internal methods should not be called from outside the class. The declarative builder should use the constructor parameter start_executor instead, or this method should remain public.

Copilot uses AI. Check for mistakes.
)

# Step 2: Build the workflow graph using fan out and fan in edges.
workflow_builder._start_executor = "split_data_executor" # Set start executor
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct assignment to private attribute _start_executor bypasses the validation and wrapping logic in _set_start_executor. This could lead to bugs if the start_executor is an Agent or a string reference that needs to be resolved. Consider using builder._set_start_executor(...) instead to ensure proper validation and wrapping.

Copilot uses AI. Check for mistakes.
@moonbox3 moonbox3 changed the title Python: Move single-config fluent methods to constructor parameters [BREAKING] Python: Move single-config fluent methods to constructor parameters Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Introduces changes that are not backward compatible and may require updates to dependent code. documentation Improvements or additions to documentation lab Agent Framework Lab python workflows Related to Workflows in agent-framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Python: Move single-config fluent methods to constructor parameters

2 participants