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

* Move single-config fluent methods to constructor parameters

* Updates

* Adjust magentic and group chat
This commit is contained in:
Evan Mattson
2026-02-07 15:01:52 +09:00
committed by GitHub
Unverified
parent 5d355ac507
commit 74ac470a56
132 changed files with 1341 additions and 2386 deletions
+1 -1
View File
@@ -96,7 +96,7 @@ agents/
│ ├── agent.py
│ └── .env # Optional: API keys, config vars
├── my_workflow/
│ ├── __init__.py # Must export: workflow = WorkflowBuilder()...
│ ├── __init__.py # Must export: workflow = WorkflowBuilder(start_executor=...)...
│ ├── workflow.py
│ └── .env # Optional: environment variables
└── .env # Optional: shared environment variables
@@ -540,7 +540,7 @@ class EntityDiscovery:
This safely checks for module-level assignments like:
- agent = ChatAgent(...)
- workflow = WorkflowBuilder()...
- workflow = WorkflowBuilder(start_executor=...)...
Args:
file_path: Python file to check
@@ -441,7 +441,7 @@ class AgentFrameworkExecutor:
if not checkpoint_id:
error_msg = (
"Cannot process HIL responses without a checkpoint. "
"Workflows using HIL must be configured with .with_checkpointing() "
"Workflows using HIL must be configured with checkpoint_storage in constructor"
"and a checkpoint must exist before sending responses."
)
logger.error(error_msg)
@@ -488,7 +488,7 @@ async def sequential_workflow() -> tuple[AgentFrameworkExecutor, str, MockBaseCh
system_message="You are a reviewer. Provide constructive feedback.",
)
workflow = SequentialBuilder().participants([writer, reviewer]).build()
workflow = SequentialBuilder(participants=[writer, reviewer]).build()
discovery = EntityDiscovery(None)
mapper = MessageMapper()
@@ -540,7 +540,7 @@ async def concurrent_workflow() -> tuple[AgentFrameworkExecutor, str, MockBaseCh
system_message="You are a summarizer. Provide concise summaries.",
)
workflow = ConcurrentBuilder().participants([researcher, analyst, summarizer]).build()
workflow = ConcurrentBuilder(participants=[researcher, analyst, summarizer]).build()
discovery = EntityDiscovery(None)
mapper = MessageMapper()
@@ -76,12 +76,12 @@ def test_workflow():
executor = WorkflowTestExecutor(id="test_executor")
checkpoint_storage = InMemoryCheckpointStorage()
return (
WorkflowBuilder(name="Test Workflow", description="Test checkpoint behavior")
.set_start_executor(executor)
.with_checkpointing(checkpoint_storage)
.build()
)
return WorkflowBuilder(
name="Test Workflow",
description="Test checkpoint behavior",
start_executor=executor,
checkpoint_storage=checkpoint_storage,
).build()
class TestCheckpointConversationManager:
@@ -335,7 +335,7 @@ class TestIntegration:
# Get checkpoint storage for this session
checkpoint_storage = checkpoint_manager.get_checkpoint_storage(conversation_id)
# Set build-time storage (equivalent to .with_checkpointing() at build time)
# Set build-time storage (equivalent to checkpoint_storage= at build time)
# Note: In production, DevUI uses runtime injection via run(stream=True) parameter
if hasattr(test_workflow, "_runner") and hasattr(test_workflow._runner, "context"):
test_workflow._runner.context._checkpoint_storage = checkpoint_storage
@@ -399,7 +399,7 @@ class TestIntegration:
"""Test that workflows automatically save checkpoints to our conversation-backed storage.
This is the critical end-to-end test that verifies the entire checkpoint flow:
1. Storage is set as build-time storage (simulates .with_checkpointing())
1. Storage is set as build-time storage (simulates checkpoint_storage=...)
2. Workflow runs and pauses at HIL point (IDLE_WITH_PENDING_REQUESTS status)
3. Framework automatically saves checkpoint to our storage
4. Checkpoint is accessible via manager for UI to list/resume
@@ -135,10 +135,8 @@ from agent_framework import WorkflowBuilder, FunctionExecutor
def test_func(input: str) -> str:
return f"Processed: {input}"
builder = WorkflowBuilder()
executor = FunctionExecutor(id="test_executor", func=test_func)
builder.set_start_executor(executor)
workflow = builder.build()
workflow = WorkflowBuilder(start_executor=executor).build()
""")
discovery = EntityDiscovery(str(temp_path))
@@ -182,10 +180,8 @@ from agent_framework import WorkflowBuilder, FunctionExecutor
def test_func(input: str) -> str:
return f"Processed: {input}"
builder = WorkflowBuilder()
executor = FunctionExecutor(id="test_executor", func=test_func)
builder.set_start_executor(executor)
workflow = builder.build()
workflow = WorkflowBuilder(start_executor=executor).build()
""")
# Create agent with agent.py
@@ -243,10 +239,8 @@ from agent_framework import WorkflowBuilder, FunctionExecutor
def test_func(input: str) -> str:
return "v1"
builder = WorkflowBuilder()
executor = FunctionExecutor(id="test_executor", func=test_func)
builder.set_start_executor(executor)
workflow = builder.build()
workflow = WorkflowBuilder(start_executor=executor).build()
""")
discovery = EntityDiscovery(str(temp_path))
@@ -266,12 +260,9 @@ def test_func(input: str) -> str:
def test_func2(input: str) -> str:
return "v2_extra"
builder = WorkflowBuilder()
executor1 = FunctionExecutor(id="test_executor", func=test_func)
executor2 = FunctionExecutor(id="test_executor2", func=test_func2)
builder.set_start_executor(executor1)
builder.add_edge(executor1, executor2)
workflow = builder.build()
workflow = WorkflowBuilder(start_executor=executor1).add_edge(executor1, executor2).build()
""")
# Without invalidation, gets cached version
@@ -298,10 +289,8 @@ async def test_in_memory_entities_bypass_lazy_loading():
def test_func(input: str) -> str:
return f"Processed: {input}"
builder = WorkflowBuilder()
executor = FunctionExecutor(id="test_executor", func=test_func)
builder.set_start_executor(executor)
workflow = builder.build()
workflow = WorkflowBuilder(start_executor=executor).build()
discovery = EntityDiscovery()
@@ -175,10 +175,12 @@ async def test_workflow_streaming_execution():
def process_input(input_data: str) -> str:
return f"Processed: {input_data}"
builder = WorkflowBuilder(name="Test Workflow", description="Test workflow for execution")
start_executor = FunctionExecutor(id="process", func=process_input)
builder.set_start_executor(start_executor)
workflow = builder.build()
workflow = WorkflowBuilder(
name="Test Workflow",
description="Test workflow for execution",
start_executor=start_executor,
).build()
# Create executor and register workflow
discovery = EntityDiscovery(None)
@@ -213,10 +215,12 @@ async def test_workflow_sync_execution():
def echo(text: str) -> str:
return f"Echo: {text}"
builder = WorkflowBuilder(name="Echo Workflow", description="Simple echo workflow")
start_executor = FunctionExecutor(id="echo", func=echo)
builder.set_start_executor(start_executor)
workflow = builder.build()
workflow = WorkflowBuilder(
name="Echo Workflow",
description="Simple echo workflow",
start_executor=start_executor,
).build()
# Create executor and register workflow
discovery = EntityDiscovery(None)
@@ -308,10 +312,12 @@ async def test_full_pipeline_workflow_events_are_json_serializable():
system_message="You are a test assistant.",
)
builder = WorkflowBuilder(name="Serialization Test Workflow", description="Test workflow")
agent_executor = AgentExecutor(id="agent_node", agent=agent)
builder.set_start_executor(agent_executor)
workflow = builder.build()
workflow = WorkflowBuilder(
name="Serialization Test Workflow",
description="Test workflow",
start_executor=agent_executor,
).build()
# Create executor and register
discovery = EntityDiscovery(None)
@@ -420,11 +426,11 @@ async def test_executor_parse_structured_extracts_input_for_string_workflow():
async def process(self, text: str, ctx: WorkflowContext[Any, Any]) -> None:
await ctx.yield_output(f"Got: {text}")
workflow = (
WorkflowBuilder(name="String Workflow", description="Accepts string")
.set_start_executor(StringInputExecutor(id="str_exec"))
.build()
)
workflow = WorkflowBuilder(
name="String Workflow",
description="Accepts string",
start_executor=StringInputExecutor(id="str_exec"),
).build()
executor = AgentFrameworkExecutor(EntityDiscovery(None), MessageMapper())
@@ -445,11 +451,11 @@ async def test_executor_parse_raw_string_for_string_workflow():
async def process(self, text: str, ctx: WorkflowContext[Any, Any]) -> None:
await ctx.yield_output(f"Got: {text}")
workflow = (
WorkflowBuilder(name="String Workflow", description="Accepts string")
.set_start_executor(StringInputExecutor(id="str_exec"))
.build()
)
workflow = WorkflowBuilder(
name="String Workflow",
description="Accepts string",
start_executor=StringInputExecutor(id="str_exec"),
).build()
executor = AgentFrameworkExecutor(EntityDiscovery(None), MessageMapper())
@@ -490,11 +496,11 @@ async def test_executor_parse_stringified_json_workflow_input():
await ctx.yield_output(f"Got: {data.input}")
# Build workflow with Pydantic input type
workflow = (
WorkflowBuilder(name="Pydantic Workflow", description="Accepts Pydantic input")
.set_start_executor(PydanticInputExecutor(id="pydantic_exec"))
.build()
)
workflow = WorkflowBuilder(
name="Pydantic Workflow",
description="Accepts Pydantic input",
start_executor=PydanticInputExecutor(id="pydantic_exec"),
).build()
executor = AgentFrameworkExecutor(EntityDiscovery(None), MessageMapper())
@@ -689,11 +695,11 @@ async def test_full_pipeline_workflow_output_event_serialization():
await ctx.yield_output({"final": "result", "data": [1, 2, 3]})
# Build workflow
workflow = (
WorkflowBuilder(name="Output Workflow", description="Tests yield_output")
.set_start_executor(OutputtingExecutor(id="outputter"))
.build()
)
workflow = WorkflowBuilder(
name="Output Workflow",
description="Tests yield_output",
start_executor=OutputtingExecutor(id="outputter"),
).build()
# Create DevUI executor and register workflow
discovery = EntityDiscovery(None)