chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Ignore autogen source files
|
||||
autogen
|
||||
@@ -0,0 +1,61 @@
|
||||
# AutoGen → Microsoft Agent Framework Migration Samples
|
||||
|
||||
This gallery helps AutoGen developers move to the Microsoft Agent Framework (AF) with minimal guesswork. Each script pairs AutoGen code with its AF equivalent so you can compare primitives, tooling, and orchestration patterns side by side while you migrate production workloads.
|
||||
|
||||
## What's Included
|
||||
|
||||
### Single-Agent Parity
|
||||
|
||||
- [01_basic_agent.py](single_agent/01_basic_agent.py) — Minimal AutoGen `AssistantAgent` and AF `Agent` comparison.
|
||||
- [02_agent_with_tool.py](single_agent/02_agent_with_tool.py) — Function tool integration in both SDKs.
|
||||
- [03_agent_thread_and_stream.py](single_agent/03_agent_thread_and_stream.py) — Session management and streaming responses.
|
||||
- [04_agent_as_tool.py](single_agent/04_agent_as_tool.py) — Using agents as tools (hierarchical agent pattern) and streaming with tools.
|
||||
|
||||
### Multi-Agent Orchestration
|
||||
|
||||
- [01_round_robin_group_chat.py](orchestrations/01_round_robin_group_chat.py) — AutoGen `RoundRobinGroupChat` → AF `GroupChatBuilder`/`SequentialBuilder`.
|
||||
- [02_selector_group_chat.py](orchestrations/02_selector_group_chat.py) — AutoGen `SelectorGroupChat` → AF `GroupChatBuilder`.
|
||||
- [03_swarm.py](orchestrations/03_swarm.py) — AutoGen Swarm pattern → AF `HandoffBuilder`.
|
||||
- [04_magentic_one.py](orchestrations/04_magentic_one.py) — AutoGen `MagenticOneGroupChat` → AF `MagenticBuilder`.
|
||||
|
||||
Each script is fully async and the `main()` routine runs both implementations back to back so you can observe their outputs in a single execution.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10 or later.
|
||||
- Access to the necessary model endpoints (Azure OpenAI, OpenAI, etc.).
|
||||
- Installed SDKs: Install AutoGen and the Microsoft Agent Framework with:
|
||||
```bash
|
||||
pip install "autogen-agentchat autogen-ext[openai] agent-framework"
|
||||
```
|
||||
- Service credentials exposed through environment variables (e.g., `OPENAI_API_KEY`).
|
||||
|
||||
## Running Single-Agent Samples
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
python samples/autogen-migration/single_agent/01_basic_agent.py
|
||||
```
|
||||
|
||||
Every script accepts no CLI arguments and will first call the AutoGen implementation, followed by the AF version. Adjust the prompt or credentials inside the file as necessary before running.
|
||||
|
||||
## Running Orchestration Samples
|
||||
|
||||
Advanced comparisons are in `autogen-migration/orchestrations` (RoundRobin, Selector, Swarm, Magentic). You can run them directly:
|
||||
|
||||
```bash
|
||||
python samples/autogen-migration/orchestrations/01_round_robin_group_chat.py
|
||||
python samples/autogen-migration/orchestrations/04_magentic_one.py
|
||||
```
|
||||
|
||||
## Tips for Migration
|
||||
|
||||
- **Default behavior differences**: AutoGen's `AssistantAgent` is single-turn by default (`max_tool_iterations=1`), while AF's `Agent` is multi-turn and continues tool execution automatically.
|
||||
- **Thread management**: AF agents are stateless by default. Use `agent.create_session()` and pass it to `run()` to maintain conversation state, similar to AutoGen's conversation context.
|
||||
- **Tools**: AutoGen uses `FunctionTool` wrappers; AF uses `@tool` decorators with automatic schema inference.
|
||||
- **Orchestration patterns**:
|
||||
- `RoundRobinGroupChat` → `SequentialBuilder` or `WorkflowBuilder`
|
||||
- `SelectorGroupChat` → `GroupChatBuilder` with LLM-based speaker selection
|
||||
- `Swarm` → `HandoffBuilder` for agent handoff coordination
|
||||
- `MagenticOneGroupChat` → `MagenticBuilder` for orchestrated multi-agent workflows
|
||||
@@ -0,0 +1,193 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent, Message
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen RoundRobinGroupChat vs Agent Framework GroupChatBuilder/SequentialBuilder.
|
||||
|
||||
Demonstrates sequential agent orchestration where agents take turns processing
|
||||
the task in a round-robin fashion.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen's RoundRobinGroupChat for sequential agent orchestration."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.conditions import TextMentionTermination
|
||||
from autogen_agentchat.teams import RoundRobinGroupChat
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
researcher = AssistantAgent(
|
||||
name="researcher",
|
||||
model_client=client,
|
||||
system_message="You are a researcher. Provide facts and data about the topic.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
writer = AssistantAgent(
|
||||
name="writer",
|
||||
model_client=client,
|
||||
system_message="You are a writer. Turn research into engaging content.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
editor = AssistantAgent(
|
||||
name="editor",
|
||||
model_client=client,
|
||||
system_message="You are an editor. Review and finalize the content. End with APPROVED if satisfied.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create round-robin team
|
||||
team = RoundRobinGroupChat(
|
||||
participants=[researcher, writer, editor],
|
||||
termination_condition=TextMentionTermination("APPROVED"),
|
||||
)
|
||||
|
||||
# Run the team and display the conversation.
|
||||
print("[AutoGen] Round-robin conversation:")
|
||||
await Console(team.run_stream(task="Create a brief summary about electric vehicles"))
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's SequentialBuilder for sequential agent orchestration."""
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import SequentialBuilder
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
researcher = Agent(
|
||||
client=client,
|
||||
name="researcher",
|
||||
instructions="You are a researcher. Provide facts and data about the topic.",
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
client=client,
|
||||
name="writer",
|
||||
instructions="You are a writer. Turn research into engaging content.",
|
||||
)
|
||||
|
||||
editor = Agent(
|
||||
client=client,
|
||||
name="editor",
|
||||
instructions="You are an editor. Review and finalize the content.",
|
||||
)
|
||||
|
||||
# Create sequential workflow
|
||||
workflow = SequentialBuilder(participants=[researcher, writer, editor]).build()
|
||||
|
||||
# Run the workflow
|
||||
print("[Agent Framework] Sequential conversation:")
|
||||
async for event in workflow.run("Create a brief summary about electric vehicles", stream=True):
|
||||
if event.type == "output" and isinstance(event.data, list):
|
||||
for message in event.data: # type: ignore
|
||||
if isinstance(message, Message) and message.role == "assistant" and message.text:
|
||||
print(f"---------- {message.author_name} ----------")
|
||||
print(message.text)
|
||||
|
||||
|
||||
async def run_agent_framework_with_cycle() -> None:
|
||||
"""Agent Framework's WorkflowBuilder with cyclic edges and conditional exit."""
|
||||
from agent_framework import (
|
||||
Agent,
|
||||
AgentExecutorRequest,
|
||||
AgentExecutorResponse,
|
||||
AgentResponseUpdate,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
executor,
|
||||
)
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
researcher = Agent(
|
||||
client=client,
|
||||
name="researcher",
|
||||
instructions="You are a researcher. Provide facts and data about the topic.",
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
client=client,
|
||||
name="writer",
|
||||
instructions="You are a writer. Turn research into engaging content.",
|
||||
)
|
||||
|
||||
editor = Agent(
|
||||
client=client,
|
||||
name="editor",
|
||||
instructions="You are an editor. Review and finalize the content. End with APPROVED if satisfied.",
|
||||
)
|
||||
|
||||
# Create custom executor for checking approval
|
||||
@executor
|
||||
async def check_approval(
|
||||
response: AgentExecutorResponse, context: WorkflowContext[AgentExecutorRequest, str]
|
||||
) -> None:
|
||||
assert response.full_conversation is not None
|
||||
last_message = response.full_conversation[-1]
|
||||
if last_message and "APPROVED" in last_message.text:
|
||||
await context.yield_output("Content approved.")
|
||||
else:
|
||||
await context.send_message(AgentExecutorRequest(messages=response.full_conversation, should_respond=True))
|
||||
|
||||
workflow = (
|
||||
WorkflowBuilder(start_executor=researcher)
|
||||
.add_edge(researcher, writer)
|
||||
.add_edge(writer, editor)
|
||||
.add_edge(
|
||||
editor,
|
||||
check_approval,
|
||||
)
|
||||
.add_edge(check_approval, researcher)
|
||||
.build()
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
print("[Agent Framework with Cycle] Cyclic conversation:")
|
||||
current_executor = None
|
||||
async for event in workflow.run("Create a brief summary about electric vehicles", stream=True):
|
||||
if event.type == "output" and not isinstance(event.data, AgentResponseUpdate):
|
||||
print("\n---------- Workflow Output ----------")
|
||||
print(event.data)
|
||||
elif event.type == "output" and isinstance(event.data, AgentResponseUpdate):
|
||||
# Print executor name header when switching to a new agent
|
||||
if current_executor != event.executor_id:
|
||||
if current_executor is not None:
|
||||
print() # Newline after previous agent's message
|
||||
print(f"---------- {event.executor_id} ----------")
|
||||
current_executor = event.executor_id
|
||||
if event.data:
|
||||
print(event.data.text, end="", flush=True)
|
||||
print() # Final newline after conversation
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Round-Robin / Sequential Orchestration Comparison")
|
||||
print("=" * 60)
|
||||
print("AutoGen: RoundRobinGroupChat")
|
||||
print("Agent Framework: SequentialBuilder + WorkflowBuilder with cycles\n")
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
print()
|
||||
await run_agent_framework_with_cycle()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,130 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent, Message
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen SelectorGroupChat vs Agent Framework GroupChatBuilder.
|
||||
|
||||
Demonstrates LLM-based speaker selection where an orchestrator decides
|
||||
which agent should speak next based on the conversation context.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen's SelectorGroupChat with LLM-based speaker selection."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.conditions import MaxMessageTermination
|
||||
from autogen_agentchat.teams import SelectorGroupChat
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
python_expert = AssistantAgent(
|
||||
name="python_expert",
|
||||
model_client=client,
|
||||
system_message="You are a Python programming expert. Answer Python-related questions.",
|
||||
description="Expert in Python programming",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
javascript_expert = AssistantAgent(
|
||||
name="javascript_expert",
|
||||
model_client=client,
|
||||
system_message="You are a JavaScript programming expert. Answer JavaScript-related questions.",
|
||||
description="Expert in JavaScript programming",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
database_expert = AssistantAgent(
|
||||
name="database_expert",
|
||||
model_client=client,
|
||||
system_message="You are a database expert. Answer SQL and database-related questions.",
|
||||
description="Expert in databases and SQL",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create selector group chat - LLM selects appropriate expert
|
||||
team = SelectorGroupChat(
|
||||
participants=[python_expert, javascript_expert, database_expert],
|
||||
model_client=client,
|
||||
termination_condition=MaxMessageTermination(2),
|
||||
selector_prompt="Based on the conversation so far:\n{history}\n, "
|
||||
"select the most appropriate expert from {roles} to respond next.",
|
||||
)
|
||||
|
||||
# Run with a question that requires expert selection
|
||||
print("[AutoGen] Selector group chat conversation:")
|
||||
await Console(team.run_stream(task="How do I connect to a PostgreSQL database using Python?"))
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's GroupChatBuilder with LLM-based speaker selection."""
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import GroupChatBuilder
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
python_expert = Agent(
|
||||
client=client,
|
||||
name="python_expert",
|
||||
instructions="You are a Python programming expert. Answer Python-related questions.",
|
||||
description="Expert in Python programming",
|
||||
)
|
||||
|
||||
javascript_expert = Agent(
|
||||
client=client,
|
||||
name="javascript_expert",
|
||||
instructions="You are a JavaScript programming expert. Answer JavaScript-related questions.",
|
||||
description="Expert in JavaScript programming",
|
||||
)
|
||||
|
||||
database_expert = Agent(
|
||||
client=client,
|
||||
name="database_expert",
|
||||
instructions="You are a database expert. Answer SQL and database-related questions.",
|
||||
description="Expert in databases and SQL",
|
||||
)
|
||||
|
||||
workflow = GroupChatBuilder(
|
||||
participants=[python_expert, javascript_expert, database_expert],
|
||||
max_rounds=1,
|
||||
orchestrator_agent=Agent(
|
||||
client=client,
|
||||
name="selector_manager",
|
||||
instructions="Based on the conversation, select the most appropriate expert to respond next.",
|
||||
),
|
||||
).build()
|
||||
|
||||
# Run with a question that requires expert selection
|
||||
print("[Agent Framework] Group chat conversation:")
|
||||
async for event in workflow.run("How do I connect to a PostgreSQL database using Python?", stream=True):
|
||||
if event.type == "output" and isinstance(event.data, list):
|
||||
for message in event.data: # type: ignore
|
||||
if isinstance(message, Message) and message.role == "assistant" and message.text:
|
||||
print(f"---------- {message.author_name} ----------")
|
||||
print(message.text)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Selector Group Chat Comparison")
|
||||
print("=" * 60)
|
||||
print("AutoGen: SelectorGroupChat")
|
||||
print("Agent Framework: GroupChatBuilder with standard_manager\n")
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,251 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Agent, AgentResponseUpdate, WorkflowEvent
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen Swarm pattern vs Agent Framework HandoffBuilder.
|
||||
|
||||
Demonstrates agent handoff coordination where agents can transfer control
|
||||
to other specialized agents based on the task requirements.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen's Swarm pattern with human-in-the-loop handoffs."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.conditions import HandoffTermination, TextMentionTermination
|
||||
from autogen_agentchat.messages import HandoffMessage
|
||||
from autogen_agentchat.teams import Swarm
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create triage agent that routes to specialists
|
||||
triage_agent = AssistantAgent(
|
||||
name="triage",
|
||||
model_client=client,
|
||||
system_message=(
|
||||
"You are a triage agent. Analyze the user's request and hand off to the appropriate specialist.\n"
|
||||
"If you need information from the user, first send your message, then handoff to user.\n"
|
||||
"Use TERMINATE when the issue is fully resolved."
|
||||
),
|
||||
handoffs=["billing_agent", "technical_support", "user"],
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create billing specialist
|
||||
billing_agent = AssistantAgent(
|
||||
name="billing_agent",
|
||||
model_client=client,
|
||||
system_message=(
|
||||
"You are a billing specialist. Help with payment and billing questions.\n"
|
||||
"If you need information from the user, first send your message, then handoff to user.\n"
|
||||
"When the issue is resolved, handoff to triage to finalize."
|
||||
),
|
||||
handoffs=["triage", "user"],
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create technical support specialist
|
||||
tech_support = AssistantAgent(
|
||||
name="technical_support",
|
||||
model_client=client,
|
||||
system_message=(
|
||||
"You are technical support. Help with technical issues.\n"
|
||||
"If you need information from the user, first send your message, then handoff to user.\n"
|
||||
"When the issue is resolved, handoff to triage to finalize."
|
||||
),
|
||||
handoffs=["triage", "user"],
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create swarm team with human-in-the-loop termination
|
||||
termination = HandoffTermination(target="user") | TextMentionTermination("TERMINATE")
|
||||
team = Swarm(
|
||||
participants=[triage_agent, billing_agent, tech_support],
|
||||
termination_condition=termination,
|
||||
)
|
||||
|
||||
# Scripted user responses for demonstration
|
||||
scripted_responses = [
|
||||
"I was charged twice for my subscription",
|
||||
"Yes, the charge of $49.99 appears twice on my credit card statement.",
|
||||
"Thank you for your help!",
|
||||
]
|
||||
response_index = 0
|
||||
|
||||
# Run with human-in-the-loop pattern
|
||||
print("[AutoGen] Swarm handoff conversation:")
|
||||
task_result = await Console(team.run_stream(task=scripted_responses[response_index]))
|
||||
last_message = task_result.messages[-1]
|
||||
response_index += 1
|
||||
|
||||
# Continue conversation when agents handoff to user
|
||||
while (
|
||||
isinstance(last_message, HandoffMessage)
|
||||
and last_message.target == "user"
|
||||
and response_index < len(scripted_responses)
|
||||
):
|
||||
user_message = scripted_responses[response_index]
|
||||
task_result = await Console(
|
||||
team.run_stream(task=HandoffMessage(source="user", target=last_message.source, content=user_message))
|
||||
)
|
||||
last_message = task_result.messages[-1]
|
||||
response_index += 1
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's HandoffBuilder for agent coordination."""
|
||||
from agent_framework import (
|
||||
WorkflowRunState,
|
||||
)
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create triage agent
|
||||
triage_agent = Agent(
|
||||
client=client,
|
||||
name="triage",
|
||||
instructions=(
|
||||
"You are a triage agent. Analyze the user's request and route to the appropriate specialist:\n"
|
||||
"- For billing issues: call handoff_to_billing_agent\n"
|
||||
"- For technical issues: call handoff_to_technical_support"
|
||||
),
|
||||
description="Routes requests to appropriate specialists",
|
||||
require_per_service_call_history_persistence=True,
|
||||
)
|
||||
|
||||
# Create billing specialist
|
||||
billing_agent = Agent(
|
||||
client=client,
|
||||
name="billing_agent",
|
||||
instructions="You are a billing specialist. Help with payment and billing questions. Provide clear assistance.",
|
||||
description="Handles billing and payment questions",
|
||||
require_per_service_call_history_persistence=True,
|
||||
)
|
||||
|
||||
# Create technical support specialist
|
||||
tech_support = Agent(
|
||||
client=client,
|
||||
name="technical_support",
|
||||
instructions="You are technical support. Help with technical issues. Provide clear assistance.",
|
||||
description="Handles technical support questions",
|
||||
require_per_service_call_history_persistence=True,
|
||||
)
|
||||
|
||||
# Create handoff workflow - simpler configuration
|
||||
# After specialists respond, control returns to user (via triage as coordinator)
|
||||
workflow = (
|
||||
HandoffBuilder(
|
||||
name="support_handoff",
|
||||
participants=[triage_agent, billing_agent, tech_support],
|
||||
termination_condition=lambda conv: sum(1 for msg in conv if msg.role == "user") > 3,
|
||||
)
|
||||
.with_start_agent(triage_agent)
|
||||
.add_handoff(triage_agent, [billing_agent, tech_support])
|
||||
.build()
|
||||
)
|
||||
|
||||
# Scripted user responses
|
||||
scripted_responses = [
|
||||
"I was charged twice for my subscription",
|
||||
"Yes, the charge of $49.99 appears twice on my credit card statement.",
|
||||
"Thank you for your help!",
|
||||
]
|
||||
|
||||
# Run with initial message
|
||||
print("[Agent Framework] Handoff conversation:")
|
||||
print("---------- user ----------")
|
||||
print(scripted_responses[0])
|
||||
|
||||
current_executor = None
|
||||
stream_line_open = False
|
||||
pending_requests: list[WorkflowEvent] = []
|
||||
|
||||
async for event in workflow.run(scripted_responses[0], stream=True):
|
||||
if event.type == "output" and isinstance(event.data, AgentResponseUpdate):
|
||||
# Print executor name header when switching to a new agent
|
||||
if current_executor != event.executor_id:
|
||||
if stream_line_open:
|
||||
print()
|
||||
stream_line_open = False
|
||||
print(f"---------- {event.executor_id} ----------")
|
||||
current_executor = event.executor_id
|
||||
stream_line_open = True
|
||||
if event.data:
|
||||
print(event.data.text, end="", flush=True)
|
||||
elif event.type == "request_info":
|
||||
if isinstance(event.data, HandoffAgentUserRequest):
|
||||
pending_requests.append(event)
|
||||
elif event.type == "status":
|
||||
if event.state in {WorkflowRunState.IDLE_WITH_PENDING_REQUESTS} and stream_line_open:
|
||||
print()
|
||||
stream_line_open = False
|
||||
|
||||
# Process scripted responses
|
||||
response_index = 1
|
||||
while pending_requests and response_index < len(scripted_responses):
|
||||
user_response = scripted_responses[response_index]
|
||||
print("---------- user ----------")
|
||||
print(user_response)
|
||||
|
||||
responses: dict[str, Any] = {
|
||||
req.request_id: HandoffAgentUserRequest.create_response(user_response) for req in pending_requests
|
||||
} # type: ignore
|
||||
pending_requests = []
|
||||
current_executor = None
|
||||
stream_line_open = False
|
||||
|
||||
async for event in workflow.run(stream=True, responses=responses):
|
||||
if event.type == "output" and isinstance(event.data, AgentResponseUpdate):
|
||||
# Print executor name header when switching to a new agent
|
||||
if current_executor != event.executor_id:
|
||||
if stream_line_open:
|
||||
print()
|
||||
stream_line_open = False
|
||||
print(f"---------- {event.executor_id} ----------")
|
||||
current_executor = event.executor_id
|
||||
stream_line_open = True
|
||||
if event.data:
|
||||
print(event.data.text, end="", flush=True)
|
||||
elif event.type == "request_info":
|
||||
if isinstance(event.data, HandoffAgentUserRequest):
|
||||
pending_requests.append(event)
|
||||
elif event.type == "status":
|
||||
if (
|
||||
event.state in {WorkflowRunState.IDLE_WITH_PENDING_REQUESTS, WorkflowRunState.IDLE}
|
||||
and stream_line_open
|
||||
):
|
||||
print()
|
||||
stream_line_open = False
|
||||
|
||||
response_index += 1
|
||||
|
||||
if stream_line_open:
|
||||
print()
|
||||
print() # Final newline after conversation
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Swarm / Handoff Pattern Comparison")
|
||||
print("=" * 60)
|
||||
print("AutoGen: Swarm with handoffs")
|
||||
print("Agent Framework: HandoffBuilder\n")
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,172 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from typing import cast
|
||||
|
||||
from agent_framework import (
|
||||
Agent,
|
||||
AgentResponseUpdate,
|
||||
Message,
|
||||
WorkflowEvent,
|
||||
)
|
||||
from agent_framework.orchestrations import MagenticProgressLedger
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen MagenticOneGroupChat vs Agent Framework MagenticBuilder.
|
||||
|
||||
Demonstrates orchestrated multi-agent workflows with a central coordinator
|
||||
managing specialized agents for complex tasks.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen's MagenticOneGroupChat for orchestrated collaboration."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.teams import MagenticOneGroupChat
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
researcher = AssistantAgent(
|
||||
name="researcher",
|
||||
model_client=client,
|
||||
system_message="You are a research analyst. Gather and analyze information.",
|
||||
description="Research analyst for data gathering",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
coder = AssistantAgent(
|
||||
name="coder",
|
||||
model_client=client,
|
||||
system_message="You are a programmer. Write code based on requirements.",
|
||||
description="Software developer for implementation",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
reviewer = AssistantAgent(
|
||||
name="reviewer",
|
||||
model_client=client,
|
||||
system_message="You are a code reviewer. Review code for quality and correctness.",
|
||||
description="Code reviewer for quality assurance",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Create MagenticOne team with coordinator
|
||||
team = MagenticOneGroupChat(
|
||||
participants=[researcher, coder, reviewer],
|
||||
model_client=client, # Coordinator uses this client
|
||||
max_turns=20,
|
||||
max_stalls=3,
|
||||
)
|
||||
|
||||
# Run complex task and display the conversation
|
||||
print("[AutoGen] Magentic One conversation:")
|
||||
await Console(team.run_stream(task="Research Python async patterns and write a simple example"))
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's MagenticBuilder for orchestrated collaboration."""
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import MagenticBuilder
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized agents
|
||||
researcher = Agent(
|
||||
client=client,
|
||||
name="researcher",
|
||||
instructions="You are a research analyst. Gather and analyze information.",
|
||||
description="Research analyst for data gathering",
|
||||
)
|
||||
|
||||
coder = Agent(
|
||||
client=client,
|
||||
name="coder",
|
||||
instructions="You are a programmer. Write code based on requirements.",
|
||||
description="Software developer for implementation",
|
||||
)
|
||||
|
||||
reviewer = Agent(
|
||||
client=client,
|
||||
name="reviewer",
|
||||
instructions="You are a code reviewer. Review code for quality and correctness.",
|
||||
description="Code reviewer for quality assurance",
|
||||
)
|
||||
|
||||
# Create Magentic workflow
|
||||
workflow = MagenticBuilder(
|
||||
participants=[researcher, coder, reviewer],
|
||||
manager_agent=Agent(
|
||||
client=client,
|
||||
name="magentic_manager",
|
||||
instructions="You coordinate a team to complete complex tasks efficiently.",
|
||||
description="Orchestrator for team coordination",
|
||||
),
|
||||
max_round_count=20,
|
||||
max_stall_count=3,
|
||||
max_reset_count=1,
|
||||
).build()
|
||||
|
||||
# Run complex task
|
||||
last_message_id: str | None = None
|
||||
output_event: WorkflowEvent | None = None
|
||||
print("[Agent Framework] Magentic conversation:")
|
||||
async for event in workflow.run("Research Python async patterns and write a simple example", stream=True):
|
||||
if event.type == "output" and isinstance(event.data, AgentResponseUpdate):
|
||||
message_id = event.data.message_id
|
||||
if message_id != last_message_id:
|
||||
if last_message_id is not None:
|
||||
print("\n")
|
||||
print(f"- {event.executor_id}:", end=" ", flush=True)
|
||||
last_message_id = message_id
|
||||
print(event.data, end="", flush=True)
|
||||
|
||||
elif event.type == "magentic_orchestrator":
|
||||
print(f"\n[Magentic Orchestrator Event] Type: {event.data.event_type.name}")
|
||||
if isinstance(event.data.content, Message):
|
||||
print(f"Please review the plan:\n{event.data.content.text}")
|
||||
elif isinstance(event.data.content, MagenticProgressLedger):
|
||||
print(f"Please review progress ledger:\n{json.dumps(event.data.content.to_dict(), indent=2)}")
|
||||
else:
|
||||
print(f"Unknown data type in MagenticOrchestratorEvent: {type(event.data.content)}")
|
||||
|
||||
# Block to allow user to read the plan/progress before continuing
|
||||
# Note: this is for demonstration only and is not the recommended way to handle human interaction.
|
||||
# Please refer to `with_plan_review` for proper human interaction during planning phases.
|
||||
await asyncio.get_event_loop().run_in_executor(None, input, "Press Enter to continue...")
|
||||
|
||||
elif event.type == "output":
|
||||
output_event = event
|
||||
|
||||
if not output_event:
|
||||
raise RuntimeError("Workflow did not produce a final output event.")
|
||||
print("\n\nWorkflow completed!")
|
||||
print("Final Output:")
|
||||
# The output of the Magentic workflow is a list of ChatMessages with only one final message
|
||||
# generated by the orchestrator.
|
||||
output_messages = cast(list[Message], output_event.data)
|
||||
if output_messages:
|
||||
output = output_messages[-1].text
|
||||
print(output)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Magentic One Orchestration Comparison")
|
||||
print("=" * 60)
|
||||
print("AutoGen: MagenticOneGroupChat")
|
||||
print("Agent Framework: MagenticBuilder\n")
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"exclude": [
|
||||
"autogen"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
# /// script
|
||||
# requires-python = ">=3.10"
|
||||
# dependencies = [
|
||||
# "agent-framework-openai",
|
||||
# "autogen-agentchat",
|
||||
# "autogen-ext[openai]",
|
||||
# ]
|
||||
# ///
|
||||
# Run with any PEP 723 compatible runner, e.g.:
|
||||
# uv run samples/autogen-migration/single_agent/01_basic_assistant_agent.py
|
||||
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""Basic AutoGen AssistantAgent vs Agent Framework Agent.
|
||||
|
||||
Both samples expect OpenAI-compatible environment variables (OPENAI_API_KEY or
|
||||
Azure OpenAI configuration). Update the prompts or client wiring to match your
|
||||
model of choice before running.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""Call AutoGen's AssistantAgent for a simple question."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
# AutoGen agent with OpenAI model client
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
agent = AssistantAgent(
|
||||
name="assistant",
|
||||
model_client=client,
|
||||
system_message="You are a helpful assistant. Answer in one sentence.",
|
||||
)
|
||||
|
||||
# Run the agent (AutoGen maintains conversation state internally)
|
||||
result = await agent.run(task="What is the capital of France?")
|
||||
print("[AutoGen]", result.messages[-1].to_text())
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Call Agent Framework's Agent created from OpenAIChatClient."""
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
# AF constructs a lightweight Agent backed by OpenAIChatClient
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="assistant",
|
||||
instructions="You are a helpful assistant. Answer in one sentence.",
|
||||
)
|
||||
|
||||
# Run the agent (AF agents are stateless by default)
|
||||
result = await agent.run("What is the capital of France?")
|
||||
print("[Agent Framework]", result.text)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Basic Assistant Agent Comparison")
|
||||
print("=" * 60)
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,98 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen AssistantAgent vs Agent Framework Agent with function tools.
|
||||
|
||||
Demonstrates how to create and attach tools to agents in both frameworks.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen agent with a FunctionTool."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_core.tools import FunctionTool
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
# Define a simple tool function
|
||||
def get_weather(location: str) -> str:
|
||||
"""Get the weather for a location.
|
||||
|
||||
Args:
|
||||
location: The city name or location.
|
||||
|
||||
Returns:
|
||||
A weather description.
|
||||
"""
|
||||
return f"The weather in {location} is sunny and 72°F."
|
||||
|
||||
# Wrap function in FunctionTool
|
||||
weather_tool = FunctionTool(
|
||||
func=get_weather,
|
||||
description="Get weather information for a location",
|
||||
)
|
||||
|
||||
# Create agent with tool
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
agent = AssistantAgent(
|
||||
name="assistant",
|
||||
model_client=client,
|
||||
tools=[weather_tool],
|
||||
system_message="You are a helpful assistant. Use available tools to answer questions.",
|
||||
)
|
||||
|
||||
# Run with tool usage
|
||||
result = await agent.run(task="What's the weather in Seattle?")
|
||||
print("[AutoGen]", result.messages[-1].to_text())
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework agent with @tool decorator."""
|
||||
from agent_framework import Agent, tool
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
# Define tool with @tool decorator (automatic schema inference)
|
||||
# NOTE: approval_mode="never_require" is for sample brevity.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(location: str) -> str:
|
||||
"""Get the weather for a location.
|
||||
|
||||
Args:
|
||||
location: The city name or location.
|
||||
|
||||
Returns:
|
||||
A weather description.
|
||||
"""
|
||||
return f"The weather in {location} is sunny and 72°F."
|
||||
|
||||
# Create agent with tool
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="assistant",
|
||||
instructions="You are a helpful assistant. Use available tools to answer questions.",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
# Run with tool usage
|
||||
result = await agent.run("What's the weather in Seattle?")
|
||||
print("[Agent Framework]", result.text)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Assistant Agent with Tools Comparison")
|
||||
print("=" * 60)
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,99 @@
|
||||
# /// script
|
||||
# requires-python = ">=3.10"
|
||||
# dependencies = [
|
||||
# "agent-framework-openai",
|
||||
# "autogen-agentchat",
|
||||
# "autogen-ext[openai]",
|
||||
# ]
|
||||
# ///
|
||||
# Run with any PEP 723 compatible runner, e.g.:
|
||||
# uv run samples/autogen-migration/single_agent/03_assistant_agent_thread_and_stream.py
|
||||
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen vs Agent Framework: Thread management and streaming responses.
|
||||
|
||||
Demonstrates conversation state management and streaming in both frameworks.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen agent with conversation history and streaming."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
agent = AssistantAgent(
|
||||
name="assistant",
|
||||
model_client=client,
|
||||
system_message="You are a helpful math tutor.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
print("[AutoGen] Conversation with history:")
|
||||
# First turn - AutoGen maintains state internally with Console for streaming
|
||||
result = await agent.run(task="What is 15 + 27?")
|
||||
print(f" Q1: {result.messages[-1].to_text()}")
|
||||
|
||||
# Second turn - agent remembers context
|
||||
result = await agent.run(task="What about that number times 2?")
|
||||
print(f" Q2: {result.messages[-1].to_text()}")
|
||||
|
||||
print("\n[AutoGen] Streaming response:")
|
||||
# Stream response with Console for token streaming
|
||||
await Console(agent.run_stream(task="Count from 1 to 5"))
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework agent with explicit session and streaming."""
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="assistant",
|
||||
instructions="You are a helpful math tutor.",
|
||||
)
|
||||
|
||||
print("[Agent Framework] Conversation with session:")
|
||||
# Create a session to maintain state
|
||||
session = agent.create_session()
|
||||
|
||||
# First turn - pass session to maintain history
|
||||
result1 = await agent.run("What is 15 + 27?", session=session)
|
||||
print(f" Q1: {result1.text}")
|
||||
|
||||
# Second turn - agent remembers context via session
|
||||
result2 = await agent.run("What about that number times 2?", session=session)
|
||||
print(f" Q2: {result2.text}")
|
||||
|
||||
print("\n[Agent Framework] Streaming response:")
|
||||
# Stream response
|
||||
print(" ", end="")
|
||||
async for chunk in agent.run("Count from 1 to 5", session=session, stream=True):
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
print()
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Thread Management and Streaming Comparison")
|
||||
print("=" * 60)
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,140 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""AutoGen vs Agent Framework: Agent-as-a-Tool pattern.
|
||||
|
||||
Demonstrates hierarchical agent architectures where one agent delegates
|
||||
work to specialized sub-agents wrapped as tools.
|
||||
"""
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
"""AutoGen's AgentTool for hierarchical agents with streaming."""
|
||||
|
||||
from autogen_agentchat.agents import AssistantAgent
|
||||
from autogen_agentchat.tools import AgentTool
|
||||
from autogen_agentchat.ui import Console
|
||||
from autogen_ext.models.openai import OpenAIChatCompletionClient
|
||||
|
||||
# Create a specialized writer agent
|
||||
writer_client = OpenAIChatCompletionClient(model="gpt-4.1-mini")
|
||||
writer = AssistantAgent(
|
||||
name="writer",
|
||||
model_client=writer_client,
|
||||
system_message="You are a creative writer. Write short, engaging content.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Wrap writer agent as a tool (description is taken from agent.description)
|
||||
writer_tool = AgentTool(agent=writer)
|
||||
|
||||
# Create coordinator agent with writer as a tool
|
||||
# IMPORTANT: Disable parallel_tool_calls when using AgentTool
|
||||
coordinator_client = OpenAIChatCompletionClient(
|
||||
model="gpt-4.1-mini",
|
||||
parallel_tool_calls=False,
|
||||
)
|
||||
coordinator = AssistantAgent(
|
||||
name="coordinator",
|
||||
model_client=coordinator_client,
|
||||
tools=[writer_tool],
|
||||
system_message="You coordinate with specialized agents. Delegate writing tasks to the writer agent.",
|
||||
model_client_stream=True,
|
||||
)
|
||||
|
||||
# Run coordinator with streaming - it will delegate to writer
|
||||
print("[AutoGen]")
|
||||
await Console(coordinator.run_stream(task="Create a tagline for a coffee shop"))
|
||||
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's as_tool() for hierarchical agents with streaming."""
|
||||
from agent_framework import Agent, Content
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
client = OpenAIChatClient(model="gpt-4.1-mini")
|
||||
|
||||
# Create specialized writer agent
|
||||
writer = Agent(
|
||||
client=client,
|
||||
name="writer",
|
||||
instructions="You are a creative writer. Write short, engaging content.",
|
||||
)
|
||||
|
||||
# Convert writer to a tool using as_tool()
|
||||
writer_tool = writer.as_tool(
|
||||
name="creative_writer",
|
||||
description="Generate creative content",
|
||||
arg_name="request",
|
||||
arg_description="What to write",
|
||||
)
|
||||
|
||||
# Create coordinator agent with writer tool
|
||||
coordinator = Agent(
|
||||
client=client,
|
||||
name="coordinator",
|
||||
instructions="You coordinate with specialized agents. Delegate writing tasks to the writer agent.",
|
||||
tools=[writer_tool],
|
||||
)
|
||||
|
||||
# Run coordinator with streaming - it will delegate to writer
|
||||
print("[Agent Framework]")
|
||||
|
||||
# Track accumulated function calls (they stream in incrementally)
|
||||
accumulated_calls: dict[str, Content] = {}
|
||||
|
||||
async for chunk in coordinator.run("Create a tagline for a coffee shop", stream=True):
|
||||
# Stream text tokens
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
|
||||
# Process streaming function calls and results
|
||||
if chunk.contents:
|
||||
for content in chunk.contents:
|
||||
if content.type == "function_call":
|
||||
# Accumulate function call content as it streams in
|
||||
call_id = content.call_id
|
||||
assert call_id is not None, "Function call content must have a call_id"
|
||||
if call_id in accumulated_calls:
|
||||
# Add to existing call (arguments stream in gradually)
|
||||
accumulated_calls[call_id] = accumulated_calls[call_id] + content
|
||||
else:
|
||||
# First chunk of this function call
|
||||
accumulated_calls[call_id] = content
|
||||
print("\n[Function Call - streaming]", flush=True)
|
||||
print(f" Call ID: {call_id}", flush=True)
|
||||
print(f" Name: {content.name}", flush=True)
|
||||
|
||||
# Show accumulated arguments so far
|
||||
current_args = accumulated_calls[call_id].arguments
|
||||
print(f" Arguments: {current_args}", flush=True)
|
||||
|
||||
elif content.type == "function_result":
|
||||
# Tool result - shows writer's response
|
||||
result_text = content.result if isinstance(content.result, str) else str(content.result)
|
||||
if result_text.strip():
|
||||
print("\n[Function Result]", flush=True)
|
||||
print(f" Call ID: {content.call_id}", flush=True)
|
||||
print(f" Result: {result_text[:150]}{'...' if len(result_text) > 150 else ''}", flush=True)
|
||||
print()
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=" * 60)
|
||||
print("Agent-as-Tool Pattern Comparison")
|
||||
print("=" * 60)
|
||||
print("Note: AutoGen requires parallel_tool_calls=False for AgentTool")
|
||||
print(" Agent Framework handles this automatically\n")
|
||||
await run_autogen()
|
||||
print()
|
||||
await run_agent_framework()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user