From 6fa8e880bed6593d2c837f08c72e18701034a620 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 26 Feb 2026 11:11:08 +0900 Subject: [PATCH 1/2] Update workflow orchestration samples to use AzureOpenAIResponsesClient --- python/samples/03-workflows/README.md | 8 ++++++ .../agent_to_function_tool/main.py | 11 +++++--- .../declarative/function_tools/README.md | 8 ++++-- .../03-workflows/orchestrations/README.md | 4 +++ .../orchestrations/concurrent_agents.py | 15 ++++++++--- .../concurrent_custom_agent_executors.py | 21 ++++++++++----- .../concurrent_custom_aggregator.py | 15 ++++++++--- .../group_chat_agent_manager.py | 15 ++++++++--- .../group_chat_philosophical_debate.py | 15 ++++++++--- .../group_chat_simple_selector.py | 15 ++++++++--- .../orchestrations/handoff_autonomous.py | 16 +++++++---- .../orchestrations/handoff_simple.py | 20 +++++++++----- .../03-workflows/orchestrations/magentic.py | 24 +++++++++++------ .../orchestrations/magentic_checkpoint.py | 27 ++++++++++++++----- .../magentic_human_plan_review.py | 20 ++++++++++---- .../orchestrations/sequential_agents.py | 13 ++++++--- .../sequential_custom_executors.py | 13 ++++++--- 17 files changed, 191 insertions(+), 69 deletions(-) diff --git a/python/samples/03-workflows/README.md b/python/samples/03-workflows/README.md index c5abe202ac..4dfdd68157 100644 --- a/python/samples/03-workflows/README.md +++ b/python/samples/03-workflows/README.md @@ -160,6 +160,14 @@ Sequential orchestration uses a few small adapter nodes for plumbing: These may appear in event streams (executor_invoked/executor_completed). They're analogous to concurrent’s dispatcher and aggregator and can be ignored if you only care about agent activity. +### AzureOpenAIResponsesClient vs AzureAIAgent + +Workflow and orchestration samples use `AzureOpenAIResponsesClient` rather than the CRUD-style `AzureAIAgent` client. The key difference: + +- **`AzureOpenAIResponsesClient`** — A lightweight client that uses the underlying Agent Service V2 (Responses API) for non-CRUD-style agents. Orchestrations use this client because agents are created locally and do not require server-side lifecycle management (create/update/delete). This is the recommended client for orchestration patterns (Sequential, Concurrent, Handoff, GroupChat, Magentic). + +- **`AzureAIAgent`** — A CRUD-style client for server-managed agents. Use this when you need persistent, server-side agent definitions with features like file search, code interpreter sessions, or thread management provided by the Azure AI Agent Service. + ### Environment Variables Workflow samples that use `AzureOpenAIResponsesClient` expect: diff --git a/python/samples/03-workflows/declarative/agent_to_function_tool/main.py b/python/samples/03-workflows/declarative/agent_to_function_tool/main.py index 55ba77c073..d4346d826e 100644 --- a/python/samples/03-workflows/declarative/agent_to_function_tool/main.py +++ b/python/samples/03-workflows/declarative/agent_to_function_tool/main.py @@ -18,10 +18,11 @@ """ import asyncio +import os from pathlib import Path from typing import Any -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.declarative import WorkflowFactory from azure.identity import AzureCliCredential from pydantic import BaseModel, Field @@ -196,8 +197,12 @@ def format_order_confirmation(order_data: dict[str, Any], order_calculation: dic async def main(): """Run the agent to function tool workflow.""" - # Create Azure OpenAI client - chat_client = AzureOpenAIChatClient(credential=AzureCliCredential()) + # Create Azure OpenAI Responses client + chat_client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) # Create the order analysis agent with structured output order_analysis_agent = chat_client.as_agent( diff --git a/python/samples/03-workflows/declarative/function_tools/README.md b/python/samples/03-workflows/declarative/function_tools/README.md index 78e7cf361e..e831ba51d7 100644 --- a/python/samples/03-workflows/declarative/function_tools/README.md +++ b/python/samples/03-workflows/declarative/function_tools/README.md @@ -6,7 +6,7 @@ This sample demonstrates an agent with function tools responding to user queries The workflow showcases: - **Function Tools**: Agent equipped with tools to query menu data -- **Real Azure OpenAI Agent**: Uses `AzureOpenAIChatClient` to create an agent with tools +- **Real Azure OpenAI Agent**: Uses `AzureOpenAIResponsesClient` to create an agent with tools - **Agent Registration**: Shows how to register agents with the `WorkflowFactory` ## Tools @@ -72,7 +72,11 @@ Session Complete ```python # Create the agent with tools -client = AzureOpenAIChatClient(credential=AzureCliCredential()) +client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), +) menu_agent = client.as_agent( name="MenuAgent", instructions="You are a helpful restaurant menu assistant...", diff --git a/python/samples/03-workflows/orchestrations/README.md b/python/samples/03-workflows/orchestrations/README.md index 3ce85cd1ab..527a414295 100644 --- a/python/samples/03-workflows/orchestrations/README.md +++ b/python/samples/03-workflows/orchestrations/README.md @@ -92,6 +92,10 @@ from agent_framework.orchestrations import ( These may appear in event streams (executor_invoked/executor_completed). They're analogous to concurrent's dispatcher and aggregator and can be ignored if you only care about agent activity. +## Why AzureOpenAIResponsesClient? + +Orchestration samples use `AzureOpenAIResponsesClient` rather than the CRUD-style `AzureAIAgent` client. Orchestrations create agents locally and do not require server-side lifecycle management (create/update/delete). `AzureOpenAIResponsesClient` is a lightweight client that uses the underlying Agent Service V2 (Responses API) for non-CRUD-style agents, which is ideal for orchestration patterns like Sequential, Concurrent, Handoff, GroupChat, and Magentic. + ## Environment Variables Orchestration samples that use `AzureOpenAIResponsesClient` expect: diff --git a/python/samples/03-workflows/orchestrations/concurrent_agents.py b/python/samples/03-workflows/orchestrations/concurrent_agents.py index f6aae589a6..78e56b38bf 100644 --- a/python/samples/03-workflows/orchestrations/concurrent_agents.py +++ b/python/samples/03-workflows/orchestrations/concurrent_agents.py @@ -1,10 +1,11 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import Any from agent_framework import Message -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import ConcurrentBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -26,14 +27,20 @@ - Workflow completion when idle with no pending work Prerequisites: -- Azure OpenAI access configured for AzureOpenAIChatClient (use az login + env vars) +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. - Familiarity with Workflow events (WorkflowEvent) """ async def main() -> None: - # 1) Create three domain agents using AzureOpenAIChatClient - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + # 1) Create three domain agents using AzureOpenAIResponsesClient + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) researcher = client.as_agent( instructions=( diff --git a/python/samples/03-workflows/orchestrations/concurrent_custom_agent_executors.py b/python/samples/03-workflows/orchestrations/concurrent_custom_agent_executors.py index 82df710435..3e0a9b63c6 100644 --- a/python/samples/03-workflows/orchestrations/concurrent_custom_agent_executors.py +++ b/python/samples/03-workflows/orchestrations/concurrent_custom_agent_executors.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import Any from agent_framework import ( @@ -12,7 +13,7 @@ WorkflowContext, handler, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import ConcurrentBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -29,21 +30,23 @@ ConcurrentBuilder API and the default aggregator. Demonstrates: -- Executors that create their Agent in __init__ (via AzureOpenAIChatClient) +- Executors that create their Agent in __init__ (via AzureOpenAIResponsesClient) - A @handler that converts AgentExecutorRequest -> AgentExecutorResponse - ConcurrentBuilder(participants=[...]) to build fan-out/fan-in - Default aggregator returning list[Message] (one user + one assistant per agent) - Workflow completion when all participants become idle Prerequisites: -- Azure OpenAI configured for AzureOpenAIChatClient (az login + required env vars) +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ class ResearcherExec(Executor): agent: Agent - def __init__(self, client: AzureOpenAIChatClient, id: str = "researcher"): + def __init__(self, client: AzureOpenAIResponsesClient, id: str = "researcher"): self.agent = client.as_agent( instructions=( "You're an expert market and product researcher. Given a prompt, provide concise, factual insights," @@ -63,7 +66,7 @@ async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExe class MarketerExec(Executor): agent: Agent - def __init__(self, client: AzureOpenAIChatClient, id: str = "marketer"): + def __init__(self, client: AzureOpenAIResponsesClient, id: str = "marketer"): self.agent = client.as_agent( instructions=( "You're a creative marketing strategist. Craft compelling value propositions and target messaging" @@ -83,7 +86,7 @@ async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExe class LegalExec(Executor): agent: Agent - def __init__(self, client: AzureOpenAIChatClient, id: str = "legal"): + def __init__(self, client: AzureOpenAIResponsesClient, id: str = "legal"): self.agent = client.as_agent( instructions=( "You're a cautious legal/compliance reviewer. Highlight constraints, disclaimers, and policy concerns" @@ -101,7 +104,11 @@ async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExe async def main() -> None: - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) researcher = ResearcherExec(client) marketer = MarketerExec(client) diff --git a/python/samples/03-workflows/orchestrations/concurrent_custom_aggregator.py b/python/samples/03-workflows/orchestrations/concurrent_custom_aggregator.py index 3014a0e3cf..b622e0f6b7 100644 --- a/python/samples/03-workflows/orchestrations/concurrent_custom_aggregator.py +++ b/python/samples/03-workflows/orchestrations/concurrent_custom_aggregator.py @@ -1,10 +1,11 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import Any from agent_framework import Message -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import ConcurrentBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -17,7 +18,7 @@ Build a concurrent workflow with ConcurrentBuilder that fans out one prompt to multiple domain agents and fans in their responses. Override the default -aggregator with a custom async callback that uses AzureOpenAIChatClient.get_response() +aggregator with a custom async callback that uses AzureOpenAIResponsesClient.get_response() to synthesize a concise, consolidated summary from the experts' outputs. The workflow completes when all participants become idle. @@ -28,12 +29,18 @@ - Workflow output yielded with the synthesized summary string Prerequisites: -- Azure OpenAI configured for AzureOpenAIChatClient (az login + required env vars) +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ async def main() -> None: - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) researcher = client.as_agent( instructions=( diff --git a/python/samples/03-workflows/orchestrations/group_chat_agent_manager.py b/python/samples/03-workflows/orchestrations/group_chat_agent_manager.py index d057756160..2fecc34282 100644 --- a/python/samples/03-workflows/orchestrations/group_chat_agent_manager.py +++ b/python/samples/03-workflows/orchestrations/group_chat_agent_manager.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import cast from agent_framework import ( @@ -8,7 +9,7 @@ AgentResponseUpdate, Message, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import GroupChatBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -25,7 +26,9 @@ - Coordinates a researcher and writer agent to solve tasks collaboratively Prerequisites: -- OpenAI environment variables configured for OpenAIChatClient +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ ORCHESTRATOR_AGENT_INSTRUCTIONS = """ @@ -39,8 +42,12 @@ async def main() -> None: - # Create a chat client using Azure OpenAI and Azure CLI credentials for all agents - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + # Create a Responses client using Azure OpenAI and Azure CLI credentials for all agents + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) # Orchestrator agent that manages the conversation # Note: This agent (and the underlying chat client) must support structured outputs. diff --git a/python/samples/03-workflows/orchestrations/group_chat_philosophical_debate.py b/python/samples/03-workflows/orchestrations/group_chat_philosophical_debate.py index 5e55fe9204..a8dd2aebfe 100644 --- a/python/samples/03-workflows/orchestrations/group_chat_philosophical_debate.py +++ b/python/samples/03-workflows/orchestrations/group_chat_philosophical_debate.py @@ -2,6 +2,7 @@ import asyncio import logging +import os from typing import cast from agent_framework import ( @@ -9,7 +10,7 @@ AgentResponseUpdate, Message, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import GroupChatBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -38,15 +39,21 @@ - Doctor from Scandinavia (public health, equity, societal support) Prerequisites: -- OpenAI environment variables configured for OpenAIChatClient +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ # Load environment variables from .env file load_dotenv() -def _get_chat_client() -> AzureOpenAIChatClient: - return AzureOpenAIChatClient(credential=AzureCliCredential()) +def _get_chat_client() -> AzureOpenAIResponsesClient: + return AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) async def main() -> None: diff --git a/python/samples/03-workflows/orchestrations/group_chat_simple_selector.py b/python/samples/03-workflows/orchestrations/group_chat_simple_selector.py index cf9b6aa8ec..984b46c6a4 100644 --- a/python/samples/03-workflows/orchestrations/group_chat_simple_selector.py +++ b/python/samples/03-workflows/orchestrations/group_chat_simple_selector.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import cast from agent_framework import ( @@ -8,7 +9,7 @@ AgentResponseUpdate, Message, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import GroupChatBuilder, GroupChatState from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -24,7 +25,9 @@ - Uses a pure Python function to control speaker selection based on conversation state Prerequisites: -- OpenAI environment variables configured for OpenAIChatClient +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ @@ -36,8 +39,12 @@ def round_robin_selector(state: GroupChatState) -> str: async def main() -> None: - # Create a chat client using Azure OpenAI and Azure CLI credentials for all agents - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + # Create a Responses client using Azure OpenAI and Azure CLI credentials for all agents + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) # Participant agents expert = Agent( diff --git a/python/samples/03-workflows/orchestrations/handoff_autonomous.py b/python/samples/03-workflows/orchestrations/handoff_autonomous.py index d97006df12..7b86e73cf8 100644 --- a/python/samples/03-workflows/orchestrations/handoff_autonomous.py +++ b/python/samples/03-workflows/orchestrations/handoff_autonomous.py @@ -2,6 +2,7 @@ import asyncio import logging +import os from typing import cast from agent_framework import ( @@ -10,7 +11,7 @@ Message, resolve_agent_id, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import HandoffBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -28,8 +29,9 @@ User -> Coordinator -> Specialist (iterates N times) -> Handoff -> Final Output Prerequisites: - - `az login` (Azure CLI authentication) - - Environment variables for AzureOpenAIChatClient (AZURE_OPENAI_ENDPOINT, etc.) + - AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. + - Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. + - Authentication via azure-identity. Use AzureCliCredential and run `az login` before executing the sample. Key Concepts: - Autonomous interaction mode: agents iterate until they handoff @@ -41,7 +43,7 @@ def create_agents( - client: AzureOpenAIChatClient, + client: AzureOpenAIResponsesClient, ) -> tuple[Agent, Agent, Agent]: """Create coordinator and specialists for autonomous iteration.""" coordinator = client.as_agent( @@ -77,7 +79,11 @@ def create_agents( async def main() -> None: """Run an autonomous handoff workflow with specialist iteration enabled.""" - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) coordinator, research_agent, summary_agent = create_agents(client) # Build the workflow with autonomous mode diff --git a/python/samples/03-workflows/orchestrations/handoff_simple.py b/python/samples/03-workflows/orchestrations/handoff_simple.py index 5a2319d4d2..1b4820ccbe 100644 --- a/python/samples/03-workflows/orchestrations/handoff_simple.py +++ b/python/samples/03-workflows/orchestrations/handoff_simple.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import Annotated, cast from agent_framework import ( @@ -11,7 +12,7 @@ WorkflowRunState, tool, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -25,8 +26,9 @@ them to transfer control to each other based on the conversation context. Prerequisites: - - `az login` (Azure CLI authentication) - - Environment variables configured for AzureOpenAIChatClient (AZURE_OPENAI_ENDPOINT, etc.) + - AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. + - Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. + - Authentication via azure-identity. Use AzureCliCredential and run `az login` before executing the sample. Key Concepts: - Auto-registered handoff tools: HandoffBuilder automatically creates handoff tools @@ -58,11 +60,11 @@ def process_return(order_number: Annotated[str, "Order number to process return return f"Return initiated successfully for order {order_number}. You will receive return instructions via email." -def create_agents(client: AzureOpenAIChatClient) -> tuple[Agent, Agent, Agent, Agent]: +def create_agents(client: AzureOpenAIResponsesClient) -> tuple[Agent, Agent, Agent, Agent]: """Create and configure the triage and specialist agents. Args: - client: The AzureOpenAIChatClient to use for creating agents. + client: The AzureOpenAIResponsesClient to use for creating agents. Returns: Tuple of (triage_agent, refund_agent, order_agent, return_agent) @@ -192,8 +194,12 @@ async def main() -> None: the demo reproducible and testable. In a production application, you would replace the scripted_responses with actual user input collection. """ - # Initialize the Azure OpenAI chat client - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + # Initialize the Azure OpenAI Responses client + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) # Create all agents: triage + specialists triage, refund, order, support = create_agents(client) diff --git a/python/samples/03-workflows/orchestrations/magentic.py b/python/samples/03-workflows/orchestrations/magentic.py index 2420b74245..b412fd0b9d 100644 --- a/python/samples/03-workflows/orchestrations/magentic.py +++ b/python/samples/03-workflows/orchestrations/magentic.py @@ -3,6 +3,7 @@ import asyncio import json import logging +import os from typing import cast from agent_framework import ( @@ -11,8 +12,9 @@ Message, WorkflowEvent, ) -from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import GroupChatRequestSentEvent, MagenticBuilder, MagenticProgressLedger +from azure.identity import AzureCliCredential from dotenv import load_dotenv logging.basicConfig(level=logging.WARNING) @@ -40,7 +42,9 @@ events, and prints the final answer. The workflow completes when idle. Prerequisites: -- OpenAI credentials configured for `OpenAIChatClient` and `OpenAIResponsesClient`. +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ # Load environment variables from .env file @@ -48,25 +52,29 @@ async def main() -> None: + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) + researcher_agent = Agent( name="ResearcherAgent", description="Specialist in research and information gathering", instructions=( "You are a Researcher. You find information without additional computation or quantitative analysis." ), - # This agent requires the gpt-4o-search-preview model to perform web searches. - client=OpenAIChatClient(model_id="gpt-4o-search-preview"), + client=client, ) # Create code interpreter tool using instance method - coder_client = OpenAIResponsesClient() - code_interpreter_tool = coder_client.get_code_interpreter_tool() + code_interpreter_tool = client.get_code_interpreter_tool() coder_agent = Agent( name="CoderAgent", description="A helpful assistant that writes and executes code to process and analyze data.", instructions="You solve questions using code. Please provide detailed analysis and computation process.", - client=coder_client, + client=client, tools=code_interpreter_tool, ) @@ -75,7 +83,7 @@ async def main() -> None: name="MagenticManager", description="Orchestrator that coordinates the research and coding workflow", instructions="You coordinate a team to complete complex tasks efficiently.", - client=OpenAIChatClient(), + client=client, ) print("\nBuilding Magentic Workflow...") diff --git a/python/samples/03-workflows/orchestrations/magentic_checkpoint.py b/python/samples/03-workflows/orchestrations/magentic_checkpoint.py index 940e47759f..ab3da11c1d 100644 --- a/python/samples/03-workflows/orchestrations/magentic_checkpoint.py +++ b/python/samples/03-workflows/orchestrations/magentic_checkpoint.py @@ -2,6 +2,7 @@ import asyncio import json +import os from datetime import datetime from pathlib import Path from typing import cast @@ -14,9 +15,9 @@ WorkflowEvent, WorkflowRunState, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import MagenticBuilder, MagenticPlanReviewRequest -from azure.identity._credentials import AzureCliCredential +from azure.identity import AzureCliCredential from dotenv import load_dotenv # Load environment variables from .env file @@ -38,7 +39,9 @@ `responses` mapping so we can inject the stored human reply during restoration. Prerequisites: -- OpenAI environment variables configured for `OpenAIChatClient`. +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ TASK = ( @@ -61,14 +64,22 @@ def build_workflow(checkpoint_storage: FileCheckpointStorage): name="ResearcherAgent", description="Collects background facts and references for the project.", instructions=("You are the research lead. Gather crisp bullet points the team should know."), - client=AzureOpenAIChatClient(credential=AzureCliCredential()), + client=AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ), ) writer = Agent( name="WriterAgent", description="Synthesizes the final brief for stakeholders.", instructions=("You convert the research notes into a structured brief with milestones and risks."), - client=AzureOpenAIChatClient(credential=AzureCliCredential()), + client=AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ), ) # Create a manager agent for orchestration @@ -76,7 +87,11 @@ def build_workflow(checkpoint_storage: FileCheckpointStorage): name="MagenticManager", description="Orchestrator that coordinates the research and writing workflow", instructions="You coordinate a team to complete complex tasks efficiently.", - client=AzureOpenAIChatClient(credential=AzureCliCredential()), + client=AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ), ) # The builder wires in the Magentic orchestrator, sets the plan review path, and diff --git a/python/samples/03-workflows/orchestrations/magentic_human_plan_review.py b/python/samples/03-workflows/orchestrations/magentic_human_plan_review.py index d9234026aa..61f1cd412d 100644 --- a/python/samples/03-workflows/orchestrations/magentic_human_plan_review.py +++ b/python/samples/03-workflows/orchestrations/magentic_human_plan_review.py @@ -2,6 +2,7 @@ import asyncio import json +import os from collections.abc import AsyncIterable from typing import cast @@ -11,8 +12,9 @@ Message, WorkflowEvent, ) -from agent_framework.openai import OpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import MagenticBuilder, MagenticPlanReviewRequest, MagenticPlanReviewResponse +from azure.identity import AzureCliCredential from dotenv import load_dotenv # Load environment variables from .env file @@ -35,7 +37,9 @@ - revise(feedback): Provide textual feedback to modify the plan Prerequisites: -- OpenAI credentials configured for `OpenAIChatClient`. +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ # Keep track of the last response to format output nicely in streaming mode @@ -96,25 +100,31 @@ async def process_event_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str async def main() -> None: + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) + researcher_agent = Agent( name="ResearcherAgent", description="Specialist in research and information gathering", instructions="You are a Researcher. You find information and gather facts.", - client=OpenAIChatClient(model_id="gpt-4o"), + client=client, ) analyst_agent = Agent( name="AnalystAgent", description="Data analyst who processes and summarizes research findings", instructions="You are an Analyst. You analyze findings and create summaries.", - client=OpenAIChatClient(model_id="gpt-4o"), + client=client, ) manager_agent = Agent( name="MagenticManager", description="Orchestrator that coordinates the workflow", instructions="You coordinate a team to complete tasks efficiently.", - client=OpenAIChatClient(model_id="gpt-4o"), + client=client, ) print("\nBuilding Magentic Workflow with Human Plan Review...") diff --git a/python/samples/03-workflows/orchestrations/sequential_agents.py b/python/samples/03-workflows/orchestrations/sequential_agents.py index 6eda11ece9..916ecbee9c 100644 --- a/python/samples/03-workflows/orchestrations/sequential_agents.py +++ b/python/samples/03-workflows/orchestrations/sequential_agents.py @@ -1,10 +1,11 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import cast from agent_framework import Message -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import SequentialBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -28,13 +29,19 @@ You can safely ignore them when focusing on agent progress. Prerequisites: -- Azure OpenAI access configured for AzureOpenAIChatClient (use az login + env vars) +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ async def main() -> None: # 1) Create agents - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) writer = client.as_agent( instructions=("You are a concise copywriter. Provide a single, punchy marketing sentence based on the prompt."), diff --git a/python/samples/03-workflows/orchestrations/sequential_custom_executors.py b/python/samples/03-workflows/orchestrations/sequential_custom_executors.py index 56308d2b5f..b46971cffe 100644 --- a/python/samples/03-workflows/orchestrations/sequential_custom_executors.py +++ b/python/samples/03-workflows/orchestrations/sequential_custom_executors.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import os from typing import Any from agent_framework import ( @@ -10,7 +11,7 @@ WorkflowContext, handler, ) -from agent_framework.azure import AzureOpenAIChatClient +from agent_framework.azure import AzureOpenAIResponsesClient from agent_framework.orchestrations import SequentialBuilder from azure.identity import AzureCliCredential from dotenv import load_dotenv @@ -32,7 +33,9 @@ - Emit the updated conversation via ctx.send_message([...]) Prerequisites: -- Azure OpenAI access configured for AzureOpenAIChatClient (use az login + env vars) +- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint. +- Azure OpenAI configured for AzureOpenAIResponsesClient with required environment variables. +- Authentication via azure-identity. Use AzureCliCredential and run az login before executing the sample. """ @@ -62,7 +65,11 @@ async def summarize(self, agent_response: AgentExecutorResponse, ctx: WorkflowCo async def main() -> None: # 1) Create a content agent - client = AzureOpenAIChatClient(credential=AzureCliCredential()) + client = AzureOpenAIResponsesClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=AzureCliCredential(), + ) content = client.as_agent( instructions="Produce a concise paragraph answering the user's request.", name="content", From 5c61c13b10147ce5ba1910b51e991880fc95e0c1 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 26 Feb 2026 12:19:47 +0900 Subject: [PATCH 2/2] Fix broken link --- docs/decisions/0001-agent-run-response.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/0001-agent-run-response.md b/docs/decisions/0001-agent-run-response.md index 6f3385e1a1..fb4a962802 100644 --- a/docs/decisions/0001-agent-run-response.md +++ b/docs/decisions/0001-agent-run-response.md @@ -498,7 +498,7 @@ We need to decide what AIContent types, each agent response type will be mapped | Google ADK | **Approach 1** Both [input and output schemas can be specified for LLM Agents](https://google.github.io/adk-docs/agents/llm-agents/#structuring-data-input_schema-output_schema-output_key) at construction time. This option is specific to this agent type and other agent types do not necessarily support | | AWS (Strands) | **Approach 2** Supports a special invocation method called [structured_output](https://strandsagents.com/latest/documentation/docs/api-reference/python/agent/agent/#strands.agent.agent.Agent.structured_output) | | LangGraph | **Approach 1** Supports [configuring an agent](https://langchain-ai.github.io/langgraph/agents/agents/?h=structured#6-configure-structured-output) at agent construction time, and a [structured response](https://langchain-ai.github.io/langgraph/agents/run_agents/#output-format) can be retrieved as a special property on the agent response | -| Agno | **Approach 1** Supports [configuring an agent](https://docs.agno.com/examples/getting-started/structured-output) at agent construction time | +| Agno | **Approach 1** Supports [configuring an agent](https://docs.agno.com/input-output/structured-output/agent) at agent construction time | | A2A | **Informal Approach 2** Doesn't formally support schema negotiation, but [hints can be provided via metadata](https://a2a-protocol.org/latest/specification/#97-structured-data-exchange-requesting-and-providing-json) at invocation time | | Protocol Activity | Supports returning [Complex types](https://github.com/microsoft/Agents/blob/main/specs/activity/protocol-activity.md#complex-types) but no support for requesting a type |