mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
[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:
committed by
GitHub
Unverified
parent
5d355ac507
commit
74ac470a56
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user