[BREAKING] Python: Move orchestrations to dedicated package (#3685)

* Move orchestrations to dedicated package

* Merge main

* Fix markdown links

* Fix links
This commit is contained in:
Evan Mattson
2026-02-05 12:05:13 +09:00
committed by GitHub
Unverified
parent 10afb86213
commit 0daa7700c6
47 changed files with 1197 additions and 712 deletions
+1 -1
View File
@@ -233,7 +233,7 @@ if __name__ == "__main__":
asyncio.run(main())
```
For more advanced orchestration patterns including Sequential, GroupChat, Concurrent, Magentic, and Handoff orchestrations, see the [orchestration samples](samples/getting_started/workflows/orchestration).
For more advanced orchestration patterns including Sequential, Concurrent, Group Chat, Handoff, and Magentic orchestrations, see the [orchestration samples](samples/getting_started/orchestrations).
## More Examples & Samples
+1 -4
View File
@@ -213,10 +213,7 @@ if __name__ == "__main__":
asyncio.run(main())
```
**Note**: GroupChat, Sequential, and Concurrent orchestrations are available today. See examples in:
- [python/samples/getting_started/workflows/orchestration/](https://github.com/microsoft/agent-framework/tree/main/python/samples/getting_started/workflows/orchestration)
- [group_chat_simple_selector.py](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/workflows/orchestration/group_chat_simple_selector.py)
- [group_chat_prompt_based_manager.py](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/workflows/orchestration/group_chat_prompt_based_manager.py)
**Note**: Sequential, Concurrent, Group Chat, Handoff, and Magentic orchestrations are available. See examples in [orchestration samples](../../samples/getting_started/orchestrations).
## More Examples & Samples
@@ -20,7 +20,6 @@ from ._checkpoint import (
WorkflowCheckpoint,
)
from ._checkpoint_summary import WorkflowCheckpointSummary, get_checkpoint_summary
from ._concurrent import ConcurrentBuilder
from ._const import (
DEFAULT_MAX_ITERATIONS,
)
@@ -66,30 +65,6 @@ from ._executor import (
handler,
)
from ._function_executor import FunctionExecutor, executor
from ._group_chat import (
AgentBasedGroupChatOrchestrator,
GroupChatBuilder,
GroupChatState,
)
from ._handoff import HandoffAgentUserRequest, HandoffBuilder, HandoffSentEvent
from ._magentic import (
ORCH_MSG_KIND_INSTRUCTION,
ORCH_MSG_KIND_NOTICE,
ORCH_MSG_KIND_TASK_LEDGER,
ORCH_MSG_KIND_USER_TASK,
MagenticBuilder,
MagenticContext,
MagenticManagerBase,
MagenticOrchestrator,
MagenticOrchestratorEvent,
MagenticOrchestratorEventType,
MagenticPlanReviewRequest,
MagenticPlanReviewResponse,
MagenticProgressLedger,
MagenticProgressLedgerItem,
MagenticResetSignal,
StandardMagenticManager,
)
from ._orchestration_request_info import AgentRequestInfoResponse
from ._orchestration_state import OrchestrationState
from ._request_info_mixin import response_handler
@@ -99,7 +74,6 @@ from ._runner_context import (
Message,
RunnerContext,
)
from ._sequential import SequentialBuilder
from ._validation import (
EdgeDuplicationError,
GraphConnectivityError,
@@ -120,11 +94,6 @@ from ._workflow_executor import (
__all__ = [
"DEFAULT_MAX_ITERATIONS",
"ORCH_MSG_KIND_INSTRUCTION",
"ORCH_MSG_KIND_NOTICE",
"ORCH_MSG_KIND_TASK_LEDGER",
"ORCH_MSG_KIND_USER_TASK",
"AgentBasedGroupChatOrchestrator",
"AgentExecutor",
"AgentExecutorRequest",
"AgentExecutorResponse",
@@ -132,7 +101,6 @@ __all__ = [
"BaseGroupChatOrchestrator",
"Case",
"CheckpointStorage",
"ConcurrentBuilder",
"Default",
"Edge",
"EdgeCondition",
@@ -147,35 +115,17 @@ __all__ = [
"FileCheckpointStorage",
"FunctionExecutor",
"GraphConnectivityError",
"GroupChatBuilder",
"GroupChatRequestMessage",
"GroupChatRequestSentEvent",
"GroupChatResponseReceivedEvent",
"GroupChatState",
"HandoffAgentUserRequest",
"HandoffBuilder",
"HandoffSentEvent",
"InMemoryCheckpointStorage",
"InProcRunnerContext",
"MagenticBuilder",
"MagenticContext",
"MagenticManagerBase",
"MagenticOrchestrator",
"MagenticOrchestratorEvent",
"MagenticOrchestratorEventType",
"MagenticPlanReviewRequest",
"MagenticPlanReviewResponse",
"MagenticProgressLedger",
"MagenticProgressLedgerItem",
"MagenticResetSignal",
"Message",
"OrchestrationState",
"RequestInfoEvent",
"Runner",
"RunnerContext",
"SequentialBuilder",
"SingleEdgeGroup",
"StandardMagenticManager",
"SubWorkflowRequestMessage",
"SubWorkflowResponseMessage",
"SuperStepCompletedEvent",
@@ -0,0 +1,61 @@
# Copyright (c) Microsoft. All rights reserved.
import importlib
from typing import Any
IMPORT_PATH = "agent_framework_orchestrations"
PACKAGE_NAME = "agent-framework-orchestrations"
_IMPORTS = [
"__version__",
# Sequential
"SequentialBuilder",
# Concurrent
"ConcurrentBuilder",
# Handoff
"HandoffAgentExecutor",
"HandoffAgentUserRequest",
"HandoffBuilder",
"HandoffConfiguration",
"HandoffSentEvent",
# Group Chat
"AgentBasedGroupChatOrchestrator",
"AgentOrchestrationOutput",
"GroupChatBuilder",
"GroupChatOrchestrator",
"GroupChatSelectionFunction",
"GroupChatState",
# Magentic
"MAGENTIC_MANAGER_NAME",
"ORCH_MSG_KIND_INSTRUCTION",
"ORCH_MSG_KIND_NOTICE",
"ORCH_MSG_KIND_TASK_LEDGER",
"ORCH_MSG_KIND_USER_TASK",
"MagenticAgentExecutor",
"MagenticBuilder",
"MagenticContext",
"MagenticManagerBase",
"MagenticOrchestrator",
"MagenticOrchestratorEvent",
"MagenticOrchestratorEventType",
"MagenticPlanReviewRequest",
"MagenticPlanReviewResponse",
"MagenticProgressLedger",
"MagenticProgressLedgerItem",
"MagenticResetSignal",
"StandardMagenticManager",
]
def __getattr__(name: str) -> Any:
if name in _IMPORTS:
try:
return getattr(importlib.import_module(IMPORT_PATH), name)
except ModuleNotFoundError as exc:
raise ModuleNotFoundError(
f"The '{PACKAGE_NAME}' package is not installed, please do `pip install {PACKAGE_NAME}`"
) from exc
raise AttributeError(f"Module {IMPORT_PATH} has no attribute {name}.")
def __dir__() -> list[str]:
return _IMPORTS
@@ -0,0 +1,141 @@
# Copyright (c) Microsoft. All rights reserved.
# Type stubs for lazy-loaded orchestrations module
# These re-export types from agent_framework_orchestrations
from agent_framework_orchestrations import (
# Magentic
MAGENTIC_MANAGER_NAME as MAGENTIC_MANAGER_NAME,
)
from agent_framework_orchestrations import (
ORCH_MSG_KIND_INSTRUCTION as ORCH_MSG_KIND_INSTRUCTION,
)
from agent_framework_orchestrations import (
ORCH_MSG_KIND_NOTICE as ORCH_MSG_KIND_NOTICE,
)
from agent_framework_orchestrations import (
ORCH_MSG_KIND_TASK_LEDGER as ORCH_MSG_KIND_TASK_LEDGER,
)
from agent_framework_orchestrations import (
ORCH_MSG_KIND_USER_TASK as ORCH_MSG_KIND_USER_TASK,
)
from agent_framework_orchestrations import (
# Group Chat
AgentBasedGroupChatOrchestrator as AgentBasedGroupChatOrchestrator,
)
from agent_framework_orchestrations import (
AgentOrchestrationOutput as AgentOrchestrationOutput,
)
from agent_framework_orchestrations import (
# Concurrent
ConcurrentBuilder as ConcurrentBuilder,
)
from agent_framework_orchestrations import (
GroupChatBuilder as GroupChatBuilder,
)
from agent_framework_orchestrations import (
GroupChatOrchestrator as GroupChatOrchestrator,
)
from agent_framework_orchestrations import (
GroupChatSelectionFunction as GroupChatSelectionFunction,
)
from agent_framework_orchestrations import (
GroupChatState as GroupChatState,
)
from agent_framework_orchestrations import (
# Handoff
HandoffAgentExecutor as HandoffAgentExecutor,
)
from agent_framework_orchestrations import (
HandoffAgentUserRequest as HandoffAgentUserRequest,
)
from agent_framework_orchestrations import (
HandoffBuilder as HandoffBuilder,
)
from agent_framework_orchestrations import (
HandoffConfiguration as HandoffConfiguration,
)
from agent_framework_orchestrations import (
HandoffSentEvent as HandoffSentEvent,
)
from agent_framework_orchestrations import (
MagenticAgentExecutor as MagenticAgentExecutor,
)
from agent_framework_orchestrations import (
MagenticBuilder as MagenticBuilder,
)
from agent_framework_orchestrations import (
MagenticContext as MagenticContext,
)
from agent_framework_orchestrations import (
MagenticManagerBase as MagenticManagerBase,
)
from agent_framework_orchestrations import (
MagenticOrchestrator as MagenticOrchestrator,
)
from agent_framework_orchestrations import (
MagenticOrchestratorEvent as MagenticOrchestratorEvent,
)
from agent_framework_orchestrations import (
MagenticOrchestratorEventType as MagenticOrchestratorEventType,
)
from agent_framework_orchestrations import (
MagenticPlanReviewRequest as MagenticPlanReviewRequest,
)
from agent_framework_orchestrations import (
MagenticPlanReviewResponse as MagenticPlanReviewResponse,
)
from agent_framework_orchestrations import (
MagenticProgressLedger as MagenticProgressLedger,
)
from agent_framework_orchestrations import (
MagenticProgressLedgerItem as MagenticProgressLedgerItem,
)
from agent_framework_orchestrations import (
MagenticResetSignal as MagenticResetSignal,
)
from agent_framework_orchestrations import (
# Sequential
SequentialBuilder as SequentialBuilder,
)
from agent_framework_orchestrations import (
StandardMagenticManager as StandardMagenticManager,
)
from agent_framework_orchestrations import (
__version__ as __version__,
)
__all__ = [
"MAGENTIC_MANAGER_NAME",
"ORCH_MSG_KIND_INSTRUCTION",
"ORCH_MSG_KIND_NOTICE",
"ORCH_MSG_KIND_TASK_LEDGER",
"ORCH_MSG_KIND_USER_TASK",
"AgentBasedGroupChatOrchestrator",
"AgentOrchestrationOutput",
"ConcurrentBuilder",
"GroupChatBuilder",
"GroupChatOrchestrator",
"GroupChatSelectionFunction",
"GroupChatState",
"HandoffAgentExecutor",
"HandoffAgentUserRequest",
"HandoffBuilder",
"HandoffConfiguration",
"HandoffSentEvent",
"MagenticAgentExecutor",
"MagenticBuilder",
"MagenticContext",
"MagenticManagerBase",
"MagenticOrchestrator",
"MagenticOrchestratorEvent",
"MagenticOrchestratorEventType",
"MagenticPlanReviewRequest",
"MagenticPlanReviewResponse",
"MagenticProgressLedger",
"MagenticProgressLedgerItem",
"MagenticResetSignal",
"SequentialBuilder",
"StandardMagenticManager",
"__version__",
]
+1
View File
@@ -55,6 +55,7 @@ all = [
"agent-framework-lab",
"agent-framework-mem0",
"agent-framework-ollama",
"agent-framework-orchestrations",
"agent-framework-purview",
"agent-framework-redis",
]
@@ -12,13 +12,13 @@ from agent_framework import (
ChatMessage,
ChatMessageStore,
Content,
SequentialBuilder,
WorkflowOutputEvent,
WorkflowRunState,
WorkflowStatusEvent,
)
from agent_framework._workflows._agent_executor import AgentExecutorResponse
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework.orchestrations import SequentialBuilder
class _CountingAgent(BaseAgent):
@@ -16,13 +16,13 @@ from agent_framework import (
ChatMessage,
Content,
Executor,
SequentialBuilder,
WorkflowBuilder,
WorkflowContext,
WorkflowRunState,
WorkflowStatusEvent,
handler,
)
from agent_framework.orchestrations import SequentialBuilder
class _SimpleAgent(BaseAgent):
@@ -11,17 +11,19 @@ from agent_framework import (
AgentThread,
BaseAgent,
ChatMessage,
ConcurrentBuilder,
Content,
GroupChatBuilder,
GroupChatState,
HandoffBuilder,
SequentialBuilder,
WorkflowRunState,
WorkflowStatusEvent,
tool,
)
from agent_framework._workflows._const import WORKFLOW_RUN_KWARGS_KEY
from agent_framework.orchestrations import (
ConcurrentBuilder,
GroupChatBuilder,
GroupChatState,
HandoffBuilder,
SequentialBuilder,
)
# Track kwargs received by tools during test execution
_received_kwargs: list[dict[str, Any]] = []
@@ -371,14 +373,15 @@ async def test_handoff_kwargs_flow_to_agents() -> None:
async def test_magentic_kwargs_flow_to_agents() -> None:
"""Test that kwargs flow to agents in a magentic workflow via MagenticAgentExecutor."""
from agent_framework import MagenticBuilder
from agent_framework._workflows._magentic import (
from agent_framework_orchestrations._magentic import (
MagenticContext,
MagenticManagerBase,
MagenticProgressLedger,
MagenticProgressLedgerItem,
)
from agent_framework.orchestrations import MagenticBuilder
# Create a mock manager that completes after one round
class _MockManager(MagenticManagerBase):
def __init__(self) -> None:
@@ -422,14 +425,15 @@ async def test_magentic_kwargs_flow_to_agents() -> None:
async def test_magentic_kwargs_stored_in_state() -> None:
"""Test that kwargs are stored in State when using MagenticWorkflow.run_stream()."""
from agent_framework import MagenticBuilder
from agent_framework._workflows._magentic import (
from agent_framework_orchestrations._magentic import (
MagenticContext,
MagenticManagerBase,
MagenticProgressLedger,
MagenticProgressLedgerItem,
)
from agent_framework.orchestrations import MagenticBuilder
class _MockManager(MagenticManagerBase):
def __init__(self) -> None:
super().__init__(max_stall_count=3, max_reset_count=None, max_round_count=1)
+1 -2
View File
@@ -27,13 +27,12 @@ from agent_framework import (
ChatMessage,
ChatResponse,
ChatResponseUpdate,
ConcurrentBuilder,
Content,
SequentialBuilder,
use_chat_middleware,
)
from agent_framework._clients import TOptions_co
from agent_framework._workflows._agent_executor import AgentExecutorResponse
from agent_framework.orchestrations import ConcurrentBuilder, SequentialBuilder
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
+19 -19
View File
@@ -437,20 +437,20 @@ async def test_workflow_status_event(mapper: MessageMapper, test_request: AgentF
# =============================================================================
# Magentic Event Tests - Testing REAL AgentRunUpdateEvent with additional_properties
# Magentic Event Tests - Testing WorkflowOutputEvent with additional_properties
# =============================================================================
async def test_magentic_agent_run_update_event_with_agent_delta_metadata(
mapper: MessageMapper, test_request: AgentFrameworkRequest
) -> None:
"""Test that AgentRunUpdateEvent with magentic_event_type='agent_delta' is handled correctly.
"""Test that WorkflowOutputEvent with magentic_event_type='agent_delta' is handled correctly.
This tests the ACTUAL event format Magentic emits - not a fake MagenticAgentDeltaEvent class.
Magentic uses AgentRunUpdateEvent with additional_properties containing magentic_event_type.
Magentic uses WorkflowOutputEvent wrapping AgentResponseUpdate with additional_properties.
"""
from agent_framework._types import AgentResponseUpdate
from agent_framework._workflows._events import AgentRunUpdateEvent
from agent_framework._workflows._events import WorkflowOutputEvent
# Create the REAL event format that Magentic emits
update = AgentResponseUpdate(
@@ -462,11 +462,11 @@ async def test_magentic_agent_run_update_event_with_agent_delta_metadata(
"agent_id": "writer_agent",
},
)
event = AgentRunUpdateEvent(executor_id="magentic_executor", data=update)
event = WorkflowOutputEvent(executor_id="magentic_executor", data=update)
events = await mapper.convert_event(event, test_request)
# Should be treated as a regular AgentRunUpdateEvent with text content
# Should be treated as a regular WorkflowOutputEvent with text content
# The mapper should emit text delta events
assert len(events) >= 1
text_events = [e for e in events if getattr(e, "type", "") == "response.output_text.delta"]
@@ -475,13 +475,13 @@ async def test_magentic_agent_run_update_event_with_agent_delta_metadata(
async def test_magentic_orchestrator_message_event(mapper: MessageMapper, test_request: AgentFrameworkRequest) -> None:
"""Test that AgentRunUpdateEvent with magentic_event_type='orchestrator_message' is handled.
"""Test that WorkflowOutputEvent with magentic_event_type='orchestrator_message' is handled.
Magentic emits orchestrator planning/instruction messages using AgentRunUpdateEvent
with additional_properties containing magentic_event_type='orchestrator_message'.
Magentic emits orchestrator planning/instruction messages using WorkflowOutputEvent
wrapping AgentResponseUpdate with additional_properties.
"""
from agent_framework._types import AgentResponseUpdate
from agent_framework._workflows._events import AgentRunUpdateEvent
from agent_framework._workflows._events import WorkflowOutputEvent
# Create orchestrator message event (REAL format from Magentic)
update = AgentResponseUpdate(
@@ -494,11 +494,11 @@ async def test_magentic_orchestrator_message_event(mapper: MessageMapper, test_r
"orchestrator_id": "magentic_orchestrator",
},
)
event = AgentRunUpdateEvent(executor_id="magentic_orchestrator", data=update)
event = WorkflowOutputEvent(executor_id="magentic_orchestrator", data=update)
events = await mapper.convert_event(event, test_request)
# Currently, mapper treats this as regular AgentRunUpdateEvent (no special handling)
# Currently, mapper treats this as regular WorkflowOutputEvent (no special handling)
# This test documents the current behavior
assert len(events) >= 1
text_events = [e for e in events if getattr(e, "type", "") == "response.output_text.delta"]
@@ -509,15 +509,15 @@ async def test_magentic_orchestrator_message_event(mapper: MessageMapper, test_r
async def test_magentic_events_use_same_event_class_as_other_workflows(
mapper: MessageMapper, test_request: AgentFrameworkRequest
) -> None:
"""Verify Magentic uses the same AgentRunUpdateEvent class as other workflows.
"""Verify Magentic uses the same WorkflowOutputEvent class as other workflows.
This test documents that Magentic does NOT define separate event classes like
MagenticAgentDeltaEvent - it reuses AgentRunUpdateEvent with metadata in
MagenticAgentDeltaEvent - it reuses WorkflowOutputEvent with metadata in
additional_properties. Any mapper code checking for 'MagenticAgentDeltaEvent'
class names is dead code.
"""
from agent_framework._types import AgentResponseUpdate
from agent_framework._workflows._events import AgentRunUpdateEvent
from agent_framework._workflows._events import WorkflowOutputEvent
# Create events the way different workflows do it
# 1. Regular workflow (no additional_properties)
@@ -525,7 +525,7 @@ async def test_magentic_events_use_same_event_class_as_other_workflows(
contents=[Content.from_text(text="Regular workflow response")],
role="assistant",
)
regular_event = AgentRunUpdateEvent(executor_id="regular_executor", data=regular_update)
regular_event = WorkflowOutputEvent(executor_id="regular_executor", data=regular_update)
# 2. Magentic workflow (with additional_properties)
magentic_update = AgentResponseUpdate(
@@ -533,12 +533,12 @@ async def test_magentic_events_use_same_event_class_as_other_workflows(
role="assistant",
additional_properties={"magentic_event_type": "agent_delta"},
)
magentic_event = AgentRunUpdateEvent(executor_id="magentic_executor", data=magentic_update)
magentic_event = WorkflowOutputEvent(executor_id="magentic_executor", data=magentic_update)
# Both should be the SAME class
assert type(regular_event) is type(magentic_event)
assert isinstance(regular_event, AgentRunUpdateEvent)
assert isinstance(magentic_event, AgentRunUpdateEvent)
assert isinstance(regular_event, WorkflowOutputEvent)
assert isinstance(magentic_event, WorkflowOutputEvent)
# Both should be handled by the same isinstance check in mapper
regular_events = await mapper.convert_event(regular_event, test_request)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
+88
View File
@@ -0,0 +1,88 @@
# Agent Framework Orchestrations
Orchestration patterns for Microsoft Agent Framework. This package provides high-level builders for common multi-agent workflow patterns.
## Installation
```bash
pip install agent-framework-orchestrations
```
## Orchestration Patterns
### SequentialBuilder
Chain agents/executors in sequence, passing conversation context along:
```python
from agent_framework_orchestrations import SequentialBuilder
workflow = SequentialBuilder().participants([agent1, agent2, agent3]).build()
```
### ConcurrentBuilder
Fan-out to multiple agents in parallel, then aggregate results:
```python
from agent_framework_orchestrations import ConcurrentBuilder
workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).build()
```
### HandoffBuilder
Decentralized agent routing where agents decide handoff targets:
```python
from agent_framework_orchestrations import HandoffBuilder
workflow = (
HandoffBuilder()
.participants([triage, billing, support])
.with_start_agent(triage)
.build()
)
```
### GroupChatBuilder
Orchestrator-directed multi-agent conversations:
```python
from agent_framework_orchestrations import GroupChatBuilder
workflow = (
GroupChatBuilder()
.with_orchestrator(selection_func=my_selector)
.participants([agent1, agent2])
.build()
)
```
### MagenticBuilder
Sophisticated multi-agent orchestration using the Magentic One pattern:
```python
from agent_framework_orchestrations import MagenticBuilder
workflow = (
MagenticBuilder()
.participants([researcher, writer, reviewer])
.with_manager(agent=manager_agent)
.build()
)
```
## Usage with agent_framework
You can also import orchestrations through the main agent_framework package:
```python
from agent_framework.orchestrations import SequentialBuilder, ConcurrentBuilder
```
## Documentation
For more information, see the [Agent Framework documentation](https://aka.ms/agent-framework).
@@ -0,0 +1,91 @@
# Copyright (c) Microsoft. All rights reserved.
"""Orchestration patterns for Microsoft Agent Framework.
This package provides high-level builders for common multi-agent workflow patterns:
- SequentialBuilder: Chain agents in sequence
- ConcurrentBuilder: Fan-out to multiple agents in parallel
- HandoffBuilder: Decentralized agent routing
- GroupChatBuilder: Orchestrator-directed multi-agent conversations
- MagenticBuilder: Magentic One pattern for sophisticated multi-agent orchestration
"""
import importlib.metadata
try:
__version__ = importlib.metadata.version(__name__)
except importlib.metadata.PackageNotFoundError:
__version__ = "0.0.0" # Fallback for development mode
from ._concurrent import ConcurrentBuilder
from ._group_chat import (
AgentBasedGroupChatOrchestrator,
AgentOrchestrationOutput,
GroupChatBuilder,
GroupChatOrchestrator,
GroupChatSelectionFunction,
GroupChatState,
)
from ._handoff import (
HandoffAgentExecutor,
HandoffAgentUserRequest,
HandoffBuilder,
HandoffConfiguration,
HandoffSentEvent,
)
from ._magentic import (
MAGENTIC_MANAGER_NAME,
ORCH_MSG_KIND_INSTRUCTION,
ORCH_MSG_KIND_NOTICE,
ORCH_MSG_KIND_TASK_LEDGER,
ORCH_MSG_KIND_USER_TASK,
MagenticAgentExecutor,
MagenticBuilder,
MagenticContext,
MagenticManagerBase,
MagenticOrchestrator,
MagenticOrchestratorEvent,
MagenticOrchestratorEventType,
MagenticPlanReviewRequest,
MagenticPlanReviewResponse,
MagenticProgressLedger,
MagenticProgressLedgerItem,
MagenticResetSignal,
StandardMagenticManager,
)
from ._sequential import SequentialBuilder
__all__ = [
"MAGENTIC_MANAGER_NAME",
"ORCH_MSG_KIND_INSTRUCTION",
"ORCH_MSG_KIND_NOTICE",
"ORCH_MSG_KIND_TASK_LEDGER",
"ORCH_MSG_KIND_USER_TASK",
"AgentBasedGroupChatOrchestrator",
"AgentOrchestrationOutput",
"ConcurrentBuilder",
"GroupChatBuilder",
"GroupChatOrchestrator",
"GroupChatSelectionFunction",
"GroupChatState",
"HandoffAgentExecutor",
"HandoffAgentUserRequest",
"HandoffBuilder",
"HandoffConfiguration",
"HandoffSentEvent",
"MagenticAgentExecutor",
"MagenticBuilder",
"MagenticContext",
"MagenticManagerBase",
"MagenticOrchestrator",
"MagenticOrchestratorEvent",
"MagenticOrchestratorEventType",
"MagenticPlanReviewRequest",
"MagenticPlanReviewResponse",
"MagenticProgressLedger",
"MagenticProgressLedgerItem",
"MagenticResetSignal",
"SequentialBuilder",
"StandardMagenticManager",
"__version__",
]
@@ -6,19 +6,17 @@ import logging
from collections.abc import Callable, Sequence
from typing import Any
from typing_extensions import Never
from agent_framework import AgentProtocol, ChatMessage
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._agent_utils import resolve_agent_id
from ._checkpoint import CheckpointStorage
from ._executor import Executor, handler
from ._message_utils import normalize_messages_input
from ._orchestration_request_info import AgentApprovalExecutor
from ._workflow import Workflow
from ._workflow_builder import WorkflowBuilder
from ._workflow_context import WorkflowContext
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from agent_framework._workflows._agent_utils import resolve_agent_id
from agent_framework._workflows._checkpoint import CheckpointStorage
from agent_framework._workflows._executor import Executor, handler
from agent_framework._workflows._message_utils import normalize_messages_input
from agent_framework._workflows._orchestration_request_info import AgentApprovalExecutor
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_builder import WorkflowBuilder
from agent_framework._workflows._workflow_context import WorkflowContext
from typing_extensions import Never
logger = logging.getLogger(__name__)
@@ -198,7 +196,7 @@ class ConcurrentBuilder:
.. code-block:: python
from agent_framework import ConcurrentBuilder
from agent_framework_orchestrations import ConcurrentBuilder
# Minimal: use default aggregator (returns list[ChatMessage])
workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).build()
@@ -483,7 +481,7 @@ class ConcurrentBuilder:
Returns:
Self for fluent chaining
"""
from ._orchestration_request_info import resolve_request_info_filter
from agent_framework._workflows._orchestration_request_info import resolve_request_info_filter
self._request_info_enabled = True
self._request_info_filter = resolve_request_info_filter(list(agents) if agents else None)
@@ -26,15 +26,12 @@ from collections.abc import Awaitable, Callable, Sequence
from dataclasses import dataclass
from typing import Any, ClassVar, cast, overload
from pydantic import BaseModel, Field
from typing_extensions import Never
from .._agents import AgentProtocol, ChatAgent
from .._threads import AgentThread
from .._types import ChatMessage
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._agent_utils import resolve_agent_id
from ._base_group_chat_orchestrator import (
from agent_framework import AgentProtocol, ChatAgent
from agent_framework._threads import AgentThread
from agent_framework._types import ChatMessage
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from agent_framework._workflows._agent_utils import resolve_agent_id
from agent_framework._workflows._base_group_chat_orchestrator import (
BaseGroupChatOrchestrator,
GroupChatParticipantMessage,
GroupChatRequestMessage,
@@ -43,13 +40,15 @@ from ._base_group_chat_orchestrator import (
ParticipantRegistry,
TerminationCondition,
)
from ._checkpoint import CheckpointStorage
from ._conversation_state import decode_chat_messages, encode_chat_messages
from ._executor import Executor
from ._orchestration_request_info import AgentApprovalExecutor
from ._workflow import Workflow
from ._workflow_builder import WorkflowBuilder
from ._workflow_context import WorkflowContext
from agent_framework._workflows._checkpoint import CheckpointStorage
from agent_framework._workflows._conversation_state import decode_chat_messages, encode_chat_messages
from agent_framework._workflows._executor import Executor
from agent_framework._workflows._orchestration_request_info import AgentApprovalExecutor
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_builder import WorkflowBuilder
from agent_framework._workflows._workflow_context import WorkflowContext
from pydantic import BaseModel, Field
from typing_extensions import Never
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
@@ -134,7 +133,7 @@ class GroupChatOrchestrator(BaseGroupChatOrchestrator):
Example:
.. code-block:: python
from agent_framework import GroupChatOrchestrator
from agent_framework_orchestrations import GroupChatOrchestrator
async def round_robin_selector(state: GroupChatState) -> str:
@@ -641,7 +640,7 @@ class GroupChatBuilder:
Example:
.. code-block:: python
from agent_framework import GroupChatBuilder
from agent_framework_orchestrations import GroupChatBuilder
orchestrator = CustomGroupChatOrchestrator(...)
@@ -726,7 +725,7 @@ class GroupChatBuilder:
.. code-block:: python
from agent_framework import GroupChatBuilder
from agent_framework_orchestrations import GroupChatBuilder
workflow = (
GroupChatBuilder()
@@ -781,7 +780,8 @@ class GroupChatBuilder:
.. code-block:: python
from agent_framework import ChatMessage, GroupChatBuilder, Role
from agent_framework import ChatMessage
from agent_framework_orchestrations import GroupChatBuilder
def stop_after_two_calls(conversation: list[ChatMessage]) -> bool:
@@ -840,7 +840,8 @@ class GroupChatBuilder:
.. code-block:: python
from agent_framework import GroupChatBuilder, MemoryCheckpointStorage
from agent_framework import MemoryCheckpointStorage
from agent_framework_orchestrations import GroupChatBuilder
storage = MemoryCheckpointStorage()
workflow = (
@@ -876,7 +877,7 @@ class GroupChatBuilder:
Returns:
Self for fluent chaining
"""
from ._orchestration_request_info import resolve_request_info_filter
from agent_framework._workflows._orchestration_request_info import resolve_request_info_filter
self._request_info_enabled = True
self._request_info_filter = resolve_request_info_filter(list(agents) if agents else None)
@@ -36,24 +36,23 @@ from collections.abc import Awaitable, Callable, Mapping, Sequence
from dataclasses import dataclass
from typing import Any, cast
from agent_framework import AgentProtocol, ChatAgent
from agent_framework._middleware import FunctionInvocationContext, FunctionMiddleware
from agent_framework._threads import AgentThread
from agent_framework._tools import FunctionTool, tool
from agent_framework._types import AgentResponse, AgentResponseUpdate, ChatMessage
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from agent_framework._workflows._agent_utils import resolve_agent_id
from agent_framework._workflows._base_group_chat_orchestrator import TerminationCondition
from agent_framework._workflows._checkpoint import CheckpointStorage
from agent_framework._workflows._events import WorkflowEvent
from agent_framework._workflows._orchestrator_helpers import clean_conversation_for_handoff
from agent_framework._workflows._request_info_mixin import response_handler
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_builder import WorkflowBuilder
from agent_framework._workflows._workflow_context import WorkflowContext
from typing_extensions import Never
from .._agents import AgentProtocol, ChatAgent
from .._middleware import FunctionInvocationContext, FunctionMiddleware
from .._threads import AgentThread
from .._tools import FunctionTool, tool
from .._types import AgentResponse, AgentResponseUpdate, ChatMessage
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._agent_utils import resolve_agent_id
from ._base_group_chat_orchestrator import TerminationCondition
from ._checkpoint import CheckpointStorage
from ._events import WorkflowEvent
from ._orchestrator_helpers import clean_conversation_for_handoff
from ._request_info_mixin import response_handler
from ._workflow import Workflow
from ._workflow_builder import WorkflowBuilder
from ._workflow_context import WorkflowContext
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
else:
@@ -333,14 +332,14 @@ class HandoffAgentExecutor(AgentExecutor):
new_tools: list[FunctionTool[Any, Any]] = []
for target in targets:
tool = self._create_handoff_tool(target.target_id, target.description)
if tool.name in existing_names:
handoff_tool = self._create_handoff_tool(target.target_id, target.description)
if handoff_tool.name in existing_names:
raise ValueError(
f"Agent '{resolve_agent_id(agent)}' already has a tool named '{tool.name}'. "
f"Handoff tool name '{tool.name}' conflicts with existing tool."
f"Agent '{resolve_agent_id(agent)}' already has a tool named '{handoff_tool.name}'. "
f"Handoff tool name '{handoff_tool.name}' conflicts with existing tool."
"Please rename the existing tool or modify the target agent ID to avoid conflicts."
)
new_tools.append(tool)
new_tools.append(handoff_tool)
if new_tools:
default_options["tools"] = existing_tools + new_tools # type: ignore[operator]
@@ -654,7 +653,8 @@ class HandoffBuilder:
Example:
.. code-block:: python
from agent_framework import ChatAgent, HandoffBuilder
from agent_framework import ChatAgent
from agent_framework_orchestrations import HandoffBuilder
def create_triage() -> ChatAgent:
@@ -710,7 +710,7 @@ class HandoffBuilder:
.. code-block:: python
from agent_framework import HandoffBuilder
from agent_framework_orchestrations import HandoffBuilder
from agent_framework.openai import OpenAIChatClient
client = OpenAIChatClient()
@@ -12,16 +12,13 @@ from dataclasses import dataclass, field
from enum import Enum
from typing import Any, ClassVar, TypeVar, cast, overload
from typing_extensions import Never
from agent_framework import (
AgentProtocol,
AgentResponse,
ChatMessage,
)
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._base_group_chat_orchestrator import (
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from agent_framework._workflows._base_group_chat_orchestrator import (
BaseGroupChatOrchestrator,
GroupChatParticipantMessage,
GroupChatRequestMessage,
@@ -29,14 +26,15 @@ from ._base_group_chat_orchestrator import (
GroupChatWorkflowContextOutT,
ParticipantRegistry,
)
from ._checkpoint import CheckpointStorage
from ._events import ExecutorEvent
from ._executor import Executor, handler
from ._model_utils import DictConvertible, encode_value
from ._request_info_mixin import response_handler
from ._workflow import Workflow
from ._workflow_builder import WorkflowBuilder
from ._workflow_context import WorkflowContext
from agent_framework._workflows._checkpoint import CheckpointStorage
from agent_framework._workflows._events import ExecutorEvent
from agent_framework._workflows._executor import Executor, handler
from agent_framework._workflows._model_utils import DictConvertible, encode_value
from agent_framework._workflows._request_info_mixin import response_handler
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_builder import WorkflowBuilder
from agent_framework._workflows._workflow_context import WorkflowContext
from typing_extensions import Never
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
@@ -42,22 +42,21 @@ from collections.abc import Callable, Sequence
from typing import Any
from agent_framework import AgentProtocol, ChatMessage
from ._agent_executor import (
from agent_framework._workflows._agent_executor import (
AgentExecutor,
AgentExecutorResponse,
)
from ._agent_utils import resolve_agent_id
from ._checkpoint import CheckpointStorage
from ._executor import (
from agent_framework._workflows._agent_utils import resolve_agent_id
from agent_framework._workflows._checkpoint import CheckpointStorage
from agent_framework._workflows._executor import (
Executor,
handler,
)
from ._message_utils import normalize_messages_input
from ._orchestration_request_info import AgentApprovalExecutor
from ._workflow import Workflow
from ._workflow_builder import WorkflowBuilder
from ._workflow_context import WorkflowContext
from agent_framework._workflows._message_utils import normalize_messages_input
from agent_framework._workflows._orchestration_request_info import AgentApprovalExecutor
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_builder import WorkflowBuilder
from agent_framework._workflows._workflow_context import WorkflowContext
logger = logging.getLogger(__name__)
@@ -122,7 +121,7 @@ class SequentialBuilder:
.. code-block:: python
from agent_framework import SequentialBuilder
from agent_framework_orchestrations import SequentialBuilder
# With agent instances
workflow = SequentialBuilder().participants([agent1, agent2, summarizer_exec]).build()
@@ -236,7 +235,7 @@ class SequentialBuilder:
Returns:
Self for fluent chaining
"""
from ._orchestration_request_info import resolve_request_info_filter
from agent_framework._workflows._orchestration_request_info import resolve_request_info_filter
self._request_info_enabled = True
self._request_info_filter = resolve_request_info_filter(list(agents) if agents else None)
@@ -0,0 +1,87 @@
[project]
name = "agent-framework-orchestrations"
description = "Orchestration patterns for Microsoft Agent Framework. Includes SequentialBuilder, ConcurrentBuilder, HandoffBuilder, GroupChatBuilder, and MagenticBuilder."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260130"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
urls.issues = "https://github.com/microsoft/agent-framework/issues"
classifiers = [
"License :: OSI Approved :: MIT License",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
]
[tool.uv]
prerelease = "if-necessary-or-explicit"
environments = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform == 'win32'"
]
[tool.uv-dynamic-versioning]
fallback-version = "0.0.0"
[tool.pytest.ini_options]
testpaths = 'tests'
addopts = "-ra -q -r fEX"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
filterwarnings = []
timeout = 120
[tool.ruff]
extend = "../../pyproject.toml"
[tool.coverage.run]
omit = [
"**/__init__.py"
]
[tool.pyright]
extends = "../../pyproject.toml"
exclude = ['tests']
[tool.mypy]
plugins = ['pydantic.mypy']
strict = true
python_version = "3.10"
ignore_missing_imports = true
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true
warn_unused_ignores = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
[tool.bandit]
targets = ["agent_framework_orchestrations"]
exclude_dirs = ["tests"]
[tool.poe]
executor.type = "uv"
include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_orchestrations"
test = "pytest --cov=agent_framework_orchestrations --cov-report=term-missing:skip-covered tests"
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
build-backend = "flit_core.buildapi"
@@ -3,14 +3,11 @@
from typing import Any, cast
import pytest
from typing_extensions import Never
from agent_framework import (
AgentExecutorRequest,
AgentExecutorResponse,
AgentResponse,
ChatMessage,
ConcurrentBuilder,
Executor,
WorkflowContext,
WorkflowOutputEvent,
@@ -19,6 +16,8 @@ from agent_framework import (
handler,
)
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework.orchestrations import ConcurrentBuilder
from typing_extensions import Never
class _FakeAgentExec(Executor):
@@ -4,7 +4,6 @@ from collections.abc import AsyncIterable, Callable, Sequence
from typing import Any, cast
import pytest
from agent_framework import (
AgentExecutorResponse,
AgentRequestInfoResponse,
@@ -18,18 +17,20 @@ from agent_framework import (
ChatResponse,
ChatResponseUpdate,
Content,
GroupChatBuilder,
GroupChatState,
MagenticContext,
MagenticManagerBase,
MagenticProgressLedger,
MagenticProgressLedgerItem,
RequestInfoEvent,
WorkflowOutputEvent,
WorkflowRunState,
WorkflowStatusEvent,
)
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework.orchestrations import (
GroupChatBuilder,
GroupChatState,
MagenticContext,
MagenticManagerBase,
MagenticProgressLedger,
MagenticProgressLedgerItem,
)
class StubAgent(BaseAgent):
@@ -1186,7 +1187,7 @@ def test_group_chat_with_orchestrator_factory_returning_base_orchestrator():
nonlocal factory_call_count
factory_call_count += 1
from agent_framework._workflows._base_group_chat_orchestrator import ParticipantRegistry
from agent_framework._workflows._group_chat import GroupChatOrchestrator
from agent_framework.orchestrations import GroupChatOrchestrator
# Create a custom orchestrator; when returning BaseGroupChatOrchestrator,
# the builder uses it as-is without modifying its participant registry
@@ -5,21 +5,19 @@ from typing import Any, cast
from unittest.mock import AsyncMock, MagicMock
import pytest
from agent_framework import (
ChatAgent,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
Content,
HandoffAgentUserRequest,
HandoffBuilder,
RequestInfoEvent,
WorkflowEvent,
WorkflowOutputEvent,
resolve_agent_id,
use_function_invocation,
)
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
@use_function_invocation
@@ -6,7 +6,6 @@ from dataclasses import dataclass
from typing import Any, ClassVar, cast
import pytest
from agent_framework import (
AgentProtocol,
AgentResponse,
@@ -17,16 +16,7 @@ from agent_framework import (
Content,
Executor,
GroupChatRequestMessage,
MagenticBuilder,
MagenticContext,
MagenticManagerBase,
MagenticOrchestrator,
MagenticOrchestratorEvent,
MagenticPlanReviewRequest,
MagenticProgressLedger,
MagenticProgressLedgerItem,
RequestInfoEvent,
StandardMagenticManager,
Workflow,
WorkflowCheckpoint,
WorkflowCheckpointException,
@@ -38,6 +28,17 @@ from agent_framework import (
handler,
)
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework.orchestrations import (
MagenticBuilder,
MagenticContext,
MagenticManagerBase,
MagenticOrchestrator,
MagenticOrchestratorEvent,
MagenticPlanReviewRequest,
MagenticProgressLedger,
MagenticProgressLedgerItem,
StandardMagenticManager,
)
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
@@ -1246,7 +1247,7 @@ def test_magentic_agent_factory_with_standard_manager_options():
custom_final_prompt = "Custom final: {task}"
# Create a custom task ledger
from agent_framework._workflows._magentic import _MagenticTaskLedger # type: ignore
from agent_framework_orchestrations._magentic import _MagenticTaskLedger # type: ignore
custom_task_ledger = _MagenticTaskLedger(
facts=ChatMessage("assistant", ["Custom facts"]),
@@ -1282,7 +1283,7 @@ def test_magentic_agent_factory_with_standard_manager_options():
manager = orchestrator._manager # type: ignore[reportPrivateUsage]
# Verify the manager is a StandardMagenticManager with the expected options
from agent_framework import StandardMagenticManager
from agent_framework.orchestrations import StandardMagenticManager
assert isinstance(manager, StandardMagenticManager)
assert manager.task_ledger is custom_task_ledger
@@ -4,7 +4,6 @@ from collections.abc import AsyncIterable
from typing import Any
import pytest
from agent_framework import (
AgentExecutorResponse,
AgentResponse,
@@ -14,7 +13,6 @@ from agent_framework import (
ChatMessage,
Content,
Executor,
SequentialBuilder,
TypeCompatibilityError,
WorkflowContext,
WorkflowOutputEvent,
@@ -23,6 +21,7 @@ from agent_framework import (
handler,
)
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework.orchestrations import SequentialBuilder
class _EchoAgent(BaseAgent):
+2
View File
@@ -104,6 +104,7 @@ agent-framework-purview = { workspace = true }
agent-framework-redis = { workspace = true }
agent-framework-github-copilot = { workspace = true }
agent-framework-claude = { workspace = true }
agent-framework-orchestrations = { workspace = true }
[tool.ruff]
line-length = 120
@@ -253,6 +254,7 @@ pytest --import-mode=importlib
--cov=agent_framework_mem0
--cov=agent_framework_purview
--cov=agent_framework_redis
--cov=agent_framework_orchestrations
--cov-config=pyproject.toml
--cov-report=term-missing:skip-covered
--ignore-glob=packages/lab/**
@@ -0,0 +1,70 @@
# Orchestration Getting Started Samples
## Installation
The orchestrations package is included when you install `agent-framework` (which pulls in all optional packages):
```bash
pip install agent-framework
```
Or install the orchestrations package directly:
```bash
pip install agent-framework-orchestrations
```
Orchestration builders are available via the `agent_framework.orchestrations` submodule:
```python
from agent_framework.orchestrations import (
SequentialBuilder,
ConcurrentBuilder,
HandoffBuilder,
GroupChatBuilder,
MagenticBuilder,
)
```
## Samples Overview
| Sample | File | Concepts |
| ------------------------------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| Concurrent Orchestration (Default Aggregator) | [concurrent_agents.py](./concurrent_agents.py) | Fan-out to multiple agents; fan-in with default aggregator returning combined ChatMessages |
| Concurrent Orchestration (Custom Aggregator) | [concurrent_custom_aggregator.py](./concurrent_custom_aggregator.py) | Override aggregator via callback; summarize results with an LLM |
| Concurrent Orchestration (Custom Agent Executors) | [concurrent_custom_agent_executors.py](./concurrent_custom_agent_executors.py) | Child executors own ChatAgents; concurrent fan-out/fan-in via ConcurrentBuilder |
| Concurrent Orchestration (Participant Factory) | [concurrent_participant_factory.py](./concurrent_participant_factory.py) | Use participant factories for state isolation between workflow instances |
| Group Chat with Agent Manager | [group_chat_agent_manager.py](./group_chat_agent_manager.py) | Agent-based manager using `with_orchestrator(agent=)` to select next speaker |
| Group Chat Philosophical Debate | [group_chat_philosophical_debate.py](./group_chat_philosophical_debate.py) | Agent manager moderates long-form, multi-round debate across diverse participants |
| Group Chat with Simple Function Selector | [group_chat_simple_selector.py](./group_chat_simple_selector.py) | Group chat with a simple function selector for next speaker |
| Handoff (Simple) | [handoff_simple.py](./handoff_simple.py) | Single-tier routing: triage agent routes to specialists, control returns to user after each specialist response |
| Handoff (Autonomous) | [handoff_autonomous.py](./handoff_autonomous.py) | Autonomous mode: specialists iterate independently until invoking a handoff tool using `.with_autonomous_mode()` |
| Handoff (Participant Factory) | [handoff_participant_factory.py](./handoff_participant_factory.py) | Use participant factories for state isolation between workflow instances |
| Handoff with Code Interpreter | [handoff_with_code_interpreter_file.py](./handoff_with_code_interpreter_file.py) | Retrieve file IDs from code interpreter output in handoff workflow |
| Magentic Workflow (Multi-Agent) | [magentic.py](./magentic.py) | Orchestrate multiple agents with Magentic manager and streaming |
| Magentic + Human Plan Review | [magentic_human_plan_review.py](./magentic_human_plan_review.py) | Human reviews/updates the plan before execution |
| Magentic + Checkpoint Resume | [magentic_checkpoint.py](./magentic_checkpoint.py) | Resume Magentic orchestration from saved checkpoints |
| Sequential Orchestration (Agents) | [sequential_agents.py](./sequential_agents.py) | Chain agents sequentially with shared conversation context |
| Sequential Orchestration (Custom Executor) | [sequential_custom_executors.py](./sequential_custom_executors.py) | Mix agents with a summarizer that appends a compact summary |
| Sequential Orchestration (Participant Factories) | [sequential_participant_factory.py](./sequential_participant_factory.py) | Use participant factories for state isolation between workflow instances |
## Tips
**Magentic checkpointing tip**: Treat `MagenticBuilder.participants` keys as stable identifiers. When resuming from a checkpoint, the rebuilt workflow must reuse the same participant names; otherwise the checkpoint cannot be applied and the run will fail fast.
**Handoff workflow tip**: Handoff workflows maintain the full conversation history including any `ChatMessage.additional_properties` emitted by your agents. This ensures routing metadata remains intact across all agent transitions. For specialist-to-specialist handoffs, use `.add_handoff(source, targets)` to configure which agents can route to which others with a fluent, type-safe API.
**Sequential orchestration note**: Sequential orchestration uses a few small adapter nodes for plumbing:
- `input-conversation` normalizes input to `list[ChatMessage]`
- `to-conversation:<participant>` converts agent responses into the shared conversation
- `complete` publishes the final `WorkflowOutputEvent`
These may appear in event streams (ExecutorInvoke/Completed). They're analogous to concurrent's dispatcher and aggregator and can be ignored if you only care about agent activity.
## Environment Variables
- **AzureOpenAIChatClient**: Set Azure OpenAI environment variables as documented [here](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/chat_client/README.md#environment-variables).
- **OpenAI** (used in some orchestration samples):
- [OpenAIChatClient env vars](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/agents/openai_chat_client/README.md)
- [OpenAIResponsesClient env vars](https://github.com/microsoft/agent-framework/blob/main/python/samples/getting_started/agents/openai_responses_client/README.md)
@@ -3,8 +3,9 @@
import asyncio
from typing import Any
from agent_framework import ChatMessage, ConcurrentBuilder
from agent_framework import ChatMessage
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import ConcurrentBuilder
from azure.identity import AzureCliCredential
"""
@@ -8,12 +8,12 @@ from agent_framework import (
AgentExecutorResponse,
ChatAgent,
ChatMessage,
ConcurrentBuilder,
Executor,
WorkflowContext,
handler,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import ConcurrentBuilder
from azure.identity import AzureCliCredential
"""
@@ -3,8 +3,9 @@
import asyncio
from typing import Any
from agent_framework import ChatMessage, ConcurrentBuilder
from agent_framework import ChatMessage
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import ConcurrentBuilder
from azure.identity import AzureCliCredential
"""
@@ -6,13 +6,13 @@ from typing import Any, Never
from agent_framework import (
ChatAgent,
ChatMessage,
ConcurrentBuilder,
Executor,
Workflow,
WorkflowContext,
handler,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import ConcurrentBuilder
from azure.identity import AzureCliCredential
"""
@@ -7,10 +7,10 @@ from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
GroupChatBuilder,
WorkflowOutputEvent,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import GroupChatBuilder
from azure.identity import AzureCliCredential
"""
@@ -4,8 +4,14 @@ import asyncio
import logging
from typing import cast
from agent_framework import AgentResponseUpdate, ChatAgent, ChatMessage, GroupChatBuilder, WorkflowOutputEvent
from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
WorkflowOutputEvent,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import GroupChatBuilder
from azure.identity import AzureCliCredential
logging.basicConfig(level=logging.WARNING)
@@ -7,11 +7,10 @@ from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
GroupChatBuilder,
GroupChatState,
WorkflowOutputEvent,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import GroupChatBuilder, GroupChatState
from azure.identity import AzureCliCredential
"""
@@ -8,13 +8,12 @@ from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
HandoffBuilder,
HandoffSentEvent,
HostedWebSearchTool,
WorkflowOutputEvent,
resolve_agent_id,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import HandoffBuilder
from azure.identity import AzureCliCredential
logging.basicConfig(level=logging.ERROR)
@@ -61,7 +60,6 @@ def create_agents(
"coordinator. Keep each individual response focused on one aspect."
),
name="research_agent",
tools=[HostedWebSearchTool()],
)
summary_agent = chat_client.as_agent(
@@ -8,9 +8,6 @@ from agent_framework import (
AgentResponse,
ChatAgent,
ChatMessage,
HandoffAgentUserRequest,
HandoffBuilder,
HandoffSentEvent,
RequestInfoEvent,
Workflow,
WorkflowEvent,
@@ -20,6 +17,7 @@ from agent_framework import (
tool,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder, HandoffSentEvent
from azure.identity import AzureCliCredential
logging.basicConfig(level=logging.ERROR)
@@ -7,9 +7,6 @@ from agent_framework import (
AgentResponse,
ChatAgent,
ChatMessage,
HandoffAgentUserRequest,
HandoffBuilder,
HandoffSentEvent,
RequestInfoEvent,
WorkflowEvent,
WorkflowOutputEvent,
@@ -18,6 +15,7 @@ from agent_framework import (
tool,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder, HandoffSentEvent
from azure.identity import AzureCliCredential
"""Sample: Simple handoff workflow.
@@ -34,8 +34,6 @@ from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
HandoffAgentUserRequest,
HandoffBuilder,
HandoffSentEvent,
HostedCodeInterpreterTool,
RequestInfoEvent,
@@ -44,6 +42,7 @@ from agent_framework import (
WorkflowRunState,
WorkflowStatusEvent,
)
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
from azure.identity.aio import AzureCliCredential
# Toggle between V1 (AzureAIAgentClient) and V2 (AzureAIClient)
@@ -11,12 +11,10 @@ from agent_framework import (
ChatMessage,
GroupChatRequestSentEvent,
HostedCodeInterpreterTool,
MagenticBuilder,
MagenticOrchestratorEvent,
MagenticProgressLedger,
WorkflowOutputEvent,
)
from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient
from agent_framework.orchestrations import MagenticBuilder, MagenticOrchestratorEvent, MagenticProgressLedger
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
@@ -9,8 +9,6 @@ from agent_framework import (
ChatAgent,
ChatMessage,
FileCheckpointStorage,
MagenticBuilder,
MagenticPlanReviewRequest,
RequestInfoEvent,
WorkflowCheckpoint,
WorkflowOutputEvent,
@@ -18,6 +16,7 @@ from agent_framework import (
WorkflowStatusEvent,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import MagenticBuilder, MagenticPlanReviewRequest
from azure.identity._credentials import AzureCliCredential
"""
@@ -9,14 +9,12 @@ from agent_framework import (
AgentResponseUpdate,
ChatAgent,
ChatMessage,
MagenticBuilder,
MagenticPlanReviewRequest,
MagenticPlanReviewResponse,
RequestInfoEvent,
WorkflowEvent,
WorkflowOutputEvent,
)
from agent_framework.openai import OpenAIChatClient
from agent_framework.orchestrations import MagenticBuilder, MagenticPlanReviewRequest, MagenticPlanReviewResponse
"""
Sample: Magentic Orchestration with Human Plan Review
@@ -3,8 +3,9 @@
import asyncio
from typing import cast
from agent_framework import ChatMessage, SequentialBuilder, WorkflowOutputEvent
from agent_framework import ChatMessage, WorkflowOutputEvent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
"""
@@ -7,11 +7,11 @@ from agent_framework import (
AgentExecutorResponse,
ChatMessage,
Executor,
SequentialBuilder,
WorkflowContext,
handler,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
"""
@@ -6,12 +6,12 @@ from agent_framework import (
ChatAgent,
ChatMessage,
Executor,
SequentialBuilder,
Workflow,
WorkflowContext,
handler,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
"""
@@ -108,31 +108,7 @@ For additional observability samples in Agent Framework, see the [observability
### orchestration
| Sample | File | Concepts |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Concurrent Orchestration (Default Aggregator) | [orchestration/concurrent_agents.py](./orchestration/concurrent_agents.py) | Fan-out to multiple agents; fan-in with default aggregator returning combined ChatMessages |
| Concurrent Orchestration (Custom Aggregator) | [orchestration/concurrent_custom_aggregator.py](./orchestration/concurrent_custom_aggregator.py) | Override aggregator via callback; summarize results with an LLM |
| Concurrent Orchestration (Custom Agent Executors) | [orchestration/concurrent_custom_agent_executors.py](./orchestration/concurrent_custom_agent_executors.py) | Child executors own ChatAgents; concurrent fan-out/fan-in via ConcurrentBuilder |
| Concurrent Orchestration (Participant Factory) | [orchestration/concurrent_participant_factory.py](./orchestration/concurrent_participant_factory.py) | Use participant factories for state isolation between workflow instances |
| Group Chat with Agent Manager | [orchestration/group_chat_agent_manager.py](./orchestration/group_chat_agent_manager.py) | Agent-based manager using `with_orchestrator(agent=)` to select next speaker |
| Group Chat Philosophical Debate | [orchestration/group_chat_philosophical_debate.py](./orchestration/group_chat_philosophical_debate.py) | Agent manager moderates long-form, multi-round debate across diverse participants |
| Group Chat with Simple Function Selector | [orchestration/group_chat_simple_selector.py](./orchestration/group_chat_simple_selector.py) | Group chat with a simple function selector for next speaker |
| Handoff (Simple) | [orchestration/handoff_simple.py](./orchestration/handoff_simple.py) | Single-tier routing: triage agent routes to specialists, control returns to user after each specialist response |
| Handoff (Autonomous) | [orchestration/handoff_autonomous.py](./orchestration/handoff_autonomous.py) | Autonomous mode: specialists iterate independently until invoking a handoff tool using `.with_autonomous_mode()` |
| Handoff (Participant Factory) | [orchestration/handoff_participant_factory.py](./orchestration/handoff_participant_factory.py) | Use participant factories for state isolation between workflow instances |
| Magentic Workflow (Multi-Agent) | [orchestration/magentic.py](./orchestration/magentic.py) | Orchestrate multiple agents with Magentic manager and streaming |
| Magentic + Human Plan Review | [orchestration/magentic_human_plan_review.py](./orchestration/magentic_human_plan_review.py) | Human reviews/updates the plan before execution |
| Magentic + Checkpoint Resume | [orchestration/magentic_checkpoint.py](./orchestration/magentic_checkpoint.py) | Resume Magentic orchestration from saved checkpoints |
| Sequential Orchestration (Agents) | [orchestration/sequential_agents.py](./orchestration/sequential_agents.py) | Chain agents sequentially with shared conversation context |
| Sequential Orchestration (Custom Executor) | [orchestration/sequential_custom_executors.py](./orchestration/sequential_custom_executors.py) | Mix agents with a summarizer that appends a compact summary |
| Sequential Orchestration (Participant Factories) | [orchestration/sequential_participant_factory.py](./orchestration/sequential_participant_factory.py) | Use participant factories for state isolation between workflow instances |
**Magentic checkpointing tip**: Treat `MagenticBuilder.participants` keys as stable identifiers. When resuming from a checkpoint, the rebuilt workflow must reuse the same participant names; otherwise the checkpoint cannot be applied and the run will fail fast.
**Handoff workflow tip**: Handoff workflows maintain the full conversation history including any
`ChatMessage.additional_properties` emitted by your agents. This ensures routing metadata remains
intact across all agent transitions. For specialist-to-specialist handoffs, use `.add_handoff(source, targets)`
to configure which agents can route to which others with a fluent, type-safe API.
Orchestration samples (Sequential, Concurrent, Handoff, GroupChat, Magentic) have moved to the dedicated [orchestrations samples directory](../orchestrations/README.md).
### parallelism
+465 -458
View File
File diff suppressed because it is too large Load Diff