Python: [BREAKING] Python: Provider-leading client design & OpenAI package extraction (#4818)

* Python: Provider-leading client design & OpenAI package extraction

Major refactoring of the Python Agent Framework client architecture:

- Extract OpenAI clients into new `agent-framework-openai` package
- Core package no longer depends on openai, azure-identity, azure-ai-projects
- Rename clients for discoverability: OpenAIResponsesClient → OpenAIChatClient,
  OpenAIChatClient → OpenAIChatCompletionClient
- Unify `model_id`/`deployment_name`/`model_deployment_name` → `model` param
- New FoundryChatClient for Azure AI Foundry Responses API
- New FoundryAgent/FoundryAgentClient for connecting to pre-configured Foundry agents
- Remove OpenAIBase/OpenAIConfigMixin from non-deprecated client MRO
- Deprecate AzureOpenAI* clients, AzureAIClient, OpenAIAssistantsClient
- Reorganize samples: azure_openai+azure_ai+azure_ai_agent → azure/
- ADR-0020: Provider-Leading Client Design

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: missing Agent imports in samples, .model_id → .model in foundry_local sample

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: CI failures — mypy errors, coverage targets, sample imports

- azure-ai mypy: add type ignores for TypedDict total=, model arg, forward ref
- Coverage: replace core.azure/openai targets with openai package target
- project_provider: add type annotation for opts dict

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: populate openai .pyi stub, fix broken README links, coverage targets

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fixes

* updated observabilitty

* reset azure init.pyi

* fix errors

* updated adr number

* fix foundry local

* fixed not renamed docstrings and comments, and added deprecated markers to old classes

* fix tests and pyprojects

* fix test vars

* updated function tests

* update durable

* updated test setup for functions

* Fix Foundry auth in workflow samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Stabilize Python integration workflows

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update hosting samples for Foundry

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Trigger full CI rerun

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Trigger CI rerun again

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* trigger rerun

* trigger rerun

* fix for litellm

* undo durabletask changes

* Move Foundry APIs into foundry namespace

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix Foundry pyproject formatting

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Split provider samples by Foundry surface

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Restore hosting sample requirements

Also fix the Foundry Local sample link after the provider sample move.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* updated tests

* udpated foundry integration tests

* removed dist from azurefunctions tests

* Use separate Foundry clients for concurrent agents

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix client setup in azfunc and durable

* disabled two tests

* updated setup for some function and durable tests

* improved azure openai setup with new clients

* ignore deprecated

* fixes

* skip 11

* remove openai assistants int tests

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-03-25 09:56:29 +00:00
committed by GitHub
co-authored by Copilot
parent 4b533608b6
commit 5e056b672e
485 changed files with 9784 additions and 12084 deletions
@@ -29,7 +29,7 @@ import uvicorn
# Agent Framework imports
from agent_framework import Agent, AgentResponseUpdate, FunctionResultContent, Message, Role, tool
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.foundry import FoundryChatClient
# Agent Framework ChatKit integration
from agent_framework_chatkit import ThreadItemConverter, stream_agent_response
@@ -222,7 +222,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
# For authentication, run `az login` command in terminal
try:
self.weather_agent = Agent(
client=AzureOpenAIChatClient(credential=AzureCliCredential()),
client=FoundryChatClient(credential=AzureCliCredential()),
instructions=(
"You are a helpful weather assistant with image analysis capabilities. "
"You can provide weather information for any location, tell the current time, "
@@ -15,8 +15,8 @@ import json
import os
from typing import Any
from agent_framework import Message
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework import Agent, Message
from agent_framework.foundry import FoundryChatClient
from azure.ai.evaluation.red_team import AttackStrategy, RedTeam, RiskCategory
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
@@ -52,7 +52,8 @@ async def main() -> None:
# Create the agent
# Constructor automatically reads from environment variables:
# AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_DEPLOYMENT_NAME, AZURE_OPENAI_API_KEY
agent = AzureOpenAIChatClient(credential=credential).as_agent(
agent = Agent(
client=FoundryChatClient(credential=credential),
name="FinancialAdvisor",
instructions="""You are a professional financial advisor assistant.
@@ -98,7 +99,7 @@ Your boundaries:
# Create RedTeam instance
red_team = RedTeam(
azure_ai_project=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
azure_ai_project=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=credential,
risk_categories=[
RiskCategory.Violence,
@@ -20,7 +20,7 @@ from typing import Any
import openai
import pandas as pd
from agent_framework import Agent, Message
from agent_framework.azure import AzureOpenAIResponsesClient
from agent_framework.foundry import FoundryChatClient
from azure.ai.projects import AIProjectClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
@@ -87,7 +87,7 @@ DEFAULT_JUDGE_MODEL = "gpt-5.2"
def create_openai_client():
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
credential = AzureCliCredential()
project_client = AIProjectClient(endpoint=endpoint, credential=credential)
return project_client.get_openai_client()
@@ -97,7 +97,7 @@ def create_async_project_client():
from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient
from azure.identity.aio import AzureCliCredential as AsyncAzureCliCredential
return AsyncAIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=AsyncAzureCliCredential())
return AsyncAIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=AsyncAzureCliCredential())
def create_eval(client: openai.OpenAI, judge_model: str) -> openai.types.EvalCreateResponse:
@@ -321,9 +321,9 @@ async def run_self_reflection_batch(
load_dotenv(override=True)
# Create agent, it loads environment variables AZURE_OPENAI_API_KEY and AZURE_OPENAI_ENDPOINT automatically
responses_client = AzureOpenAIResponsesClient(
responses_client = FoundryChatClient(
project_client=project_client,
deployment_name=agent_model,
model=agent_model,
)
# Load input data
@@ -368,7 +368,7 @@ async def run_self_reflection_batch(
try:
result = await execute_query_with_self_reflection(
client=client,
agent=responses_client.as_agent(instructions=row["system_instruction"]),
agent=Agent(client=responses_client, instructions=row["system_instruction"]),
eval_object=eval_object,
full_user_query=row["full_prompt"],
context=row["context_document"],
@@ -1,8 +1,9 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.agentframework import from_agent_framework # pyright: ignore[reportUnknownVariableType]
from azure.identity import DefaultAzureCredential
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
@@ -16,14 +17,13 @@ def main():
"server_label": "Microsoft_Learn_MCP",
"server_url": "https://learn.microsoft.com/api/mcp",
}
# Create an Agent using the Azure OpenAI Chat Client with a MCP Tool that connects to Microsoft Learn MCP
agent = AzureOpenAIChatClient(credential=DefaultAzureCredential()).as_agent(
agent = Agent(
client=FoundryChatClient(credential=AzureCliCredential()),
name="DocsAgent",
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
tools=mcp_tool,
)
# Run the agent as a hosted agent
from_agent_framework(agent).run()
@@ -11,18 +11,14 @@ import os
from datetime import datetime
from typing import Annotated
from agent_framework.azure import AzureOpenAIResponsesClient
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.agentframework import from_agent_framework
from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential
from dotenv import load_dotenv
load_dotenv(override=True)
# Configure these for your Foundry project
# Read the explicit variables present in the .env file
PROJECT_ENDPOINT = os.getenv(
"PROJECT_ENDPOINT"
) # e.g., "https://<project>.services.ai.azure.com"
PROJECT_ENDPOINT = os.getenv("PROJECT_ENDPOINT") # e.g., "https://<project>.services.ai.azure.com"
MODEL_DEPLOYMENT_NAME = os.getenv(
"MODEL_DEPLOYMENT_NAME", "gpt-4.1-mini"
) # Your model deployment name e.g., "gpt-4.1-mini"
@@ -90,14 +86,10 @@ def get_available_hotels(
nights = (check_out - check_in).days
# Filter hotels by price
available_hotels = [
hotel for hotel in SEATTLE_HOTELS if hotel["price_per_night"] <= max_price
]
available_hotels = [hotel for hotel in SEATTLE_HOTELS if hotel["price_per_night"] <= max_price]
if not available_hotels:
return (
f"No hotels found in Seattle within your budget of ${max_price}/night."
)
return f"No hotels found in Seattle within your budget of ${max_price}/night."
# Build response
result = f"Available hotels in Seattle from {check_in_date} to {check_out_date} ({nights} nights):\n\n"
@@ -117,22 +109,19 @@ def get_available_hotels(
def get_credential():
"""Will use Managed Identity when running in Azure, otherwise falls back to Azure CLI Credential."""
return (
ManagedIdentityCredential()
if os.getenv("MSI_ENDPOINT")
else AzureCliCredential()
)
return ManagedIdentityCredential() if os.getenv("MSI_ENDPOINT") else AzureCliCredential()
async def main():
"""Main function to run the agent as a web server."""
async with get_credential() as credential:
client = AzureOpenAIResponsesClient(
client = FoundryChatClient(
project_endpoint=PROJECT_ENDPOINT,
deployment_name=MODEL_DEPLOYMENT_NAME,
model=MODEL_DEPLOYMENT_NAME,
credential=credential,
)
agent = client.as_agent(
agent = Agent(
client=client,
name="SeattleHotelAgent",
instructions="""You are a helpful travel assistant specializing in finding hotels in Seattle, Washington.
@@ -1,2 +1,2 @@
azure-ai-agentserver-agentframework==1.0.0b16
agent-framework-azure-ai
agent-framework-foundry
@@ -5,8 +5,8 @@ import sys
from dataclasses import dataclass
from typing import Any
from agent_framework import AgentSession, BaseContextProvider, Message, SessionContext
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework import Agent, AgentSession, BaseContextProvider, Message, SessionContext
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.agentframework import from_agent_framework # pyright: ignore[reportUnknownVariableType]
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
@@ -105,7 +105,8 @@ class TextSearchContextProvider(BaseContextProvider):
def main():
# Create an Agent using the Azure OpenAI Chat Client
agent = AzureOpenAIChatClient(credential=DefaultAzureCredential()).as_agent(
agent = Agent(
client=FoundryChatClient(credential=DefaultAzureCredential()),
name="SupportSpecialist",
instructions=(
"You are a helpful support specialist for Contoso Outdoors. "
@@ -1,6 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_orchestrations import ConcurrentBuilder
from azure.ai.agentserver.agentframework import from_agent_framework
from azure.identity import DefaultAzureCredential # pyright: ignore[reportUnknownVariableType]
@@ -12,21 +13,24 @@ load_dotenv()
def main():
# Create agents
researcher = AzureOpenAIChatClient(credential=DefaultAzureCredential()).as_agent(
researcher = Agent(
client=FoundryChatClient(credential=DefaultAzureCredential()),
instructions=(
"You're an expert market and product researcher. "
"Given a prompt, provide concise, factual insights, opportunities, and risks."
),
name="researcher",
)
marketer = AzureOpenAIChatClient(credential=DefaultAzureCredential()).as_agent(
marketer = Agent(
client=FoundryChatClient(credential=DefaultAzureCredential()),
instructions=(
"You're a creative marketing strategist. "
"Craft compelling value propositions and target messaging aligned to the prompt."
),
name="marketer",
)
legal = AzureOpenAIChatClient(credential=DefaultAzureCredential()).as_agent(
legal = Agent(
client=FoundryChatClient(credential=DefaultAzureCredential()),
instructions=(
"You're a cautious legal/compliance reviewer. "
"Highlight constraints, disclaimers, and policy concerns based on the prompt."
@@ -38,7 +42,7 @@ def main():
workflow = ConcurrentBuilder(participants=[researcher, marketer, legal]).build()
# Convert the workflow to an agent
workflow_agent = workflow.as_agent()
workflow_agent = Agent(client=workflow)
# Run the agent as a hosted agent
from_agent_framework(workflow_agent).run()
@@ -4,8 +4,8 @@ import asyncio
import os
from contextlib import asynccontextmanager
from agent_framework import WorkflowBuilder
from agent_framework.azure import AzureOpenAIResponsesClient
from agent_framework import Agent, WorkflowBuilder
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.agentframework import from_agent_framework
from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential
from dotenv import load_dotenv
@@ -24,26 +24,24 @@ MODEL_DEPLOYMENT_NAME = os.getenv(
def get_credential():
"""Will use Managed Identity when running in Azure, otherwise falls back to Azure CLI Credential."""
return (
ManagedIdentityCredential()
if os.getenv("MSI_ENDPOINT")
else AzureCliCredential()
)
return ManagedIdentityCredential() if os.getenv("MSI_ENDPOINT") else AzureCliCredential()
@asynccontextmanager
async def create_agents():
async with get_credential() as credential:
client = AzureOpenAIResponsesClient(
client = FoundryChatClient(
project_endpoint=PROJECT_ENDPOINT,
deployment_name=MODEL_DEPLOYMENT_NAME,
model=MODEL_DEPLOYMENT_NAME,
credential=credential,
)
writer = client.as_agent(
writer = Agent(
client=client,
name="Writer",
instructions="You are an excellent content writer. You create new content and edit contents based on the feedback.",
)
reviewer = client.as_agent(
reviewer = Agent(
client=client,
name="Reviewer",
instructions="You are an excellent content reviewer. Provide actionable feedback to the writer about the provided content in the most concise manner possible.",
)
@@ -52,7 +50,9 @@ async def create_agents():
def create_workflow(writer, reviewer):
workflow = WorkflowBuilder(start_executor=writer).add_edge(writer, reviewer).build()
return workflow.as_agent()
return Agent(
client=workflow,
)
async def main() -> None:
@@ -1,2 +1,2 @@
azure-ai-agentserver-agentframework==1.0.0b16
agent-framework-azure-ai
agent-framework-foundry
@@ -19,7 +19,7 @@ from random import randint
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from agent_framework.foundry import FoundryChatClient
from aiohttp import web
from aiohttp.web_middlewares import middleware
from dotenv import load_dotenv
@@ -101,8 +101,9 @@ def get_weather(
def build_agent() -> Agent:
"""Create and return the chat agent instance with weather tool registered."""
return OpenAIChatClient().as_agent(
name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather
_client = FoundryChatClient()
return Agent(
client=_client, name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather
)
@@ -26,7 +26,7 @@ import os
from typing import Any
from agent_framework import Agent, AgentResponse, Message
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.foundry import FoundryChatClient
from agent_framework.microsoft import (
PurviewChatPolicyMiddleware,
PurviewPolicyMiddleware,
@@ -145,7 +145,7 @@ async def run_with_agent_middleware() -> None:
deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini")
user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID")
client = AzureOpenAIChatClient(deployment_name=deployment, endpoint=endpoint, credential=AzureCliCredential())
client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential())
purview_agent_middleware = PurviewPolicyMiddleware(
build_credential(),
@@ -182,8 +182,8 @@ async def run_with_chat_middleware() -> None:
deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", default="gpt-4o-mini")
user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID")
client = AzureOpenAIChatClient(
deployment_name=deployment,
client = FoundryChatClient(
model=deployment,
endpoint=endpoint,
credential=AzureCliCredential(),
middleware=[
@@ -231,7 +231,7 @@ async def run_with_custom_cache_provider() -> None:
deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini")
user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID")
client = AzureOpenAIChatClient(deployment_name=deployment, endpoint=endpoint, credential=AzureCliCredential())
client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential())
custom_cache = SimpleDictCacheProvider()
@@ -271,7 +271,7 @@ async def run_with_custom_cache_provider() -> None:
deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini")
user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID")
client = AzureOpenAIChatClient(deployment_name=deployment, endpoint=endpoint, credential=AzureCliCredential())
client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential())
# No cache_provider specified - uses default InMemoryCacheProvider
purview_agent_middleware = PurviewPolicyMiddleware(
@@ -46,6 +46,7 @@ from _tools import (
validate_payment_method,
)
from agent_framework import (
Agent,
AgentExecutorResponse,
AgentResponseUpdate,
Executor,
@@ -56,7 +57,7 @@ from agent_framework import (
executor,
handler,
)
from agent_framework.azure import AzureOpenAIResponsesClient
from agent_framework.foundry import FoundryChatClient
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import DefaultAzureCredential
from dotenv import load_dotenv
@@ -74,9 +75,10 @@ async def start_executor(input: str, ctx: WorkflowContext[list[Message]]) -> Non
class ResearchLead(Executor):
"""Aggregates and summarizes travel planning findings from all specialized agents."""
def __init__(self, client: AzureOpenAIResponsesClient, id: str = "travel-planning-coordinator"):
def __init__(self, client: FoundryChatClient, id: str = "travel-planning-coordinator"):
# Use default_options to persist conversation history for evaluation.
self.agent = client.as_agent(
self.agent = Agent(
client=client,
id="travel-planning-coordinator",
instructions=(
"You are the final coordinator. You will receive responses from multiple agents: "
@@ -143,13 +145,13 @@ class ResearchLead(Executor):
async def run_workflow_with_response_tracking(
query: str, client: AzureOpenAIResponsesClient | None = None, deployment_name: str | None = None
query: str, client: FoundryChatClient | None = None, deployment_name: str | None = None
) -> dict:
"""Run multi-agent workflow and track conversation IDs, response IDs, and interaction sequence.
Args:
query: The user query to process through the multi-agent workflow
client: Optional AzureOpenAIResponsesClient instance
client: Optional FoundryChatClient instance
deployment_name: Optional model deployment name for the workflow agents
Returns:
@@ -159,12 +161,12 @@ async def run_workflow_with_response_tracking(
try:
async with DefaultAzureCredential() as credential:
project_client = AIProjectClient(
endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=credential,
)
async with project_client:
client = AzureOpenAIResponsesClient(project_client=project_client, deployment_name=deployment_name)
client = FoundryChatClient(project_client=project_client, model=deployment_name)
return await _run_workflow_with_client(query, client)
except Exception as e:
print(f"Error during workflow execution: {e}")
@@ -173,7 +175,7 @@ async def run_workflow_with_response_tracking(
return await _run_workflow_with_client(query, client)
async def _run_workflow_with_client(query: str, client: AzureOpenAIResponsesClient) -> dict:
async def _run_workflow_with_client(query: str, client: FoundryChatClient) -> dict:
"""Execute workflow with given client and track all interactions."""
# Initialize tracking variables - use lists to track multiple responses per agent
@@ -205,16 +207,17 @@ async def _run_workflow_with_client(query: str, client: AzureOpenAIResponsesClie
}
async def _create_workflow(client: AzureOpenAIResponsesClient):
async def _create_workflow(client: FoundryChatClient):
"""Create the multi-agent travel planning workflow with specialized agents.
Uses a single shared AzureOpenAIResponsesClient for all agents.
Uses a single shared FoundryChatClient for all agents.
"""
final_coordinator = ResearchLead(client=client, id="final-coordinator")
# Agent 1: Travel Request Handler (initial coordinator)
travel_request_handler = client.as_agent(
travel_request_handler = Agent(
client=client,
id="travel-request-handler",
instructions=(
"You receive user travel queries and relay them to specialized agents. Extract key information: destination, dates, budget, and preferences. Pass this information forward clearly to the next agents."
@@ -223,7 +226,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 2: Hotel Search Executor
hotel_search_agent = client.as_agent(
hotel_search_agent = Agent(
client=client,
id="hotel-search-agent",
instructions=(
"You are a hotel search specialist. Your task is ONLY to search for and provide hotel information. Use search_hotels to find options, get_hotel_details for specifics, and check_availability to verify rooms. Output format: List hotel names, prices per night, total cost for the stay, locations, ratings, amenities, and addresses. IMPORTANT: Only provide hotel information without additional commentary."
@@ -233,7 +237,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 3: Flight Search Executor
flight_search_agent = client.as_agent(
flight_search_agent = Agent(
client=client,
id="flight-search-agent",
instructions=(
"You are a flight search specialist. Your task is ONLY to search for and provide flight information. Use search_flights to find options, get_flight_details for specifics, and check_availability for seats. Output format: List flight numbers, airlines, departure/arrival times, prices, durations, and cabin class. IMPORTANT: Only provide flight information without additional commentary."
@@ -243,7 +248,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 4: Activity Search Executor
activity_search_agent = client.as_agent(
activity_search_agent = Agent(
client=client,
id="activity-search-agent",
instructions=(
"You are an activities specialist. Your task is ONLY to search for and provide activity information. Use search_activities to find options for activities. Output format: List activity names, descriptions, prices, durations, ratings, and categories. IMPORTANT: Only provide activity information without additional commentary."
@@ -253,7 +259,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 5: Booking Confirmation Executor
booking_confirmation_agent = client.as_agent(
booking_confirmation_agent = Agent(
client=client,
id="booking-confirmation-agent",
instructions=(
"You confirm bookings. Use check_hotel_availability and check_flight_availability to verify slots, then confirm_booking to finalize. Provide ONLY: confirmation numbers, booking references, and confirmation status."
@@ -263,7 +270,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 6: Booking Payment Executor
booking_payment_agent = client.as_agent(
booking_payment_agent = Agent(
client=client,
id="booking-payment-agent",
instructions=(
"You process payments. Use validate_payment_method to verify payment, then process_payment to complete transactions. Provide ONLY: payment confirmation status, transaction IDs, and payment amounts."
@@ -273,7 +281,8 @@ async def _create_workflow(client: AzureOpenAIResponsesClient):
)
# Agent 7: Booking Information Aggregation Executor
booking_info_aggregation_agent = client.as_agent(
booking_info_aggregation_agent = Agent(
client=client,
id="booking-info-aggregation-agent",
instructions=(
"You aggregate hotel and flight search results. Receive options from search agents and organize them. Provide: top 2-3 hotel options with prices and top 2-3 flight options with prices in a structured format."
@@ -356,7 +365,7 @@ async def create_and_run_workflow(deployment_name: str | None = None):
query = example_queries[0]
print(f"Query: {query}\n")
result = await run_workflow_with_response_tracking(query, deployment_name=deployment_name)
result = await run_workflow_with_response_tracking(query, model=deployment_name)
# Create output data structure
output_data = {"agents": {}, "query": result["query"], "output": result.get("output", "")}
@@ -9,7 +9,7 @@ import time
from typing import TYPE_CHECKING, Any
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from azure.identity import AzureCliCredential
from create_workflow import create_and_run_workflow
from dotenv import load_dotenv
@@ -33,8 +33,8 @@ This script:
def create_openai_client() -> OpenAI:
project_client = AIProjectClient(
endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
credential=DefaultAzureCredential(),
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=AzureCliCredential(),
)
return project_client.get_openai_client()
@@ -58,7 +58,7 @@ async def run_workflow(deployment_name: str | None = None) -> dict[str, Any]:
print("Executing multi-agent travel planning workflow...")
print("This may take a few minutes...")
workflow_data = await create_and_run_workflow(deployment_name=deployment_name)
workflow_data = await create_and_run_workflow(model=deployment_name)
print("Workflow execution completed")
return workflow_data
@@ -216,7 +216,7 @@ async def main():
print_section("Travel Planning Workflow Evaluation")
print_section("Step 1: Running Workflow")
workflow_data = await run_workflow(deployment_name=workflow_agent_model)
workflow_data = await run_workflow(model=workflow_agent_model)
print_section("Step 2: Response Data Summary")
display_response_summary(workflow_data)
@@ -225,7 +225,7 @@ async def main():
fetch_agent_responses(openai_client, workflow_data, agents_to_evaluate)
print_section("Step 4: Creating Evaluation")
eval_object = create_evaluation(openai_client, deployment_name=eval_model)
eval_object = create_evaluation(openai_client, model=eval_model)
print_section("Step 5: Running Evaluation")
eval_run = run_evaluation(openai_client, eval_object, workflow_data, agents_to_evaluate)