Python: Create/Get Agent API for Azure V2 (#3059)

* Added get_agent method to Azure AI V2

* Small fixes

* Small fix

* Removed AzureAIAgentProvider

* Added create_agent method

* Small fixes

* Fixed code interpreter tool mapping

* Added agent provider for V2 client

* Updated response format handling

* Added provider example

* Fixed errors

* Update python/samples/getting_started/agents/azure_ai/README.md

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

* Small fix

* Updates from merge

* Resolved comments

* Resolved comments

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Dmytro Struk
2026-01-14 11:35:01 -08:00
committed by GitHub
Unverified
parent f56808b279
commit 99c5718696
35 changed files with 1903 additions and 336 deletions
@@ -4,6 +4,7 @@ import importlib.metadata
from ._chat_client import AzureAIAgentClient, AzureAIAgentOptions
from ._client import AzureAIClient
from ._provider import AzureAIProjectAgentProvider
from ._shared import AzureAISettings
try:
@@ -15,6 +16,7 @@ __all__ = [
"AzureAIAgentClient",
"AzureAIAgentOptions",
"AzureAIClient",
"AzureAIProjectAgentProvider",
"AzureAISettings",
"__version__",
]
@@ -2,7 +2,7 @@
import sys
from collections.abc import Mapping, MutableSequence
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypedDict, cast
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypedDict, TypeVar, cast
from agent_framework import (
AGENT_FRAMEWORK_USER_AGENT,
@@ -13,7 +13,7 @@ from agent_framework import (
use_chat_middleware,
use_function_invocation,
)
from agent_framework.exceptions import ServiceInitializationError, ServiceInvalidRequestError
from agent_framework.exceptions import ServiceInitializationError
from agent_framework.observability import use_instrumentation
from agent_framework.openai._responses_client import OpenAIBaseResponsesClient
from azure.ai.projects.aio import AIProjectClient
@@ -21,15 +21,12 @@ from azure.ai.projects.models import (
MCPTool,
PromptAgentDefinition,
PromptAgentDefinitionText,
ResponseTextFormatConfigurationJsonObject,
ResponseTextFormatConfigurationJsonSchema,
ResponseTextFormatConfigurationText,
)
from azure.core.credentials_async import AsyncTokenCredential
from azure.core.exceptions import ResourceNotFoundError
from pydantic import BaseModel, ValidationError
from pydantic import ValidationError
from ._shared import AzureAISettings
from ._shared import AzureAISettings, create_text_format_config
if TYPE_CHECKING:
from agent_framework.openai import OpenAIResponsesOptions
@@ -286,47 +283,6 @@ class AzureAIClient(OpenAIBaseResponsesClient[TAzureAIClientOptions], Generic[TA
"""Close the project_client."""
await self._close_client_if_needed()
def _create_text_format_config(
self, response_format: type[BaseModel] | Mapping[str, Any]
) -> (
ResponseTextFormatConfigurationJsonSchema
| ResponseTextFormatConfigurationJsonObject
| ResponseTextFormatConfigurationText
):
"""Convert response_format into Azure text format configuration."""
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
schema = response_format.model_json_schema()
# Ensure additionalProperties is explicitly false to satisfy Azure validation
if isinstance(schema, dict):
schema.setdefault("additionalProperties", False)
return ResponseTextFormatConfigurationJsonSchema(
name=response_format.__name__,
schema=schema,
)
if isinstance(response_format, Mapping):
format_config = self._convert_response_format(response_format)
format_type = format_config.get("type")
if format_type == "json_schema":
# Ensure schema includes additionalProperties=False to satisfy Azure validation
schema = dict(format_config.get("schema", {})) # type: ignore[assignment]
schema.setdefault("additionalProperties", False)
config_kwargs: dict[str, Any] = {
"name": format_config.get("name") or "response",
"schema": schema,
}
if "strict" in format_config:
config_kwargs["strict"] = format_config["strict"]
if "description" in format_config:
config_kwargs["description"] = format_config["description"]
return ResponseTextFormatConfigurationJsonSchema(**config_kwargs)
if format_type == "json_object":
return ResponseTextFormatConfigurationJsonObject()
if format_type == "text":
return ResponseTextFormatConfigurationText()
raise ServiceInvalidRequestError("response_format must be a Pydantic model or mapping.")
async def _get_agent_reference_or_create(
self,
run_options: dict[str, Any],
@@ -380,7 +336,7 @@ class AzureAIClient(OpenAIBaseResponsesClient[TAzureAIClientOptions], Generic[TA
# response_format is accessed from chat_options or additional_properties
# since the base class excludes it from run_options
if chat_options and (response_format := chat_options.get("response_format")):
args["text"] = PromptAgentDefinitionText(format=self._create_text_format_config(response_format))
args["text"] = PromptAgentDefinitionText(format=create_text_format_config(response_format))
# Combine instructions from messages and options
combined_instructions = [
@@ -0,0 +1,455 @@
# Copyright (c) Microsoft. All rights reserved.
import sys
from collections.abc import Callable, MutableMapping, Sequence
from typing import TYPE_CHECKING, Any, Generic, TypedDict
from agent_framework import (
AGENT_FRAMEWORK_USER_AGENT,
AIFunction,
ChatAgent,
ContextProvider,
Middleware,
ToolProtocol,
get_logger,
normalize_tools,
)
from agent_framework.exceptions import ServiceInitializationError
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import (
AgentReference,
AgentVersionDetails,
FunctionTool,
PromptAgentDefinition,
PromptAgentDefinitionText,
)
from azure.core.credentials_async import AsyncTokenCredential
from pydantic import BaseModel, ValidationError
from ._client import AzureAIClient
from ._shared import AzureAISettings, create_text_format_config, from_azure_ai_tools, to_azure_ai_tools
if TYPE_CHECKING:
from agent_framework.openai import OpenAIResponsesOptions
if sys.version_info >= (3, 13):
from typing import Self, TypeVar # pragma: no cover
else:
from typing_extensions import Self, TypeVar # pragma: no cover
logger = get_logger("agent_framework.azure")
# Type variable for options - allows typed ChatAgent[TOptions] returns
# Default matches AzureAIClient's default options type
TOptions_co = TypeVar(
"TOptions_co",
bound=TypedDict, # type: ignore[valid-type]
default="OpenAIResponsesOptions",
covariant=True,
)
class AzureAIProjectAgentProvider(Generic[TOptions_co]):
"""Provider for Azure AI Agent Service (Responses API).
This provider allows you to create, retrieve, and manage Azure AI agents
using the AIProjectClient from the Azure AI Projects SDK.
Examples:
Using with explicit AIProjectClient:
.. code-block:: python
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import DefaultAzureCredential
async with AIProjectClient(endpoint, credential) as client:
provider = AzureAIProjectAgentProvider(client)
agent = await provider.create_agent(
name="MyAgent",
model="gpt-4",
instructions="You are a helpful assistant.",
)
response = await agent.run("Hello!")
Using with credential and endpoint (auto-creates client):
.. code-block:: python
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import DefaultAzureCredential
async with AzureAIProjectAgentProvider(credential=credential) as provider:
agent = await provider.create_agent(
name="MyAgent",
model="gpt-4",
instructions="You are a helpful assistant.",
)
response = await agent.run("Hello!")
"""
def __init__(
self,
project_client: AIProjectClient | None = None,
*,
project_endpoint: str | None = None,
model: str | None = None,
credential: AsyncTokenCredential | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize an Azure AI Project Agent Provider.
Args:
project_client: An existing AIProjectClient to use. If not provided, one will be created.
project_endpoint: The Azure AI Project endpoint URL.
Can also be set via environment variable AZURE_AI_PROJECT_ENDPOINT.
Ignored when a project_client is passed.
model: The default model deployment name to use for agent creation.
Can also be set via environment variable AZURE_AI_MODEL_DEPLOYMENT_NAME.
credential: Azure async credential to use for authentication.
Required when project_client is not provided.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
Raises:
ServiceInitializationError: If required parameters are missing or invalid.
"""
try:
self._settings = AzureAISettings(
project_endpoint=project_endpoint,
model_deployment_name=model,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
except ValidationError as ex:
raise ServiceInitializationError("Failed to create Azure AI settings.", ex) from ex
# Track whether we should close client connection
self._should_close_client = False
if project_client is None:
if not self._settings.project_endpoint:
raise ServiceInitializationError(
"Azure AI project endpoint is required. Set via 'project_endpoint' parameter "
"or 'AZURE_AI_PROJECT_ENDPOINT' environment variable."
)
if not credential:
raise ServiceInitializationError("Azure credential is required when project_client is not provided.")
project_client = AIProjectClient(
endpoint=self._settings.project_endpoint,
credential=credential,
user_agent=AGENT_FRAMEWORK_USER_AGENT,
)
self._should_close_client = True
self._project_client = project_client
async def create_agent(
self,
name: str,
model: str | None = None,
instructions: str | None = None,
description: str | None = None,
response_format: type[BaseModel] | MutableMapping[str, Any] | None = None,
tools: ToolProtocol
| Callable[..., Any]
| MutableMapping[str, Any]
| Sequence[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
default_options: TOptions_co | None = None,
middleware: Sequence[Middleware] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
"""Create a new agent on the Azure AI service and return a local ChatAgent wrapper.
Args:
name: The name of the agent to create.
model: The model deployment name to use. Falls back to AZURE_AI_MODEL_DEPLOYMENT_NAME
environment variable if not provided.
instructions: Instructions for the agent.
description: A description of the agent.
response_format: The format of the response. Can be a Pydantic model for structured
output, or a dict with JSON schema configuration.
tools: Tools to make available to the agent.
default_options: A TypedDict containing default chat options for the agent.
These options are applied to every run unless overridden.
middleware: List of middleware to intercept agent and function invocations.
context_provider: Context provider to include during agent invocation.
Returns:
ChatAgent: A ChatAgent instance configured with the created agent.
Raises:
ServiceInitializationError: If required parameters are missing.
"""
# Resolve model from parameter or environment variable
resolved_model = model or self._settings.model_deployment_name
if not resolved_model:
raise ServiceInitializationError(
"Model deployment name is required. Provide 'model' parameter "
"or set 'AZURE_AI_MODEL_DEPLOYMENT_NAME' environment variable."
)
args: dict[str, Any] = {"model": resolved_model}
if instructions:
args["instructions"] = instructions
if response_format:
args["text"] = PromptAgentDefinitionText(format=create_text_format_config(response_format))
# Normalize tools once and reuse for both Azure AI API and ChatAgent
normalized_tools = normalize_tools(tools)
if normalized_tools:
args["tools"] = to_azure_ai_tools(normalized_tools)
created_agent = await self._project_client.agents.create_version(
agent_name=name,
definition=PromptAgentDefinition(**args),
description=description,
)
return self._to_chat_agent_from_details(
created_agent,
normalized_tools,
response_format=response_format,
default_options=default_options,
middleware=middleware,
context_provider=context_provider,
)
async def get_agent(
self,
*,
name: str | None = None,
reference: AgentReference | None = None,
tools: ToolProtocol
| Callable[..., Any]
| MutableMapping[str, Any]
| Sequence[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
default_options: TOptions_co | None = None,
middleware: Sequence[Middleware] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
"""Retrieve an existing agent from the Azure AI service and return a local ChatAgent wrapper.
You must provide either name or reference. Use `as_agent()` if you already have
AgentVersionDetails and want to avoid an async call.
Args:
name: The name of the agent to retrieve (fetches latest version).
reference: Reference containing the agent's name and optionally a specific version.
tools: Tools to make available to the agent. Required if the agent has function tools.
default_options: A TypedDict containing default chat options for the agent.
These options are applied to every run unless overridden.
middleware: List of middleware to intercept agent and function invocations.
context_provider: Context provider to include during agent invocation.
Returns:
ChatAgent: A ChatAgent instance configured with the retrieved agent.
Raises:
ValueError: If no identifier is provided or required tools are missing.
"""
existing_agent: AgentVersionDetails
if reference and reference.version:
# Fetch specific version
existing_agent = await self._project_client.agents.get_version(
agent_name=reference.name, agent_version=reference.version
)
elif agent_name := (reference.name if reference else name):
# Fetch latest version
details = await self._project_client.agents.get(agent_name=agent_name)
existing_agent = details.versions.latest
else:
raise ValueError("Either name or reference must be provided to get an agent.")
if not isinstance(existing_agent.definition, PromptAgentDefinition):
raise ValueError("Agent definition must be PromptAgentDefinition to get a ChatAgent.")
# Validate that required function tools are provided
self._validate_function_tools(existing_agent.definition.tools, tools)
return self._to_chat_agent_from_details(
existing_agent,
normalize_tools(tools),
default_options=default_options,
middleware=middleware,
context_provider=context_provider,
)
def as_agent(
self,
details: AgentVersionDetails,
tools: ToolProtocol
| Callable[..., Any]
| MutableMapping[str, Any]
| Sequence[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
default_options: TOptions_co | None = None,
middleware: Sequence[Middleware] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
"""Wrap an SDK agent version object into a ChatAgent without making HTTP calls.
Use this when you already have an AgentVersionDetails from a previous API call.
Args:
details: The AgentVersionDetails to wrap.
tools: Tools to make available to the agent. Required if the agent has function tools.
default_options: A TypedDict containing default chat options for the agent.
These options are applied to every run unless overridden.
middleware: List of middleware to intercept agent and function invocations.
context_provider: Context provider to include during agent invocation.
Returns:
ChatAgent: A ChatAgent instance configured with the agent version.
Raises:
ValueError: If the agent definition is not a PromptAgentDefinition or required tools are missing.
"""
if not isinstance(details.definition, PromptAgentDefinition):
raise ValueError("Agent definition must be PromptAgentDefinition to create a ChatAgent.")
# Validate that required function tools are provided
self._validate_function_tools(details.definition.tools, tools)
return self._to_chat_agent_from_details(
details,
normalize_tools(tools),
default_options=default_options,
middleware=middleware,
context_provider=context_provider,
)
def _to_chat_agent_from_details(
self,
details: AgentVersionDetails,
provided_tools: Sequence[ToolProtocol | MutableMapping[str, Any]] | None = None,
response_format: type[BaseModel] | MutableMapping[str, Any] | None = None,
default_options: TOptions_co | None = None,
middleware: Sequence[Middleware] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
"""Create a ChatAgent from an AgentVersionDetails.
Args:
details: The AgentVersionDetails containing the agent definition.
provided_tools: User-provided tools (including function implementations).
These are merged with hosted tools from the definition.
response_format: The response format. Can be a Pydantic model for structured
output parsing, or a dict with JSON schema for service-side formatting.
default_options: A TypedDict containing default chat options for the agent.
These options are applied to every run unless overridden.
middleware: List of middleware to intercept agent and function invocations.
context_provider: Context provider to include during agent invocation.
"""
if not isinstance(details.definition, PromptAgentDefinition):
raise ValueError("Agent definition must be PromptAgentDefinition to get a ChatAgent.")
client = AzureAIClient(
project_client=self._project_client,
agent_name=details.name,
agent_version=details.version,
agent_description=details.description,
)
# Merge tools: hosted tools from definition + user-provided function tools
# from_azure_ai_tools converts hosted tools (MCP, code interpreter, file search, web search)
# but function tools need the actual implementations from provided_tools
merged_tools = self._merge_tools(details.definition.tools, provided_tools)
return ChatAgent( # type: ignore[return-value]
chat_client=client,
id=details.id,
name=details.name,
description=details.description,
instructions=details.definition.instructions,
model_id=details.definition.model,
tools=merged_tools,
response_format=response_format,
default_options=default_options, # type: ignore[arg-type]
middleware=middleware,
context_provider=context_provider,
)
def _merge_tools(
self,
definition_tools: Sequence[Any] | None,
provided_tools: Sequence[ToolProtocol | MutableMapping[str, Any]] | None,
) -> list[ToolProtocol | dict[str, Any]]:
"""Merge hosted tools from definition with user-provided function tools.
Args:
definition_tools: Tools from the agent definition (Azure AI format).
provided_tools: User-provided tools (Agent Framework format), including function implementations.
Returns:
Combined list of tools for the ChatAgent.
"""
merged: list[ToolProtocol | dict[str, Any]] = []
# Convert hosted tools from definition (MCP, code interpreter, file search, web search)
# Function tools from the definition are skipped - we use user-provided implementations instead
hosted_tools = from_azure_ai_tools(definition_tools)
for hosted_tool in hosted_tools:
# Skip function tool dicts - they don't have implementations
if isinstance(hosted_tool, dict) and hosted_tool.get("type") == "function":
continue
merged.append(hosted_tool)
# Add user-provided function tools (these have the actual implementations)
if provided_tools:
for provided_tool in provided_tools:
if isinstance(provided_tool, AIFunction):
merged.append(provided_tool) # type: ignore[reportUnknownArgumentType]
return merged
def _validate_function_tools(
self,
agent_tools: Sequence[Any] | None,
provided_tools: ToolProtocol
| Callable[..., Any]
| MutableMapping[str, Any]
| Sequence[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None,
) -> None:
"""Validate that required function tools are provided."""
# Normalize and validate function tools
normalized_tools = normalize_tools(provided_tools)
tool_names = {tool.name for tool in normalized_tools if isinstance(tool, AIFunction)}
# If function tools exist in agent definition but were not provided,
# we need to raise an error, as it won't be possible to invoke the function.
missing_tools = [
tool.name for tool in (agent_tools or []) if isinstance(tool, FunctionTool) and tool.name not in tool_names
]
if missing_tools:
raise ValueError(
f"The following prompt agent definition required tools were not provided: {', '.join(missing_tools)}"
)
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
async def __aexit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any) -> None:
"""Async context manager exit."""
await self.close()
async def close(self) -> None:
"""Close the provider and release resources.
Only closes the underlying AIProjectClient if it was created by this provider.
"""
if self._should_close_client:
await self._project_client.close()
@@ -1,8 +1,38 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import ClassVar
from collections.abc import Mapping, MutableMapping, Sequence
from typing import Any, ClassVar, Literal, cast
from agent_framework import (
AIFunction,
Contents,
HostedCodeInterpreterTool,
HostedFileContent,
HostedFileSearchTool,
HostedMCPTool,
HostedVectorStoreContent,
HostedWebSearchTool,
ToolProtocol,
get_logger,
)
from agent_framework._pydantic import AFBaseSettings
from agent_framework.exceptions import ServiceInvalidRequestError
from azure.ai.projects.models import (
ApproximateLocation,
CodeInterpreterTool,
CodeInterpreterToolAuto,
FileSearchTool,
FunctionTool,
MCPTool,
ResponseTextFormatConfigurationJsonObject,
ResponseTextFormatConfigurationJsonSchema,
ResponseTextFormatConfigurationText,
Tool,
WebSearchPreviewTool,
)
from pydantic import BaseModel
logger = get_logger("agent_framework.azure")
class AzureAISettings(AFBaseSettings):
@@ -44,3 +74,279 @@ class AzureAISettings(AFBaseSettings):
project_endpoint: str | None = None
model_deployment_name: str | None = None
def from_azure_ai_tools(tools: Sequence[Tool | dict[str, Any]] | None) -> list[ToolProtocol | dict[str, Any]]:
"""Parses and converts a sequence of Azure AI tools into Agent Framework compatible tools.
Args:
tools: A sequence of tool objects or dictionaries
defining the tools to be parsed. Can be None.
Returns:
list[ToolProtocol | dict[str, Any]]: A list of converted tools compatible with the
Agent Framework.
"""
agent_tools: list[ToolProtocol | dict[str, Any]] = []
if not tools:
return agent_tools
for tool in tools:
# Handle raw dictionary tools
tool_dict = tool if isinstance(tool, dict) else dict(tool)
tool_type = tool_dict.get("type")
if tool_type == "mcp":
mcp_tool = cast(MCPTool, tool_dict)
approval_mode: Literal["always_require", "never_require"] | dict[str, set[str]] | None = None
if require_approval := mcp_tool.get("require_approval"):
if require_approval == "always":
approval_mode = "always_require"
elif require_approval == "never":
approval_mode = "never_require"
elif isinstance(require_approval, dict):
approval_mode = {}
if "always" in require_approval:
approval_mode["always_require_approval"] = set(require_approval["always"].get("tool_names", [])) # type: ignore
if "never" in require_approval:
approval_mode["never_require_approval"] = set(require_approval["never"].get("tool_names", [])) # type: ignore
agent_tools.append(
HostedMCPTool(
name=mcp_tool.get("server_label", "").replace("_", " "),
url=mcp_tool.get("server_url", ""),
description=mcp_tool.get("server_description"),
headers=mcp_tool.get("headers"),
allowed_tools=mcp_tool.get("allowed_tools"),
approval_mode=approval_mode, # type: ignore
)
)
elif tool_type == "code_interpreter":
ci_tool = cast(CodeInterpreterTool, tool_dict)
container = ci_tool.get("container", {})
ci_inputs: list[Contents] = []
if "file_ids" in container:
for file_id in container["file_ids"]:
ci_inputs.append(HostedFileContent(file_id=file_id))
agent_tools.append(HostedCodeInterpreterTool(inputs=ci_inputs if ci_inputs else None)) # type: ignore
elif tool_type == "file_search":
fs_tool = cast(FileSearchTool, tool_dict)
fs_inputs: list[Contents] = []
if "vector_store_ids" in fs_tool:
for vs_id in fs_tool["vector_store_ids"]:
fs_inputs.append(HostedVectorStoreContent(vector_store_id=vs_id))
agent_tools.append(
HostedFileSearchTool(
inputs=fs_inputs if fs_inputs else None, # type: ignore
max_results=fs_tool.get("max_num_results"),
)
)
elif tool_type == "web_search_preview":
ws_tool = cast(WebSearchPreviewTool, tool_dict)
additional_properties: dict[str, Any] = {}
if user_location := ws_tool.get("user_location"):
additional_properties["user_location"] = {
"city": user_location.get("city"),
"country": user_location.get("country"),
"region": user_location.get("region"),
"timezone": user_location.get("timezone"),
}
agent_tools.append(HostedWebSearchTool(additional_properties=additional_properties))
else:
agent_tools.append(tool_dict)
return agent_tools
def to_azure_ai_tools(
tools: Sequence[ToolProtocol | MutableMapping[str, Any]] | None,
) -> list[Tool | dict[str, Any]]:
"""Converts Agent Framework tools into Azure AI compatible tools.
Args:
tools: A sequence of Agent Framework tool objects or dictionaries
defining the tools to be converted. Can be None.
Returns:
list[Tool | dict[str, Any]]: A list of converted tools compatible with Azure AI.
"""
azure_tools: list[Tool | dict[str, Any]] = []
if not tools:
return azure_tools
for tool in tools:
if isinstance(tool, ToolProtocol):
match tool:
case HostedMCPTool():
azure_tools.append(_prepare_mcp_tool_for_azure_ai(tool))
case HostedCodeInterpreterTool():
file_ids: list[str] = []
if tool.inputs:
for tool_input in tool.inputs:
if isinstance(tool_input, HostedFileContent):
file_ids.append(tool_input.file_id)
container = CodeInterpreterToolAuto(file_ids=file_ids if file_ids else None)
ci_tool: CodeInterpreterTool = CodeInterpreterTool(container=container)
azure_tools.append(ci_tool)
case AIFunction():
params = tool.parameters()
params["additionalProperties"] = False
azure_tools.append(
FunctionTool(
name=tool.name,
parameters=params,
strict=False,
description=tool.description,
)
)
case HostedFileSearchTool():
if not tool.inputs:
raise ValueError("HostedFileSearchTool requires inputs to be specified.")
vector_store_ids: list[str] = [
inp.vector_store_id for inp in tool.inputs if isinstance(inp, HostedVectorStoreContent)
]
if not vector_store_ids:
raise ValueError(
"HostedFileSearchTool requires inputs to be of type `HostedVectorStoreContent`."
)
fs_tool: FileSearchTool = FileSearchTool(vector_store_ids=vector_store_ids)
if tool.max_results:
fs_tool["max_num_results"] = tool.max_results
azure_tools.append(fs_tool)
case HostedWebSearchTool():
ws_tool: WebSearchPreviewTool = WebSearchPreviewTool()
if tool.additional_properties:
location: dict[str, str] | None = (
tool.additional_properties.get("user_location", None)
if tool.additional_properties
else None
)
if location:
ws_tool.user_location = ApproximateLocation(
city=location.get("city"),
country=location.get("country"),
region=location.get("region"),
timezone=location.get("timezone"),
)
azure_tools.append(ws_tool)
case _:
logger.debug("Unsupported tool passed (type: %s)", type(tool))
else:
# Handle raw dictionary tools
tool_dict = tool if isinstance(tool, dict) else dict(tool)
azure_tools.append(tool_dict)
return azure_tools
def _prepare_mcp_tool_for_azure_ai(tool: HostedMCPTool) -> MCPTool:
"""Convert HostedMCPTool to Azure AI MCPTool format.
Args:
tool: The HostedMCPTool to convert.
Returns:
MCPTool: The converted Azure AI MCPTool.
"""
mcp: MCPTool = MCPTool(server_label=tool.name.replace(" ", "_"), server_url=str(tool.url))
if tool.description:
mcp["server_description"] = tool.description
if tool.headers:
mcp["headers"] = tool.headers
if tool.allowed_tools:
mcp["allowed_tools"] = list(tool.allowed_tools)
if tool.approval_mode:
match tool.approval_mode:
case str():
mcp["require_approval"] = "always" if tool.approval_mode == "always_require" else "never"
case _:
if always_require_approvals := tool.approval_mode.get("always_require_approval"):
mcp["require_approval"] = {"always": {"tool_names": list(always_require_approvals)}}
if never_require_approvals := tool.approval_mode.get("never_require_approval"):
mcp["require_approval"] = {"never": {"tool_names": list(never_require_approvals)}}
return mcp
def create_text_format_config(
response_format: type[BaseModel] | Mapping[str, Any],
) -> (
ResponseTextFormatConfigurationJsonSchema
| ResponseTextFormatConfigurationJsonObject
| ResponseTextFormatConfigurationText
):
"""Convert response_format into Azure text format configuration."""
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
schema = response_format.model_json_schema()
# Ensure additionalProperties is explicitly false to satisfy Azure validation
if isinstance(schema, dict):
schema.setdefault("additionalProperties", False)
return ResponseTextFormatConfigurationJsonSchema(
name=response_format.__name__,
schema=schema,
)
if isinstance(response_format, Mapping):
format_config = _convert_response_format(response_format)
format_type = format_config.get("type")
if format_type == "json_schema":
# Ensure schema includes additionalProperties=False to satisfy Azure validation
schema = dict(format_config.get("schema", {})) # type: ignore[assignment]
schema.setdefault("additionalProperties", False)
config_kwargs: dict[str, Any] = {
"name": format_config.get("name") or "response",
"schema": schema,
}
if "strict" in format_config:
config_kwargs["strict"] = format_config["strict"]
if "description" in format_config:
config_kwargs["description"] = format_config["description"]
return ResponseTextFormatConfigurationJsonSchema(**config_kwargs)
if format_type == "json_object":
return ResponseTextFormatConfigurationJsonObject()
if format_type == "text":
return ResponseTextFormatConfigurationText()
raise ServiceInvalidRequestError("response_format must be a Pydantic model or mapping.")
def _convert_response_format(response_format: Mapping[str, Any]) -> dict[str, Any]:
"""Convert Chat style response_format into Responses text format config."""
if "format" in response_format and isinstance(response_format["format"], Mapping):
return dict(cast("Mapping[str, Any]", response_format["format"]))
format_type = response_format.get("type")
if format_type == "json_schema":
schema_section = response_format.get("json_schema", response_format)
if not isinstance(schema_section, Mapping):
raise ServiceInvalidRequestError("json_schema response_format must be a mapping.")
schema_section_typed = cast("Mapping[str, Any]", schema_section)
schema: Any = schema_section_typed.get("schema")
if schema is None:
raise ServiceInvalidRequestError("json_schema response_format requires a schema.")
name: str = str(
schema_section_typed.get("name")
or schema_section_typed.get("title")
or (cast("Mapping[str, Any]", schema).get("title") if isinstance(schema, Mapping) else None)
or "response"
)
format_config: dict[str, Any] = {
"type": "json_schema",
"name": name,
"schema": schema,
}
if "strict" in schema_section:
format_config["strict"] = schema_section["strict"]
if "description" in schema_section and schema_section["description"] is not None:
format_config["description"] = schema_section["description"]
return format_config
if format_type in {"json_object", "text"}:
return {"type": format_type}
raise ServiceInvalidRequestError("Unsupported response_format provided for Azure AI client.")
@@ -17,7 +17,10 @@ from agent_framework import (
ChatOptions,
ChatResponse,
HostedCodeInterpreterTool,
HostedFileContent,
HostedFileSearchTool,
HostedMCPTool,
HostedVectorStoreContent,
HostedWebSearchTool,
Role,
TextContent,
@@ -25,7 +28,13 @@ from agent_framework import (
from agent_framework.exceptions import ServiceInitializationError
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import (
ApproximateLocation,
CodeInterpreterTool,
CodeInterpreterToolAuto,
FileSearchTool,
MCPTool,
ResponseTextFormatConfigurationJsonSchema,
WebSearchPreviewTool,
)
from azure.identity.aio import AzureCliCredential
from openai.types.responses.parsed_response import ParsedResponse
@@ -34,6 +43,7 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationError
from pytest import fixture, param
from agent_framework_azure_ai import AzureAIClient, AzureAISettings
from agent_framework_azure_ai._shared import from_azure_ai_tools
skip_if_azure_ai_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
@@ -962,6 +972,58 @@ def test_get_conversation_id_with_parsed_response_no_conversation() -> None:
assert result == "resp_parsed_12345"
def test_from_azure_ai_tools() -> None:
"""Test from_azure_ai_tools."""
# Test MCP tool
mcp_tool = MCPTool(server_label="test_server", server_url="http://localhost:8080")
parsed_tools = from_azure_ai_tools([mcp_tool])
assert len(parsed_tools) == 1
assert isinstance(parsed_tools[0], HostedMCPTool)
assert parsed_tools[0].name == "test server"
assert str(parsed_tools[0].url).rstrip("/") == "http://localhost:8080"
# Test Code Interpreter tool
ci_tool = CodeInterpreterTool(container=CodeInterpreterToolAuto(file_ids=["file-1"]))
parsed_tools = from_azure_ai_tools([ci_tool])
assert len(parsed_tools) == 1
assert isinstance(parsed_tools[0], HostedCodeInterpreterTool)
assert parsed_tools[0].inputs is not None
assert len(parsed_tools[0].inputs) == 1
tool_input = parsed_tools[0].inputs[0]
assert tool_input and isinstance(tool_input, HostedFileContent) and tool_input.file_id == "file-1"
# Test File Search tool
fs_tool = FileSearchTool(vector_store_ids=["vs-1"], max_num_results=5)
parsed_tools = from_azure_ai_tools([fs_tool])
assert len(parsed_tools) == 1
assert isinstance(parsed_tools[0], HostedFileSearchTool)
assert parsed_tools[0].inputs is not None
assert len(parsed_tools[0].inputs) == 1
tool_input = parsed_tools[0].inputs[0]
assert tool_input and isinstance(tool_input, HostedVectorStoreContent) and tool_input.vector_store_id == "vs-1"
assert parsed_tools[0].max_results == 5
# Test Web Search tool
ws_tool = WebSearchPreviewTool(
user_location=ApproximateLocation(city="Seattle", country="US", region="WA", timezone="PST")
)
parsed_tools = from_azure_ai_tools([ws_tool])
assert len(parsed_tools) == 1
assert isinstance(parsed_tools[0], HostedWebSearchTool)
assert parsed_tools[0].additional_properties
user_location = parsed_tools[0].additional_properties["user_location"]
assert user_location["city"] == "Seattle"
assert user_location["country"] == "US"
assert user_location["region"] == "WA"
assert user_location["timezone"] == "PST"
# region Integration Tests
@@ -993,6 +1055,7 @@ async def client() -> AsyncGenerator[AzureAIClient, None]:
agent_name=agent_name,
)
try:
assert client.function_invocation_configuration
client.function_invocation_configuration.max_iterations = 1
yield client
finally:
@@ -0,0 +1,408 @@
# Copyright (c) Microsoft. All rights reserved.
import os
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from agent_framework import ChatAgent
from agent_framework.exceptions import ServiceInitializationError
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import (
AgentReference,
AgentVersionDetails,
FunctionTool,
PromptAgentDefinition,
)
from azure.identity.aio import AzureCliCredential
from agent_framework_azure_ai import AzureAIProjectAgentProvider
skip_if_azure_ai_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("AZURE_AI_PROJECT_ENDPOINT", "") in ("", "https://test-project.cognitiveservices.azure.com/")
or os.getenv("AZURE_AI_MODEL_DEPLOYMENT_NAME", "") == "",
reason=(
"No real AZURE_AI_PROJECT_ENDPOINT or AZURE_AI_MODEL_DEPLOYMENT_NAME provided; skipping integration tests."
if os.getenv("RUN_INTEGRATION_TESTS", "false").lower() == "true"
else "Integration tests are disabled."
),
)
@pytest.fixture
def mock_project_client() -> MagicMock:
"""Fixture that provides a mock AIProjectClient."""
mock_client = MagicMock()
# Mock agents property
mock_client.agents = MagicMock()
mock_client.agents.create_version = AsyncMock()
# Mock conversations property
mock_client.conversations = MagicMock()
mock_client.conversations.create = AsyncMock()
# Mock telemetry property
mock_client.telemetry = MagicMock()
mock_client.telemetry.get_application_insights_connection_string = AsyncMock()
# Mock get_openai_client method
mock_client.get_openai_client = AsyncMock()
# Mock close method
mock_client.close = AsyncMock()
return mock_client
@pytest.fixture
def mock_azure_credential() -> MagicMock:
"""Fixture that provides a mock Azure credential."""
return MagicMock()
@pytest.fixture
def azure_ai_unit_test_env(monkeypatch: pytest.MonkeyPatch) -> dict[str, str]:
"""Fixture that sets up Azure AI environment variables for unit testing."""
env_vars = {
"AZURE_AI_PROJECT_ENDPOINT": "https://test-project.cognitiveservices.azure.com/",
"AZURE_AI_MODEL_DEPLOYMENT_NAME": "test-model-deployment",
}
for key, value in env_vars.items():
monkeypatch.setenv(key, value)
return env_vars
def test_provider_init_with_project_client(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider initialization with existing project_client."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
assert provider._project_client is mock_project_client # type: ignore
assert not provider._should_close_client # type: ignore
def test_provider_init_with_credential_and_endpoint(
azure_ai_unit_test_env: dict[str, str],
mock_azure_credential: MagicMock,
) -> None:
"""Test AzureAIProjectAgentProvider initialization with credential and endpoint."""
with patch("agent_framework_azure_ai._provider.AIProjectClient") as mock_ai_project_client:
mock_client = MagicMock()
mock_ai_project_client.return_value = mock_client
provider = AzureAIProjectAgentProvider(
project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"],
credential=mock_azure_credential,
)
assert provider._project_client is mock_client # type: ignore
assert provider._should_close_client # type: ignore
# Verify AIProjectClient was called with correct parameters
mock_ai_project_client.assert_called_once()
def test_provider_init_missing_endpoint() -> None:
"""Test AzureAIProjectAgentProvider initialization when endpoint is missing."""
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = None
mock_settings.return_value.model_deployment_name = "test-model"
with pytest.raises(ServiceInitializationError, match="Azure AI project endpoint is required"):
AzureAIProjectAgentProvider(credential=MagicMock())
def test_provider_init_missing_credential(azure_ai_unit_test_env: dict[str, str]) -> None:
"""Test AzureAIProjectAgentProvider initialization when credential is missing."""
with pytest.raises(
ServiceInitializationError, match="Azure credential is required when project_client is not provided"
):
AzureAIProjectAgentProvider(
project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"],
)
async def test_provider_create_agent(
mock_project_client: MagicMock,
azure_ai_unit_test_env: dict[str, str],
) -> None:
"""Test AzureAIProjectAgentProvider.create_agent method."""
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"]
mock_settings.return_value.model_deployment_name = azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Mock agent creation response
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = "Test Agent"
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.model = "gpt-4"
mock_agent_version.definition.instructions = "Test instructions"
mock_agent_version.definition.temperature = 0.7
mock_agent_version.definition.top_p = 0.9
mock_agent_version.definition.tools = []
mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version)
agent = await provider.create_agent(
name="test-agent",
model="gpt-4",
instructions="Test instructions",
description="Test Agent",
)
assert isinstance(agent, ChatAgent)
assert agent.name == "test-agent"
mock_project_client.agents.create_version.assert_called_once()
async def test_provider_create_agent_with_env_model(
mock_project_client: MagicMock,
azure_ai_unit_test_env: dict[str, str],
) -> None:
"""Test AzureAIProjectAgentProvider.create_agent uses model from env var."""
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"]
mock_settings.return_value.model_deployment_name = azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Mock agent creation response
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = None
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.model = azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
mock_agent_version.definition.instructions = None
mock_agent_version.definition.temperature = None
mock_agent_version.definition.top_p = None
mock_agent_version.definition.tools = []
mock_project_client.agents.create_version = AsyncMock(return_value=mock_agent_version)
# Call without model parameter - should use env var
agent = await provider.create_agent(name="test-agent")
assert isinstance(agent, ChatAgent)
# Verify the model from env var was used
call_args = mock_project_client.agents.create_version.call_args
assert call_args[1]["definition"].model == azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
async def test_provider_create_agent_missing_model(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.create_agent raises when model is missing."""
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = "https://test.com"
mock_settings.return_value.model_deployment_name = None
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
with pytest.raises(ServiceInitializationError, match="Model deployment name is required"):
await provider.create_agent(name="test-agent")
async def test_provider_get_agent_with_name(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.get_agent with name parameter."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Mock agent response
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = "Test Agent"
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.model = "gpt-4"
mock_agent_version.definition.instructions = "Test instructions"
mock_agent_version.definition.temperature = None
mock_agent_version.definition.top_p = None
mock_agent_version.definition.tools = []
mock_agent_object = MagicMock()
mock_agent_object.versions.latest = mock_agent_version
mock_project_client.agents = AsyncMock()
mock_project_client.agents.get.return_value = mock_agent_object
agent = await provider.get_agent(name="test-agent")
assert isinstance(agent, ChatAgent)
assert agent.name == "test-agent"
mock_project_client.agents.get.assert_called_with(agent_name="test-agent")
async def test_provider_get_agent_with_reference(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.get_agent with reference parameter."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Mock agent response
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = "Test Agent"
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.model = "gpt-4"
mock_agent_version.definition.instructions = "Test instructions"
mock_agent_version.definition.temperature = None
mock_agent_version.definition.top_p = None
mock_agent_version.definition.tools = []
mock_project_client.agents = AsyncMock()
mock_project_client.agents.get_version.return_value = mock_agent_version
agent_reference = AgentReference(name="test-agent", version="1.0")
agent = await provider.get_agent(reference=agent_reference)
assert isinstance(agent, ChatAgent)
assert agent.name == "test-agent"
mock_project_client.agents.get_version.assert_called_with(agent_name="test-agent", agent_version="1.0")
async def test_provider_get_agent_missing_parameters(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.get_agent raises when no identifier provided."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
with pytest.raises(ValueError, match="Either name or reference must be provided"):
await provider.get_agent()
async def test_provider_get_agent_missing_function_tools(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.get_agent raises when required tools are missing."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Mock agent with function tools
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = None
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.tools = [
FunctionTool(name="test_tool", parameters=[], strict=True, description="Test tool")
]
mock_agent_object = MagicMock()
mock_agent_object.versions.latest = mock_agent_version
mock_project_client.agents = AsyncMock()
mock_project_client.agents.get.return_value = mock_agent_object
with pytest.raises(
ValueError, match="The following prompt agent definition required tools were not provided: test_tool"
):
await provider.get_agent(name="test-agent")
def test_provider_as_agent(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.as_agent method."""
provider = AzureAIProjectAgentProvider(project_client=mock_project_client)
# Create mock agent version
mock_agent_version = MagicMock(spec=AgentVersionDetails)
mock_agent_version.id = "agent-id"
mock_agent_version.name = "test-agent"
mock_agent_version.version = "1.0"
mock_agent_version.description = "Test Agent"
mock_agent_version.definition = MagicMock(spec=PromptAgentDefinition)
mock_agent_version.definition.model = "gpt-4"
mock_agent_version.definition.instructions = "Test instructions"
mock_agent_version.definition.temperature = 0.7
mock_agent_version.definition.top_p = 0.9
mock_agent_version.definition.tools = []
agent = provider.as_agent(mock_agent_version)
assert isinstance(agent, ChatAgent)
assert agent.name == "test-agent"
assert agent.description == "Test Agent"
async def test_provider_context_manager(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider async context manager."""
with patch("agent_framework_azure_ai._provider.AIProjectClient") as mock_ai_project_client:
mock_client = MagicMock()
mock_client.close = AsyncMock()
mock_ai_project_client.return_value = mock_client
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = "https://test.com"
mock_settings.return_value.model_deployment_name = "test-model"
async with AzureAIProjectAgentProvider(credential=MagicMock()) as provider:
assert provider._project_client is mock_client # type: ignore
# Should call close after exiting context
mock_client.close.assert_called_once()
async def test_provider_context_manager_with_provided_client(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider context manager doesn't close provided client."""
mock_project_client.close = AsyncMock()
async with AzureAIProjectAgentProvider(project_client=mock_project_client) as provider:
assert provider._project_client is mock_project_client # type: ignore
# Should NOT call close when client was provided
mock_project_client.close.assert_not_called()
async def test_provider_close_method(mock_project_client: MagicMock) -> None:
"""Test AzureAIProjectAgentProvider.close method."""
with patch("agent_framework_azure_ai._provider.AIProjectClient") as mock_ai_project_client:
mock_client = MagicMock()
mock_client.close = AsyncMock()
mock_ai_project_client.return_value = mock_client
with patch("agent_framework_azure_ai._provider.AzureAISettings") as mock_settings:
mock_settings.return_value.project_endpoint = "https://test.com"
mock_settings.return_value.model_deployment_name = "test-model"
provider = AzureAIProjectAgentProvider(credential=MagicMock())
await provider.close()
mock_client.close.assert_called_once()
@pytest.mark.flaky
@skip_if_azure_ai_integration_tests_disabled
async def test_provider_create_and_get_agent_integration() -> None:
"""Integration test for provider create_agent and get_agent."""
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
model = os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
):
provider = AzureAIProjectAgentProvider(project_client=project_client)
try:
# Create agent
agent = await provider.create_agent(
name="ProviderTestAgent",
model=model,
instructions="You are a helpful assistant. Always respond with 'Hello from provider!'",
)
assert isinstance(agent, ChatAgent)
assert agent.name == "ProviderTestAgent"
# Run the agent
response = await agent.run("Hi!")
assert response.text is not None
assert len(response.text) > 0
# Get the same agent
retrieved_agent = await provider.get_agent(name="ProviderTestAgent")
assert retrieved_agent.name == "ProviderTestAgent"
finally:
# Cleanup
await project_client.agents.delete(agent_name="ProviderTestAgent")
+62 -13
View File
@@ -66,6 +66,7 @@ __all__ = [
"UsageContent",
"UsageDetails",
"merge_chat_options",
"normalize_tools",
"prepare_function_call_results",
"prepend_instructions_to_messages",
"validate_chat_options",
@@ -3490,6 +3491,60 @@ async def validate_chat_options(options: dict[str, Any]) -> dict[str, Any]:
return result
def normalize_tools(
tools: (
ToolProtocol
| Callable[..., Any]
| MutableMapping[str, Any]
| Sequence[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None
),
) -> list[ToolProtocol | MutableMapping[str, Any]]:
"""Normalize tools into a list.
Converts callables to AIFunction objects and ensures all tools are either
ToolProtocol instances or MutableMappings.
Args:
tools: Tools to normalize - can be a single tool, callable, or sequence.
Returns:
Normalized list of tools.
Examples:
.. code-block:: python
from agent_framework import normalize_tools, ai_function
@ai_function
def my_tool(x: int) -> int:
return x * 2
# Single tool
tools = normalize_tools(my_tool)
# List of tools
tools = normalize_tools([my_tool, another_tool])
"""
final_tools: list[ToolProtocol | MutableMapping[str, Any]] = []
if not tools:
return final_tools
if not isinstance(tools, Sequence) or isinstance(tools, (str, MutableMapping)):
# Single tool (not a sequence, or is a mapping which shouldn't be treated as sequence)
if not isinstance(tools, (ToolProtocol, MutableMapping)):
return [ai_function(tools)]
return [tools]
for tool in tools:
if isinstance(tool, (ToolProtocol, MutableMapping)):
final_tools.append(tool)
else:
# Convert callable to AIFunction
final_tools.append(ai_function(tool))
return final_tools
async def validate_tools(
tools: (
ToolProtocol
@@ -3528,16 +3583,12 @@ async def validate_tools(
# List of tools
tools = await validate_tools([my_tool, another_tool])
"""
# Sequence of tools - convert callables and expand MCP tools
# Use normalize_tools for common sync logic (converts callables to AIFunction)
normalized = normalize_tools(tools)
# Handle MCP tool expansion (async-only)
final_tools: list[ToolProtocol | MutableMapping[str, Any]] = []
if not tools:
return final_tools
if not isinstance(tools, Sequence) or isinstance(tools, (str, MutableMapping)):
# Single tool (not a sequence, or is a mapping which shouldn't be treated as sequence)
if not isinstance(tools, (ToolProtocol, MutableMapping)):
return [ai_function(tools)]
return [tools]
for tool in tools:
for tool in normalized:
# Import MCPTool here to avoid circular imports
from ._mcp import MCPTool
@@ -3546,11 +3597,9 @@ async def validate_tools(
if not tool.is_connected:
await tool.connect()
final_tools.extend(tool.functions) # type: ignore
elif isinstance(tool, (ToolProtocol, MutableMapping)):
final_tools.append(tool)
else:
# Convert callable to AIFunction
final_tools.append(ai_function(tool))
final_tools.append(tool)
return final_tools
@@ -10,6 +10,7 @@ _IMPORTS: dict[str, tuple[str, str]] = {
"AzureAIAgentClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
"AzureAIAgentOptions": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
"AzureAIClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
"AzureAIProjectAgentProvider": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
"AzureAISearchContextProvider": ("agent_framework_azure_ai_search", "agent-framework-azure-ai-search"),
"AzureAISearchSettings": ("agent_framework_azure_ai_search", "agent-framework-azure-ai-search"),
"AzureAISettings": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
@@ -1,6 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework_azure_ai import AzureAIAgentClient, AzureAIClient, AzureAISettings
from agent_framework_azure_ai import AzureAIAgentClient, AzureAIClient, AzureAIProjectAgentProvider, AzureAISettings
from agent_framework_azure_ai_search import AzureAISearchContextProvider, AzureAISearchSettings
from agent_framework_azurefunctions import (
AgentCallbackContext,
@@ -21,6 +21,7 @@ __all__ = [
"AgentResponseCallbackProtocol",
"AzureAIAgentClient",
"AzureAIClient",
"AzureAIProjectAgentProvider",
"AzureAISearchContextProvider",
"AzureAISearchSettings",
"AzureAISettings",
@@ -6,8 +6,9 @@ This folder contains examples demonstrating different ways to create and use age
| File | Description |
|------|-------------|
| [`azure_ai_basic.py`](azure_ai_basic.py) | The simplest way to create an agent using `AzureAIClient`. Demonstrates both streaming and non-streaming responses with function tools. Shows automatic agent creation and basic weather functionality. |
| [`azure_ai_use_latest_version.py`](azure_ai_use_latest_version.py) | Demonstrates how to reuse the latest version of an existing agent instead of creating a new agent version on each instantiation using the `use_latest_version=True` parameter. |
| [`azure_ai_basic.py`](azure_ai_basic.py) | The simplest way to create an agent using `AzureAIProjectAgentProvider`. Demonstrates both streaming and non-streaming responses with function tools. Shows automatic agent creation and basic weather functionality. |
| [`azure_ai_provider_methods.py`](azure_ai_provider_methods.py) | Comprehensive guide to `AzureAIProjectAgentProvider` methods: `create_agent()` for creating new agents, `get_agent()` for retrieving existing agents (by name, reference, or details), and `as_agent()` for wrapping SDK objects without HTTP calls. |
| [`azure_ai_use_latest_version.py`](azure_ai_use_latest_version.py) | Demonstrates how to reuse the latest version of an existing agent instead of creating a new agent version on each instantiation by using `provider.get_agent()` to retrieve the latest version. |
| [`azure_ai_with_agent_to_agent.py`](azure_ai_with_agent_to_agent.py) | Shows how to use Agent-to-Agent (A2A) capabilities with Azure AI agents to enable communication with other agents using the A2A protocol. Requires an A2A connection configured in your Azure AI project. |
| [`azure_ai_with_azure_ai_search.py`](azure_ai_with_azure_ai_search.py) | Shows how to use Azure AI Search with Azure AI agents to search through indexed data and answer user questions with proper citations. Requires an Azure AI Search connection and index configured in your Azure AI project. |
| [`azure_ai_with_bing_grounding.py`](azure_ai_with_bing_grounding.py) | Shows how to use Bing Grounding search with Azure AI agents to search the web for current information and provide grounded responses with citations. Requires a Bing connection configured in your Azure AI project. |
@@ -4,14 +4,14 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Azure AI Agent Basic Example
This sample demonstrates basic usage of AzureAIClient.
This sample demonstrates basic usage of AzureAIProjectAgentProvider.
Shows both streaming and non-streaming responses with function tools.
"""
@@ -28,17 +28,18 @@ async def non_streaming_example() -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
@@ -49,17 +50,18 @@ async def streaming_example() -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
query = "What's the weather like in Tokyo?"
print(f"User: {query}")
print("Agent: ", end="", flush=True)
@@ -0,0 +1,293 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import AgentReference, PromptAgentDefinition
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Azure AI Project Agent Provider Methods Example
This sample demonstrates the three main methods of AzureAIProjectAgentProvider:
1. create_agent() - Create a new agent on the Azure AI service
2. get_agent() - Retrieve an existing agent from the service
3. as_agent() - Wrap an SDK agent version object without making HTTP calls
It also shows how to use a single provider instance to spawn multiple agents
with different configurations, which is efficient for multi-agent scenarios.
Each method returns a ChatAgent that can be used for conversations.
"""
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}C."
async def create_agent_example() -> None:
"""Example of using provider.create_agent() to create a new agent.
This method creates a new agent version on the Azure AI service and returns
a ChatAgent. Use this when you want to create a fresh agent with
specific configuration.
"""
print("=== provider.create_agent() Example ===")
async with (
AzureCliCredential() as credential,
AzureAIProjectAgentProvider(credential=credential) as provider,
):
# Create a new agent with custom configuration
agent = await provider.create_agent(
name="WeatherAssistant",
instructions="You are a helpful weather assistant. Always be concise.",
description="An agent that provides weather information.",
tools=get_weather,
)
print(f"Created agent: {agent.name}")
print(f"Agent ID: {agent.id}")
query = "What's the weather in Paris?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async def get_agent_by_name_example() -> None:
"""Example of using provider.get_agent(name=...) to retrieve an agent by name.
This method fetches the latest version of an existing agent from the service.
Use this when you know the agent name and want to use the most recent version.
"""
print("=== provider.get_agent(name=...) Example ===")
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
# First, create an agent using the SDK directly
created_agent = await project_client.agents.create_version(
agent_name="TestAgentByName",
description="Test agent for get_agent by name example.",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="You are a helpful assistant. End each response with '- Your Assistant'.",
),
)
try:
# Get the agent using the provider by name (fetches latest version)
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = await provider.get_agent(name=created_agent.name)
print(f"Retrieved agent: {agent.name}")
query = "Hello!"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
finally:
# Clean up the agent
await project_client.agents.delete_version(
agent_name=created_agent.name, agent_version=created_agent.version
)
async def get_agent_by_reference_example() -> None:
"""Example of using provider.get_agent(reference=...) to retrieve a specific agent version.
This method fetches a specific version of an agent using an AgentReference.
Use this when you need to use a particular version of an agent.
"""
print("=== provider.get_agent(reference=...) Example ===")
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
# First, create an agent using the SDK directly
created_agent = await project_client.agents.create_version(
agent_name="TestAgentByReference",
description="Test agent for get_agent by reference example.",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="You are a helpful assistant. Always respond in uppercase.",
),
)
try:
# Get the agent using an AgentReference with specific version
provider = AzureAIProjectAgentProvider(project_client=project_client)
reference = AgentReference(name=created_agent.name, version=created_agent.version)
agent = await provider.get_agent(reference=reference)
print(f"Retrieved agent: {agent.name} (version via reference)")
query = "Say hello"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
finally:
# Clean up the agent
await project_client.agents.delete_version(
agent_name=created_agent.name, agent_version=created_agent.version
)
async def get_agent_by_details_example() -> None:
"""Example of using provider.get_agent(details=...) with pre-fetched AgentDetails.
This method uses pre-fetched AgentDetails to get the latest version.
Use this when you already have AgentDetails from a previous API call.
"""
print("=== provider.get_agent(details=...) Example ===")
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
# First, create an agent using the SDK directly
created_agent = await project_client.agents.create_version(
agent_name="TestAgentByDetails",
description="Test agent for get_agent by details example.",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="You are a helpful assistant. Always include an emoji in your response.",
),
)
try:
# Fetch AgentDetails separately (simulating a previous API call)
agent_details = await project_client.agents.get(agent_name=created_agent.name)
# Get the agent using the pre-fetched details (sync - no HTTP call)
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = provider.as_agent(agent_details.versions.latest)
print(f"Retrieved agent: {agent.name} (from pre-fetched details)")
query = "How are you today?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
finally:
# Clean up the agent
await project_client.agents.delete_version(
agent_name=created_agent.name, agent_version=created_agent.version
)
async def multiple_agents_example() -> None:
"""Example of using a single provider to spawn multiple agents.
A single provider instance can create multiple agents with different
configurations.
"""
print("=== Multiple Agents from Single Provider Example ===")
async with (
AzureCliCredential() as credential,
AzureAIProjectAgentProvider(credential=credential) as provider,
):
# Create multiple specialized agents from the same provider
weather_agent = await provider.create_agent(
name="WeatherExpert",
instructions="You are a weather expert. Provide brief weather information.",
tools=get_weather,
)
translator_agent = await provider.create_agent(
name="Translator",
instructions="You are a translator. Translate any text to French. Only output the translation.",
)
poet_agent = await provider.create_agent(
name="Poet",
instructions="You are a poet. Respond to everything with a short haiku.",
)
print(f"Created agents: {weather_agent.name}, {translator_agent.name}, {poet_agent.name}\n")
# Use each agent for its specialty
weather_query = "What's the weather in London?"
print(f"User to WeatherExpert: {weather_query}")
weather_result = await weather_agent.run(weather_query)
print(f"WeatherExpert: {weather_result}\n")
translate_query = "Hello, how are you today?"
print(f"User to Translator: {translate_query}")
translate_result = await translator_agent.run(translate_query)
print(f"Translator: {translate_result}\n")
poet_query = "Tell me about the morning sun"
print(f"User to Poet: {poet_query}")
poet_result = await poet_agent.run(poet_query)
print(f"Poet: {poet_result}\n")
async def as_agent_example() -> None:
"""Example of using provider.as_agent() to wrap an SDK object without HTTP calls.
This method wraps an existing AgentVersionDetails into a ChatAgent without
making additional HTTP calls. Use this when you already have the full
AgentVersionDetails from a previous SDK operation.
"""
print("=== provider.as_agent() Example ===")
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
# Create an agent using the SDK directly - this returns AgentVersionDetails
agent_version_details = await project_client.agents.create_version(
agent_name="TestAgentAsAgent",
description="Test agent for as_agent example.",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="You are a helpful assistant. Keep responses under 20 words.",
),
)
try:
# Wrap the SDK object directly without any HTTP calls
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = provider.as_agent(agent_version_details)
print(f"Wrapped agent: {agent.name} (no HTTP call needed)")
print(f"Agent version: {agent_version_details.version}")
query = "What can you do?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
finally:
# Clean up the agent
await project_client.agents.delete_version(
agent_name=agent_version_details.name, agent_version=agent_version_details.version
)
async def main() -> None:
print("=== Azure AI Project Agent Provider Methods Example ===\n")
await create_agent_example()
await get_agent_by_name_example()
await get_agent_by_reference_example()
await get_agent_by_details_example()
await as_agent_example()
await multiple_agents_example()
if __name__ == "__main__":
asyncio.run(main())
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -13,7 +13,7 @@ Azure AI Agent Latest Version Example
This sample demonstrates how to reuse the latest version of an existing agent
instead of creating a new agent version on each instantiation. The first call creates a new agent,
while subsequent calls with `use_latest_version=True` reuse the latest agent version.
while subsequent calls with `get_agent()` reuse the latest agent version.
"""
@@ -28,39 +28,36 @@ def get_weather(
async def main() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with AzureCliCredential() as credential:
async with (
AzureAIClient(
credential=credential,
).create_agent(
name="MyWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
# First query will create a new agent
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
async with (
AzureCliCredential() as credential,
AzureAIProjectAgentProvider(credential=credential) as provider,
):
# First call creates a new agent
agent = await provider.create_agent(
name="MyWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
# Create a new agent instance
async with (
AzureAIClient(
credential=credential,
# This parameter will allow to re-use latest agent version
# instead of creating a new one
use_latest_version=True,
).create_agent(
name="MyWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
query = "What's the weather like in Tokyo?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Second call retrieves the existing agent (latest version) instead of creating a new one
# This is useful when you want to reuse an agent that was created earlier
agent2 = await provider.get_agent(
name="MyWeatherAgent",
tools=get_weather, # Tools must be provided for function tools
)
query = "What's the weather like in Tokyo?"
print(f"User: {query}")
result = await agent2.run(query)
print(f"Agent: {result}\n")
print(f"First agent ID with version: {agent.id}")
print(f"Second agent ID with version: {agent2.id}")
if __name__ == "__main__":
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Agent-to-Agent (A2A) Example
This sample demonstrates usage of AzureAIClient with Agent-to-Agent (A2A) capabilities
This sample demonstrates usage of AzureAIProjectAgentProvider with Agent-to-Agent (A2A) capabilities
to enable communication with other agents using the A2A protocol.
Prerequisites:
@@ -26,21 +26,23 @@ async def main() -> None:
"type": "a2a_preview",
"project_connection_id": os.environ["A2A_PROJECT_CONNECTION_ID"],
}
# If the connection is missing a target, we need to set the A2A endpoint URL
if os.environ.get("A2A_ENDPOINT"):
a2a_tool["base_url"] = os.environ["A2A_ENDPOINT"]
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyA2AAgent",
instructions="""You are a helpful assistant that can communicate with other agents.
Use the A2A tool when you need to interact with other agents to complete tasks
or gather information from specialized agents.""",
tools=a2a_tool,
) as agent,
):
)
query = "What can the secondary agent do?"
print(f"User: {query}")
result = await agent.run(query)
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Azure AI Search Example
This sample demonstrates usage of AzureAIClient with Azure AI Search
This sample demonstrates usage of AzureAIProjectAgentProvider with Azure AI Search
to search through indexed data and answer user questions about it.
Prerequisites:
@@ -21,7 +21,9 @@ Prerequisites:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MySearchAgent",
instructions="""You are a helpful assistant. You must always provide citations for
answers using the tool and render them as: `[message_idx:search_idx†source]`.""",
@@ -38,8 +40,8 @@ async def main() -> None:
]
},
},
) as agent,
):
)
query = "Tell me about insurance options"
print(f"User: {query}")
result = await agent.run(query)
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Bing Custom Search Example
This sample demonstrates usage of AzureAIClient with Bing Custom Search
This sample demonstrates usage of AzureAIProjectAgentProvider with Bing Custom Search
to search custom search instances and provide responses with relevant results.
Prerequisites:
@@ -21,7 +21,9 @@ Prerequisites:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyCustomSearchAgent",
instructions="""You are a helpful agent that can use Bing Custom Search tools to assist users.
Use the available Bing Custom Search tools to answer questions and perform tasks.""",
@@ -36,8 +38,8 @@ async def main() -> None:
]
},
},
) as agent,
):
)
query = "Tell me more about foundry agent service"
print(f"User: {query}")
result = await agent.run(query)
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Bing Grounding Example
This sample demonstrates usage of AzureAIClient with Bing Grounding
This sample demonstrates usage of AzureAIProjectAgentProvider with Bing Grounding
to search the web for current information and provide grounded responses.
Prerequisites:
@@ -27,7 +27,9 @@ To get your Bing connection ID:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyBingGroundingAgent",
instructions="""You are a helpful assistant that can search the web for current information.
Use the Bing search tool to find up-to-date information and provide accurate, well-sourced answers.
@@ -42,8 +44,8 @@ async def main() -> None:
]
},
},
) as agent,
):
)
query = "What is today's date and weather in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Browser Automation Example
This sample demonstrates usage of AzureAIClient with Browser Automation
This sample demonstrates usage of AzureAIProjectAgentProvider with Browser Automation
to perform automated web browsing tasks and provide responses based on web interactions.
Prerequisites:
@@ -21,7 +21,9 @@ Prerequisites:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyBrowserAutomationAgent",
instructions="""You are an Agent helping with browser automation tasks.
You can answer questions, provide information, and assist with various tasks
@@ -34,8 +36,8 @@ async def main() -> None:
}
},
},
) as agent,
):
)
query = """Your goal is to report the percent of Microsoft year-to-date stock price change.
To do that, go to the website finance.yahoo.com.
At the top of the page, you will find a search bar.
@@ -3,7 +3,7 @@
import asyncio
from agent_framework import ChatResponse, HostedCodeInterpreterTool
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from openai.types.responses.response import Response as OpenAIResponse
from openai.types.responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall
@@ -11,22 +11,24 @@ from openai.types.responses.response_code_interpreter_tool_call import ResponseC
"""
Azure AI Agent Code Interpreter Example
This sample demonstrates using HostedCodeInterpreterTool with AzureAIClient
This sample demonstrates using HostedCodeInterpreterTool with AzureAIProjectAgentProvider
for Python code execution and mathematical problem solving.
"""
async def main() -> None:
"""Example showing how to use the HostedCodeInterpreterTool with AzureAIClient."""
"""Example showing how to use the HostedCodeInterpreterTool with AzureAIProjectAgentProvider."""
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyCodeInterpreterAgent",
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=HostedCodeInterpreterTool(),
) as agent,
):
)
query = "Use code to get the factorial of 100?"
print(f"User: {query}")
result = await agent.run(query)
@@ -3,19 +3,19 @@
import asyncio
from agent_framework import (
AgentResponseUpdate,
CitationAnnotation,
HostedCodeInterpreterTool,
HostedFileContent,
TextContent,
)
from agent_framework._agents import AgentResponseUpdate
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI V2 Code Interpreter File Generation Sample
This sample demonstrates how the V2 AzureAIClient handles file annotations
This sample demonstrates how the AzureAIProjectAgentProvider handles file annotations
when code interpreter generates text files. It shows both non-streaming
and streaming approaches to verify file ID extraction.
"""
@@ -32,12 +32,14 @@ async def test_non_streaming() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="V2CodeInterpreterFileAgent",
instructions="You are a helpful assistant that can write and execute Python code to create files.",
tools=HostedCodeInterpreterTool(),
) as agent,
):
)
print(f"User: {QUERY}\n")
result = await agent.run(QUERY)
@@ -66,12 +68,14 @@ async def test_streaming() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="V2CodeInterpreterFileAgentStreaming",
instructions="You are a helpful assistant that can write and execute Python code to create files.",
tools=HostedCodeInterpreterTool(),
) as agent,
):
)
print(f"User: {QUERY}\n")
annotations_found: list[str] = []
text_chunks: list[str] = []
@@ -102,7 +106,7 @@ async def test_streaming() -> None:
async def main() -> None:
print("AzureAIClient Code Interpreter File Generation Test\n")
print("AzureAIProjectAgentProvider Code Interpreter File Generation Test\n")
await test_non_streaming()
await test_streaming()
@@ -3,8 +3,7 @@
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition
from azure.identity.aio import AzureCliCredential
@@ -12,19 +11,23 @@ from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Existing Agent Example
This sample demonstrates working with pre-existing Azure AI Agents by providing
agent name and version, showing agent reuse patterns for production scenarios.
This sample demonstrates working with pre-existing Azure AI Agents by using provider.get_agent() method,
showing agent reuse patterns for production scenarios.
"""
async def main() -> None:
async def using_provider_get_agent() -> None:
print("=== Get existing Azure AI agent with provider.get_agent() ===")
# Create the client
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
# Create remote agent using SDK directly
azure_ai_agent = await project_client.agents.create_version(
agent_name="MyNewTestAgent",
description="Agent for testing purposes.",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
# Setting specific requirements to verify that this agent is used.
@@ -32,27 +35,22 @@ async def main() -> None:
),
)
chat_client = AzureAIClient(
project_client=project_client,
agent_name=azure_ai_agent.name,
# Property agent_version is required for existing agents.
# If this property is not configured, the client will try to create a new agent using
# provided agent_name.
# It's also possible to leave agent_version empty but set use_latest_version=True.
# This will pull latest available agent version and use that version for operations.
agent_version=azure_ai_agent.version,
)
try:
async with ChatAgent(
chat_client=chat_client,
) as agent:
query = "How are you?"
print(f"User: {query}")
result = await agent.run(query)
# Response that indicates that previously created agent was used:
# "I'm here and ready to help you! How can I assist you today? [END]"
print(f"Agent: {result}\n")
# Get newly created agent as ChatAgent by using provider.get_agent()
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = await provider.get_agent(name=azure_ai_agent.name)
# Verify agent properties
print(f"Agent ID: {agent.id}")
print(f"Agent name: {agent.name}")
print(f"Agent description: {agent.description}")
query = "How are you?"
print(f"User: {query}")
result = await agent.run(query)
# Response that indicates that previously created agent was used:
# "I'm here and ready to help you! How can I assist you today? [END]"
print(f"Agent: {result}\n")
finally:
# Clean up the agent manually
await project_client.agents.delete_version(
@@ -60,5 +58,9 @@ async def main() -> None:
)
async def main() -> None:
await using_provider_get_agent()
if __name__ == "__main__":
asyncio.run(main())
@@ -4,7 +4,7 @@ import os
from random import randint
from typing import Annotated
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -12,7 +12,7 @@ from pydantic import Field
"""
Azure AI Agent Existing Conversation Example
This sample demonstrates usage of AzureAIClient with existing conversation created on service side.
This sample demonstrates usage of AzureAIProjectAgentProvider with existing conversation created on service side.
"""
@@ -24,9 +24,9 @@ def get_weather(
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def example_with_client() -> None:
"""Example shows how to specify existing conversation ID when initializing Azure AI Client."""
print("=== Azure AI Agent With Existing Conversation and Client ===")
async def example_with_conversation_id() -> None:
"""Example shows how to use existing conversation ID with the provider."""
print("=== Azure AI Agent With Existing Conversation ===")
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
@@ -37,24 +37,23 @@ async def example_with_client() -> None:
conversation_id = conversation.id
print(f"Conversation ID: {conversation_id}")
async with AzureAIClient(
project_client=project_client,
# Specify conversation ID on client level
conversation_id=conversation_id,
).create_agent(
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = await provider.create_agent(
name="BasicAgent",
instructions="You are a helpful agent.",
tools=get_weather,
) as agent:
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
)
query = "What was my last question?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
# Pass conversation_id at run level
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query, conversation_id=conversation_id)
print(f"Agent: {result.text}\n")
query = "What was my last question?"
print(f"User: {query}")
result = await agent.run(query, conversation_id=conversation_id)
print(f"Agent: {result.text}\n")
async def example_with_thread() -> None:
@@ -63,12 +62,14 @@ async def example_with_thread() -> None:
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
AzureAIClient(project_client=project_client).create_agent(
):
provider = AzureAIProjectAgentProvider(project_client=project_client)
agent = await provider.create_agent(
name="BasicAgent",
instructions="You are a helpful agent.",
tools=get_weather,
) as agent,
):
)
# Create a conversation using OpenAI client
openai_client = project_client.get_openai_client()
conversation = await openai_client.conversations.create()
@@ -90,7 +91,7 @@ async def example_with_thread() -> None:
async def main() -> None:
await example_with_client()
await example_with_conversation_id()
await example_with_thread()
@@ -5,8 +5,7 @@ import os
from random import randint
from typing import Annotated
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -27,22 +26,22 @@ def get_weather(
async def main() -> None:
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
ChatAgent(
chat_client=AzureAIClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model_deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=credential,
agent_name="WeatherAgent",
),
AzureAIProjectAgentProvider(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=credential,
) as provider,
):
agent = await provider.create_agent(
name="WeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
query = "What's the weather like in New York?"
print(f"User: {query}")
result = await agent.run(query)
@@ -4,8 +4,8 @@ import asyncio
import os
from pathlib import Path
from agent_framework import ChatAgent, HostedFileSearchTool, HostedVectorStoreContent
from agent_framework.azure import AzureAIClient
from agent_framework import HostedFileSearchTool, HostedVectorStoreContent
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.agents.aio import AgentsClient
from azure.ai.agents.models import FileInfo, VectorStore
from azure.identity.aio import AzureCliCredential
@@ -32,7 +32,7 @@ async def main() -> None:
async with (
AzureCliCredential() as credential,
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
AzureAIClient(credential=credential) as client,
AzureAIProjectAgentProvider(credential=credential) as provider,
):
try:
# 1. Upload file and create vector store
@@ -48,22 +48,21 @@ async def main() -> None:
# 2. Create file search tool with uploaded resources
file_search_tool = HostedFileSearchTool(inputs=[HostedVectorStoreContent(vector_store_id=vector_store.id)])
# 3. Create an agent with file search capabilities
# The tool_resources are automatically extracted from HostedFileSearchTool
async with ChatAgent(
chat_client=client,
# 3. Create an agent with file search capabilities using the provider
agent = await provider.create_agent(
name="EmployeeSearchAgent",
instructions=(
"You are a helpful assistant that can search through uploaded employee files "
"to answer questions about employees."
),
tools=file_search_tool,
) as agent:
# 4. Simulate conversation with the agent
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
response = await agent.run(user_input)
print(f"# Agent: {response.text}")
)
# 4. Simulate conversation with the agent
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
response = await agent.run(user_input)
print(f"# Agent: {response.text}")
finally:
# 5. Cleanup: Delete the vector store and file in case of earlier failure to prevent orphaned resources.
if vector_store:
@@ -4,7 +4,7 @@ import asyncio
from typing import Any
from agent_framework import AgentProtocol, AgentResponse, AgentThread, ChatMessage, HostedMCPTool
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
@@ -59,12 +59,13 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
async def run_hosted_mcp_without_approval() -> None:
"""Example showing MCP Tools without approval."""
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyLearnDocsAgent",
instructions="You are a helpful assistant that can help with Microsoft documentation questions.",
tools=HostedMCPTool(
@@ -72,8 +73,8 @@ async def run_hosted_mcp_without_approval() -> None:
url="https://learn.microsoft.com/api/mcp",
approval_mode="never_require",
),
) as agent,
):
)
query = "How to create an Azure storage account using az cli?"
print(f"User: {query}")
result = await handle_approvals_without_thread(query, agent)
@@ -84,12 +85,13 @@ async def run_hosted_mcp_with_approval_and_thread() -> None:
"""Example showing MCP Tools with approvals using a thread."""
print("=== MCP with approvals and with thread ===")
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyApiSpecsAgent",
instructions="You are a helpful agent that can use MCP tools to assist users.",
tools=HostedMCPTool(
@@ -97,8 +99,8 @@ async def run_hosted_mcp_with_approval_and_thread() -> None:
url="https://gitmcp.io/Azure/azure-rest-api-specs",
approval_mode="always_require",
),
) as agent,
):
)
thread = agent.get_new_thread()
query = "Please summarize the Azure REST API specifications Readme"
print(f"User: {query}")
@@ -4,13 +4,13 @@ from pathlib import Path
import aiofiles
from agent_framework import DataContent, HostedImageGenerationTool
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Image Generation Example
This sample demonstrates basic usage of AzureAIClient to create an agent
This sample demonstrates basic usage of AzureAIProjectAgentProvider to create an agent
that can generate images based on user requirements.
Pre-requisites:
@@ -20,12 +20,13 @@ Pre-requisites:
async def main() -> None:
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ImageGenAgent",
instructions="Generate images based on user requirements.",
tools=[
@@ -37,8 +38,8 @@ async def main() -> None:
}
)
],
) as agent,
):
)
query = "Generate an image of Microsoft logo."
print(f"User: {query}")
result = await agent.run(
@@ -3,7 +3,7 @@
import asyncio
from agent_framework import MCPStreamableHTTPTool
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
@@ -19,20 +19,22 @@ Pre-requisites:
async def main() -> None:
"""Example showing use of Local MCP Tool with AzureAIClient."""
"""Example showing use of Local MCP Tool with AzureAIProjectAgentProvider."""
print("=== Azure AI Agent with Local MCP Tools Example ===\n")
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="DocsAgent",
instructions="You are a helpful assistant that can help with Microsoft documentation questions.",
tools=MCPStreamableHTTPTool(
name="Microsoft Learn MCP",
url="https://learn.microsoft.com/api/mcp",
),
) as agent,
):
)
# First query
first_query = "How to create an Azure storage account using az cli?"
print(f"User: {first_query}")
@@ -3,7 +3,7 @@ import asyncio
import os
import uuid
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import MemoryStoreDefaultDefinition, MemoryStoreDefaultOptions
from azure.identity.aio import AzureCliCredential
@@ -11,7 +11,7 @@ from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Memory Search Example
This sample demonstrates usage of AzureAIClient with memory search capabilities
This sample demonstrates usage of AzureAIProjectAgentProvider with memory search capabilities
to retrieve relevant past user messages and maintain conversation context across sessions.
It shows explicit memory store creation using Azure AI Projects client and agent creation
using the Agent Framework.
@@ -46,18 +46,20 @@ async def main() -> None:
)
print(f"Created memory store: {memory_store.name} ({memory_store.id}): {memory_store.description}")
# Then, create the agent using Agent Framework
async with AzureAIClient(credential=credential).create_agent(
name="MyMemoryAgent",
instructions="""You are a helpful assistant that remembers past conversations.
Use the memory search tool to recall relevant information from previous interactions.""",
tools={
"type": "memory_search",
"memory_store_name": memory_store.name,
"scope": "user_123",
"update_delay": 1, # Wait 1 second before updating memories (use higher value in production)
},
) as agent:
# Then, create the agent using Agent Framework provider
async with AzureAIProjectAgentProvider(credential=credential) as provider:
agent = await provider.create_agent(
name="MyMemoryAgent",
instructions="""You are a helpful assistant that remembers past conversations.
Use the memory search tool to recall relevant information from previous interactions.""",
tools={
"type": "memory_search",
"memory_store_name": memory_store.name,
"scope": "user_123",
"update_delay": 1, # Wait 1 second before updating memories (use higher value in production)
},
)
# First interaction - establish some preferences
print("=== First conversation ===")
query1 = "I prefer dark roast coffee"
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Microsoft Fabric Example
This sample demonstrates usage of AzureAIClient with Microsoft Fabric
This sample demonstrates usage of AzureAIProjectAgentProvider with Microsoft Fabric
to query Fabric data sources and provide responses based on data analysis.
Prerequisites:
@@ -21,7 +21,9 @@ Prerequisites:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyFabricAgent",
instructions="You are a helpful assistant.",
tools={
@@ -34,8 +36,8 @@ async def main() -> None:
]
},
},
) as agent,
):
)
query = "Tell me about sales records"
print(f"User: {query}")
result = await agent.run(query)
@@ -4,13 +4,13 @@ import json
from pathlib import Path
import aiofiles
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with OpenAPI Tool Example
This sample demonstrates usage of AzureAIClient with OpenAPI tools
This sample demonstrates usage of AzureAIProjectAgentProvider with OpenAPI tools
to call external APIs defined by OpenAPI specifications.
Prerequisites:
@@ -29,7 +29,9 @@ async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyOpenAPIAgent",
instructions="""You are a helpful assistant that can use country APIs to provide information.
Use the available OpenAPI tools to answer questions about countries, currencies, and demographics.""",
@@ -42,8 +44,8 @@ async def main() -> None:
"auth": {"type": "anonymous"},
},
},
) as agent,
):
)
query = "What is the name and population of the country that uses currency with abbreviation THB?"
print(f"User: {query}")
result = await agent.run(query)
@@ -2,14 +2,14 @@
import asyncio
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from pydantic import BaseModel, ConfigDict
"""
Azure AI Agent Response Format Example
This sample demonstrates basic usage of AzureAIClient with response format,
This sample demonstrates basic usage of AzureAIProjectAgentProvider with response format,
also known as structured outputs.
"""
@@ -24,24 +24,23 @@ class ReleaseBrief(BaseModel):
async def main() -> None:
"""Example of using response_format property."""
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ProductMarketerAgent",
instructions="Return launch briefs as structured JSON.",
) as agent,
):
query = "Draft a launch brief for the Contoso Note app."
print(f"User: {query}")
result = await agent.run(
query,
# Specify type to use as response
response_format=ReleaseBrief,
)
query = "Draft a launch brief for the Contoso Note app."
print(f"User: {query}")
result = await agent.run(query)
if isinstance(result.value, ReleaseBrief):
release_brief = result.value
print("Agent:")
@@ -2,13 +2,13 @@
import asyncio
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent Response Format Example with Runtime JSON Schema
This sample demonstrates basic usage of AzureAIClient with response format,
This sample demonstrates basic usage of AzureAIProjectAgentProvider with response format,
also known as structured outputs.
"""
@@ -29,35 +29,32 @@ runtime_schema = {
async def main() -> None:
"""Example of using response_format property."""
"""Example of using response_format property with a runtime JSON schema."""
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
name="ProductMarketerAgent",
instructions="Return launch briefs as structured JSON.",
) as agent,
AzureAIProjectAgentProvider(credential=credential) as provider,
):
query = "Draft a launch brief for the Contoso Note app."
print(f"User: {query}")
result = await agent.run(
query,
# Specify type to use as response
options={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
# Pass response_format at agent creation time using dict schema format
agent = await provider.create_agent(
name="WeatherDigestAgent",
instructions="Return sample weather digest as structured JSON.",
response_format={
"type": "json_schema",
"json_schema": {
"name": runtime_schema["title"],
"strict": True,
"schema": runtime_schema,
},
},
)
query = "Draft a sample weather digest."
print(f"User: {query}")
result = await agent.run(query)
print(result.text)
@@ -2,13 +2,13 @@
import asyncio
import os
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with SharePoint Example
This sample demonstrates usage of AzureAIClient with SharePoint
This sample demonstrates usage of AzureAIProjectAgentProvider with SharePoint
to search through SharePoint content and answer user questions about it.
Prerequisites:
@@ -21,7 +21,9 @@ Prerequisites:
async def main() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MySharePointAgent",
instructions="""You are a helpful agent that can use SharePoint tools to assist users.
Use the available SharePoint tools to answer questions and perform tasks.""",
@@ -35,8 +37,8 @@ async def main() -> None:
]
},
},
) as agent,
):
)
query = "What is Contoso whistleblower policy?"
print(f"User: {query}")
result = await agent.run(query)
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -30,12 +30,14 @@ async def example_with_automatic_thread_creation() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
# First conversation - no thread provided, will be created automatically
query1 = "What's the weather like in Seattle?"
print(f"User: {query1}")
@@ -59,12 +61,14 @@ async def example_with_thread_persistence_in_memory() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
# Create a new thread that will be reused
thread = agent.get_new_thread()
@@ -100,12 +104,14 @@ async def example_with_existing_thread_id() -> None:
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
)
# Start a conversation and get the thread ID
thread = agent.get_new_thread()
@@ -121,21 +127,21 @@ async def example_with_existing_thread_id() -> None:
if existing_thread_id:
print("\n--- Continuing with the same thread ID in a new agent instance ---")
async with (
AzureAIClient(credential=credential).create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
# Create a thread with the existing ID
thread = agent.get_new_thread(service_thread_id=existing_thread_id)
# Create a new agent instance from the same provider
agent2 = await provider.create_agent(
name="BasicWeatherAgent",
instructions="You are a helpful weather agent.",
tools=get_weather,
)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent.run(query2, thread=thread)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation from the previous thread by using thread ID.\n")
# Create a thread with the existing ID
thread = agent2.get_new_thread(service_thread_id=existing_thread_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
result2 = await agent2.run(query2, thread=thread)
print(f"Agent: {result2.text}")
print("Note: The agent continues the conversation from the previous thread by using thread ID.\n")
async def main() -> None:
@@ -3,13 +3,13 @@
import asyncio
from agent_framework import HostedWebSearchTool
from agent_framework.azure import AzureAIClient
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent With Web Search
This sample demonstrates basic usage of AzureAIClient to create an agent
This sample demonstrates basic usage of AzureAIProjectAgentProvider to create an agent
that can perform web searches using the HostedWebSearchTool.
Pre-requisites:
@@ -19,17 +19,18 @@ Pre-requisites:
async def main() -> None:
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(credential=credential).create_agent(
AzureAIProjectAgentProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="WebsearchAgent",
instructions="You are a helpful assistant that can search the web",
tools=[HostedWebSearchTool()],
) as agent,
):
)
query = "What's the weather today in Seattle?"
print(f"User: {query}")
result = await agent.run(query)