mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [Feature Branch] Renamed Azure AI agent and small fixes (#1919)
* Renaming * Small fixes * Update python/packages/core/agent_framework/openai/_shared.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
39d3111734
commit
8135a99f9e
@@ -3,7 +3,7 @@
|
||||
import importlib.metadata
|
||||
|
||||
from ._chat_client import AzureAIAgentClient, AzureAISettings
|
||||
from ._chat_client_v2 import AzureAIAgentClientV2
|
||||
from ._client import AzureAIClient
|
||||
|
||||
try:
|
||||
__version__ = importlib.metadata.version(__name__)
|
||||
@@ -12,7 +12,7 @@ except importlib.metadata.PackageNotFoundError:
|
||||
|
||||
__all__ = [
|
||||
"AzureAIAgentClient",
|
||||
"AzureAIAgentClientV2",
|
||||
"AzureAIClient",
|
||||
"AzureAISettings",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
+3
-10
@@ -37,14 +37,14 @@ else:
|
||||
logger = get_logger("agent_framework.azure")
|
||||
|
||||
|
||||
TAzureAIAgentClient = TypeVar("TAzureAIAgentClient", bound="AzureAIAgentClientV2")
|
||||
TAzureAIClient = TypeVar("TAzureAIClient", bound="AzureAIClient")
|
||||
|
||||
|
||||
@use_function_invocation
|
||||
@use_observability
|
||||
@use_chat_middleware
|
||||
class AzureAIAgentClientV2(OpenAIBaseResponsesClient):
|
||||
"""Azure AI Agent Chat client."""
|
||||
class AzureAIClient(OpenAIBaseResponsesClient):
|
||||
"""Azure AI Agent client."""
|
||||
|
||||
OTEL_PROVIDER_NAME: ClassVar[str] = "azure.ai" # type: ignore[reportIncompatibleVariableOverride, misc]
|
||||
|
||||
@@ -121,12 +121,6 @@ class AzureAIAgentClientV2(OpenAIBaseResponsesClient):
|
||||
"or 'AZURE_AI_PROJECT_ENDPOINT' environment variable."
|
||||
)
|
||||
|
||||
if not azure_ai_settings.model_deployment_name:
|
||||
raise ServiceInitializationError(
|
||||
"Azure AI model deployment name is required. Set via 'model_deployment_name' parameter "
|
||||
"or 'AZURE_AI_MODEL_DEPLOYMENT_NAME' environment variable."
|
||||
)
|
||||
|
||||
# Use provided credential
|
||||
if not async_credential:
|
||||
raise ServiceInitializationError("Azure credential is required when project_client is not provided.")
|
||||
@@ -139,7 +133,6 @@ class AzureAIAgentClientV2(OpenAIBaseResponsesClient):
|
||||
|
||||
# Initialize parent
|
||||
super().__init__(
|
||||
model_id=azure_ai_settings.model_deployment_name, # type: ignore
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
+57
-67
@@ -13,23 +13,23 @@ from agent_framework import (
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
from pydantic import ValidationError
|
||||
|
||||
from agent_framework_azure_ai import AzureAIAgentClientV2, AzureAISettings
|
||||
from agent_framework_azure_ai import AzureAIClient, AzureAISettings
|
||||
|
||||
|
||||
def create_test_azure_ai_client_v2(
|
||||
def create_test_azure_ai_client(
|
||||
mock_project_client: MagicMock,
|
||||
agent_name: str | None = None,
|
||||
agent_version: str | None = None,
|
||||
conversation_id: str | None = None,
|
||||
azure_ai_settings: AzureAISettings | None = None,
|
||||
should_close_client: bool = False,
|
||||
) -> AzureAIAgentClientV2:
|
||||
"""Helper function to create AzureAIAgentClientV2 instances for testing, bypassing normal validation."""
|
||||
) -> AzureAIClient:
|
||||
"""Helper function to create AzureAIClient instances for testing, bypassing normal validation."""
|
||||
if azure_ai_settings is None:
|
||||
azure_ai_settings = AzureAISettings(env_file_path="test.env")
|
||||
|
||||
# Create client instance directly
|
||||
client = object.__new__(AzureAIAgentClientV2)
|
||||
client = object.__new__(AzureAIClient)
|
||||
|
||||
# Set attributes directly
|
||||
client.project_client = mock_project_client
|
||||
@@ -70,13 +70,13 @@ def test_azure_ai_settings_init_with_explicit_values() -> None:
|
||||
assert settings.model_deployment_name == "custom-model"
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_with_project_client(mock_project_client: MagicMock) -> None:
|
||||
"""Test AzureAIAgentClientV2 initialization with existing project_client."""
|
||||
with patch("agent_framework_azure_ai._chat_client_v2.AzureAISettings") as mock_settings:
|
||||
def test_azure_ai_client_init_with_project_client(mock_project_client: MagicMock) -> None:
|
||||
"""Test AzureAIClient initialization with existing project_client."""
|
||||
with patch("agent_framework_azure_ai._client.AzureAISettings") as mock_settings:
|
||||
mock_settings.return_value.project_endpoint = None
|
||||
mock_settings.return_value.model_deployment_name = "test-model"
|
||||
|
||||
client = AzureAIAgentClientV2(
|
||||
client = AzureAIClient(
|
||||
project_client=mock_project_client,
|
||||
agent_name="test-agent",
|
||||
agent_version="1.0",
|
||||
@@ -89,16 +89,16 @@ def test_azure_ai_client_v2_init_with_project_client(mock_project_client: MagicM
|
||||
assert isinstance(client, ChatClientProtocol)
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_auto_create_client(
|
||||
def test_azure_ai_client_init_auto_create_client(
|
||||
azure_ai_unit_test_env: dict[str, str],
|
||||
mock_azure_credential: MagicMock,
|
||||
) -> None:
|
||||
"""Test AzureAIAgentClientV2 initialization with auto-created project_client."""
|
||||
with patch("agent_framework_azure_ai._chat_client_v2.AIProjectClient") as mock_ai_project_client:
|
||||
"""Test AzureAIClient initialization with auto-created project_client."""
|
||||
with patch("agent_framework_azure_ai._client.AIProjectClient") as mock_ai_project_client:
|
||||
mock_project_client = MagicMock()
|
||||
mock_ai_project_client.return_value = mock_project_client
|
||||
|
||||
client = AzureAIAgentClientV2(
|
||||
client = AzureAIClient(
|
||||
project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
model_deployment_name=azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
async_credential=mock_azure_credential,
|
||||
@@ -113,64 +113,54 @@ def test_azure_ai_client_v2_init_auto_create_client(
|
||||
mock_ai_project_client.assert_called_once()
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_missing_project_endpoint() -> None:
|
||||
"""Test AzureAIAgentClientV2 initialization when project_endpoint is missing and no project_client provided."""
|
||||
with patch("agent_framework_azure_ai._chat_client_v2.AzureAISettings") as mock_settings:
|
||||
def test_azure_ai_client_init_missing_project_endpoint() -> None:
|
||||
"""Test AzureAIClient initialization when project_endpoint is missing and no project_client provided."""
|
||||
with patch("agent_framework_azure_ai._client.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"):
|
||||
AzureAIAgentClientV2(async_credential=MagicMock())
|
||||
AzureAIClient(async_credential=MagicMock())
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_missing_model_deployment() -> None:
|
||||
"""Test AzureAIAgentClientV2 initialization when model deployment is missing for agent creation."""
|
||||
with patch("agent_framework_azure_ai._chat_client_v2.AzureAISettings") as mock_settings:
|
||||
mock_settings.return_value.project_endpoint = "https://test.com"
|
||||
mock_settings.return_value.model_deployment_name = None
|
||||
|
||||
with pytest.raises(ServiceInitializationError, match="Azure AI model deployment name is required"):
|
||||
AzureAIAgentClientV2(async_credential=MagicMock())
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_missing_credential(azure_ai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Test AzureAIAgentClientV2.__init__ when async_credential is missing and no project_client provided."""
|
||||
def test_azure_ai_client_init_missing_credential(azure_ai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Test AzureAIClient.__init__ when async_credential is missing and no project_client provided."""
|
||||
with pytest.raises(
|
||||
ServiceInitializationError, match="Azure credential is required when project_client is not provided"
|
||||
):
|
||||
AzureAIAgentClientV2(
|
||||
AzureAIClient(
|
||||
project_endpoint=azure_ai_unit_test_env["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
model_deployment_name=azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
)
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_init_validation_error(mock_azure_credential: MagicMock) -> None:
|
||||
def test_azure_ai_client_init_validation_error(mock_azure_credential: MagicMock) -> None:
|
||||
"""Test that ValidationError in AzureAISettings is properly handled."""
|
||||
with patch("agent_framework_azure_ai._chat_client_v2.AzureAISettings") as mock_settings:
|
||||
with patch("agent_framework_azure_ai._client.AzureAISettings") as mock_settings:
|
||||
mock_settings.side_effect = ValidationError.from_exception_data("test", [])
|
||||
|
||||
with pytest.raises(ServiceInitializationError, match="Failed to create Azure AI settings"):
|
||||
AzureAIAgentClientV2(async_credential=mock_azure_credential)
|
||||
AzureAIClient(async_credential=mock_azure_credential)
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_get_agent_reference_or_create_existing_version(
|
||||
async def test_azure_ai_client_get_agent_reference_or_create_existing_version(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_agent_reference_or_create when agent_version is already provided."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="existing-agent", agent_version="1.0")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="existing-agent", agent_version="1.0")
|
||||
|
||||
agent_ref = await client._get_agent_reference_or_create({}, None) # type: ignore
|
||||
|
||||
assert agent_ref == {"name": "existing-agent", "version": "1.0", "type": "agent_reference"}
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_get_agent_reference_or_create_new_agent(
|
||||
async def test_azure_ai_client_get_agent_reference_or_create_new_agent(
|
||||
mock_project_client: MagicMock,
|
||||
azure_ai_unit_test_env: dict[str, str],
|
||||
) -> None:
|
||||
"""Test _get_agent_reference_or_create when creating a new agent."""
|
||||
azure_ai_settings = AzureAISettings(model_deployment_name=azure_ai_unit_test_env["AZURE_AI_MODEL_DEPLOYMENT_NAME"])
|
||||
client = create_test_azure_ai_client_v2(
|
||||
client = create_test_azure_ai_client(
|
||||
mock_project_client, agent_name="new-agent", azure_ai_settings=azure_ai_settings
|
||||
)
|
||||
|
||||
@@ -188,32 +178,32 @@ async def test_azure_ai_client_v2_get_agent_reference_or_create_new_agent(
|
||||
assert client.agent_version == "1.0"
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_get_agent_reference_missing_model(
|
||||
async def test_azure_ai_client_get_agent_reference_missing_model(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_agent_reference_or_create when model is missing for agent creation."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="test-agent")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent")
|
||||
|
||||
with pytest.raises(ServiceInitializationError, match="Model deployment name is required for agent creation"):
|
||||
await client._get_agent_reference_or_create({}, None) # type: ignore
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_get_conversation_id_or_create_existing(
|
||||
async def test_azure_ai_client_get_conversation_id_or_create_existing(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_conversation_id_or_create when conversation_id is already provided."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, conversation_id="existing-conversation")
|
||||
client = create_test_azure_ai_client(mock_project_client, conversation_id="existing-conversation")
|
||||
|
||||
conversation_id = await client._get_conversation_id_or_create({}) # type: ignore
|
||||
|
||||
assert conversation_id == "existing-conversation"
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_get_conversation_id_or_create_new(
|
||||
async def test_azure_ai_client_get_conversation_id_or_create_new(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_conversation_id_or_create when creating a new conversation."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
# Mock conversation creation response
|
||||
mock_conversation = MagicMock()
|
||||
@@ -226,11 +216,11 @@ async def test_azure_ai_client_v2_get_conversation_id_or_create_new(
|
||||
client.client.conversations.create.assert_called_once()
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_prepare_input_with_system_messages(
|
||||
async def test_azure_ai_client_prepare_input_with_system_messages(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _prepare_input converts system/developer messages to instructions."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
messages = [
|
||||
ChatMessage(role=Role.SYSTEM, contents=[TextContent(text="You are a helpful assistant.")]),
|
||||
@@ -246,11 +236,11 @@ async def test_azure_ai_client_v2_prepare_input_with_system_messages(
|
||||
assert instructions == "You are a helpful assistant."
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_prepare_input_no_system_messages(
|
||||
async def test_azure_ai_client_prepare_input_no_system_messages(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _prepare_input with no system/developer messages."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
messages = [
|
||||
ChatMessage(role=Role.USER, contents=[TextContent(text="Hello")]),
|
||||
@@ -263,9 +253,9 @@ async def test_azure_ai_client_v2_prepare_input_no_system_messages(
|
||||
assert instructions is None
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_prepare_options_basic(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_prepare_options_basic(mock_project_client: MagicMock) -> None:
|
||||
"""Test prepare_options basic functionality."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="test-agent", agent_version="1.0")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent", agent_version="1.0")
|
||||
|
||||
messages = [ChatMessage(role=Role.USER, contents=[TextContent(text="Hello")])]
|
||||
chat_options = ChatOptions()
|
||||
@@ -284,9 +274,9 @@ async def test_azure_ai_client_v2_prepare_options_basic(mock_project_client: Mag
|
||||
assert run_options["extra_body"]["agent"]["name"] == "test-agent"
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_prepare_options_with_store(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_prepare_options_with_store(mock_project_client: MagicMock) -> None:
|
||||
"""Test prepare_options with store=True creates conversation."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="test-agent", agent_version="1.0")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent", agent_version="1.0")
|
||||
|
||||
# Mock conversation creation
|
||||
mock_conversation = MagicMock()
|
||||
@@ -312,9 +302,9 @@ async def test_azure_ai_client_v2_prepare_options_with_store(mock_project_client
|
||||
assert run_options["conversation"] == "new-conversation-456"
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_initialize_client(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_initialize_client(mock_project_client: MagicMock) -> None:
|
||||
"""Test initialize_client method."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
mock_openai_client = MagicMock()
|
||||
mock_project_client.get_openai_client = AsyncMock(return_value=mock_openai_client)
|
||||
@@ -325,9 +315,9 @@ async def test_azure_ai_client_v2_initialize_client(mock_project_client: MagicMo
|
||||
mock_project_client.get_openai_client.assert_called_once()
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_get_conversation_id_from_response(mock_project_client: MagicMock) -> None:
|
||||
def test_azure_ai_client_get_conversation_id_from_response(mock_project_client: MagicMock) -> None:
|
||||
"""Test get_conversation_id method."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
# Test with conversation and store=True
|
||||
mock_response = MagicMock()
|
||||
@@ -346,9 +336,9 @@ def test_azure_ai_client_v2_get_conversation_id_from_response(mock_project_clien
|
||||
assert conversation_id is None
|
||||
|
||||
|
||||
def test_azure_ai_client_v2_update_agent_name(mock_project_client: MagicMock) -> None:
|
||||
def test_azure_ai_client_update_agent_name(mock_project_client: MagicMock) -> None:
|
||||
"""Test _update_agent_name method."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client)
|
||||
client = create_test_azure_ai_client(mock_project_client)
|
||||
|
||||
# Test updating agent name when current is None
|
||||
with patch.object(client, "_update_agent_name") as mock_update:
|
||||
@@ -367,9 +357,9 @@ def test_azure_ai_client_v2_update_agent_name(mock_project_client: MagicMock) ->
|
||||
mock_update.assert_called_once_with(None)
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_async_context_manager(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_async_context_manager(mock_project_client: MagicMock) -> None:
|
||||
"""Test async context manager functionality."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, should_close_client=True)
|
||||
client = create_test_azure_ai_client(mock_project_client, should_close_client=True)
|
||||
|
||||
mock_project_client.close = AsyncMock()
|
||||
|
||||
@@ -380,9 +370,9 @@ async def test_azure_ai_client_v2_async_context_manager(mock_project_client: Mag
|
||||
mock_project_client.close.assert_called_once()
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_close_method(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_close_method(mock_project_client: MagicMock) -> None:
|
||||
"""Test close method."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, should_close_client=True)
|
||||
client = create_test_azure_ai_client(mock_project_client, should_close_client=True)
|
||||
|
||||
mock_project_client.close = AsyncMock()
|
||||
|
||||
@@ -391,9 +381,9 @@ async def test_azure_ai_client_v2_close_method(mock_project_client: MagicMock) -
|
||||
mock_project_client.close.assert_called_once()
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_close_client_when_should_close_false(mock_project_client: MagicMock) -> None:
|
||||
async def test_azure_ai_client_close_client_when_should_close_false(mock_project_client: MagicMock) -> None:
|
||||
"""Test _close_client_if_needed when should_close_client is False."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, should_close_client=False)
|
||||
client = create_test_azure_ai_client(mock_project_client, should_close_client=False)
|
||||
|
||||
mock_project_client.close = AsyncMock()
|
||||
|
||||
@@ -403,11 +393,11 @@ async def test_azure_ai_client_v2_close_client_when_should_close_false(mock_proj
|
||||
mock_project_client.close.assert_not_called()
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_agent_creation_with_instructions(
|
||||
async def test_azure_ai_client_agent_creation_with_instructions(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test agent creation with combined instructions."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="test-agent")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent")
|
||||
|
||||
# Mock agent creation response
|
||||
mock_agent = MagicMock()
|
||||
@@ -425,11 +415,11 @@ async def test_azure_ai_client_v2_agent_creation_with_instructions(
|
||||
assert call_args[1]["definition"].instructions == "Message instructions. Option instructions. "
|
||||
|
||||
|
||||
async def test_azure_ai_client_v2_agent_creation_with_tools(
|
||||
async def test_azure_ai_client_agent_creation_with_tools(
|
||||
mock_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test agent creation with tools."""
|
||||
client = create_test_azure_ai_client_v2(mock_project_client, agent_name="test-agent")
|
||||
client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent")
|
||||
|
||||
# Mock agent creation response
|
||||
mock_agent = MagicMock()
|
||||
@@ -6,7 +6,7 @@ from typing import Any
|
||||
|
||||
_IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"AzureAIAgentClient": ("agent_framework_azure_ai", "azure-ai"),
|
||||
"AzureAIAgentClientV2": ("agent_framework_azure_ai", "azure-ai"),
|
||||
"AzureAIClient": ("agent_framework_azure_ai", "azure-ai"),
|
||||
"AzureOpenAIAssistantsClient": ("agent_framework.azure._assistants_client", "core"),
|
||||
"AzureOpenAIChatClient": ("agent_framework.azure._chat_client", "core"),
|
||||
"AzureAISettings": ("agent_framework_azure_ai", "azure-ai"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from agent_framework_azure_ai import AzureAIAgentClient, AzureAIAgentClientV2, AzureAISettings
|
||||
from agent_framework_azure_ai import AzureAIAgentClient, AzureAIClient, AzureAISettings
|
||||
|
||||
from agent_framework.azure._assistants_client import AzureOpenAIAssistantsClient
|
||||
from agent_framework.azure._chat_client import AzureOpenAIChatClient
|
||||
@@ -10,7 +10,7 @@ from agent_framework.azure._shared import AzureOpenAISettings
|
||||
|
||||
__all__ = [
|
||||
"AzureAIAgentClient",
|
||||
"AzureAIAgentClientV2",
|
||||
"AzureAIClient",
|
||||
"AzureAISettings",
|
||||
"AzureOpenAIAssistantsClient",
|
||||
"AzureOpenAIChatClient",
|
||||
|
||||
@@ -338,6 +338,8 @@ class OpenAIBaseResponsesClient(OpenAIBase, BaseChatClient):
|
||||
|
||||
# model id
|
||||
if not run_options.get("model"):
|
||||
if not self.model_id:
|
||||
raise ValueError("model_id must be a non-empty string")
|
||||
run_options["model"] = self.model_id
|
||||
|
||||
# messages
|
||||
|
||||
@@ -127,18 +127,18 @@ class OpenAIBase(SerializationMixin):
|
||||
|
||||
INJECTABLE: ClassVar[set[str]] = {"client"}
|
||||
|
||||
def __init__(self, *, model_id: str, client: AsyncOpenAI | None = None, **kwargs: Any) -> None:
|
||||
def __init__(self, *, model_id: str | None = None, client: AsyncOpenAI | None = None, **kwargs: Any) -> None:
|
||||
"""Initialize OpenAIBase.
|
||||
|
||||
Keyword Args:
|
||||
client: The AsyncOpenAI client instance.
|
||||
model_id: The AI model ID to use (non-empty, whitespace stripped).
|
||||
model_id: The AI model ID to use.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
if not model_id or not model_id.strip():
|
||||
raise ValueError("model_id must be a non-empty string")
|
||||
self.client = client
|
||||
self.model_id = model_id.strip()
|
||||
self.model_id = None
|
||||
if model_id:
|
||||
self.model_id = model_id.strip()
|
||||
|
||||
# Call super().__init__() to continue MRO chain (e.g., BaseChatClient)
|
||||
# Extract known kwargs that belong to other base classes
|
||||
|
||||
@@ -2075,27 +2075,27 @@ def test_create_response_content_image_generation_fallback():
|
||||
assert f"data:image/png;base64,{unrecognized_base64}" == content.uri
|
||||
|
||||
|
||||
def test_prepare_options_store_parameter_handling() -> None:
|
||||
async def test_prepare_options_store_parameter_handling() -> None:
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="Test message")]
|
||||
|
||||
test_conversation_id = "test-conversation-123"
|
||||
chat_options = ChatOptions(store=True, conversation_id=test_conversation_id)
|
||||
options = client._prepare_options(messages, chat_options) # type: ignore
|
||||
options = await client.prepare_options(messages, chat_options) # type: ignore
|
||||
assert options["store"] is True
|
||||
assert options["previous_response_id"] == test_conversation_id
|
||||
|
||||
chat_options = ChatOptions(store=False, conversation_id="")
|
||||
options = client._prepare_options(messages, chat_options) # type: ignore
|
||||
options = await client.prepare_options(messages, chat_options) # type: ignore
|
||||
assert options["store"] is False
|
||||
|
||||
chat_options = ChatOptions(store=None, conversation_id=None)
|
||||
options = client._prepare_options(messages, chat_options) # type: ignore
|
||||
options = await client.prepare_options(messages, chat_options) # type: ignore
|
||||
assert options["store"] is False
|
||||
assert "previous_response_id" not in options
|
||||
|
||||
chat_options = ChatOptions()
|
||||
options = client._prepare_options(messages, chat_options) # type: ignore
|
||||
options = await client.prepare_options(messages, chat_options) # type: ignore
|
||||
assert options["store"] is False
|
||||
assert "previous_response_id" not in options
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from agent_framework.azure import AzureAIClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Azure AI Agent Basic Example
|
||||
|
||||
This sample demonstrates basic usage of AzureAIAgentClient to create agents with automatic
|
||||
lifecycle management. Shows both streaming and non-streaming responses with function tools.
|
||||
This sample demonstrates basic usage of AzureAIAgentClient.
|
||||
Shows both streaming and non-streaming responses with function tools.
|
||||
"""
|
||||
|
||||
|
||||
@@ -28,14 +28,13 @@ 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
|
||||
# and deleted after getting a response
|
||||
# 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,
|
||||
AzureAIAgentClient(async_credential=credential).create_agent(
|
||||
name="WeatherAgent",
|
||||
AzureAIClient(async_credential=credential).create_agent(
|
||||
name="BasicWeatherAgent",
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
@@ -50,14 +49,13 @@ 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
|
||||
# and deleted after getting a response
|
||||
# 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,
|
||||
AzureAIAgentClient(async_credential=credential).create_agent(
|
||||
name="WeatherAgent",
|
||||
AzureAIClient(async_credential=credential).create_agent(
|
||||
name="BasicWeatherAgent",
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
|
||||
@@ -4,16 +4,16 @@ import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import AgentThread, ChatAgent
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from agent_framework import AgentThread
|
||||
from agent_framework.azure import AzureAIClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Azure AI Agent with Thread Management Example
|
||||
|
||||
This sample demonstrates thread management with Azure AI Agents, comparing
|
||||
automatic thread creation with explicit thread management for persistent context.
|
||||
This sample demonstrates thread management with Azure AI Agent, showing
|
||||
persistent conversation context and simplified response handling.
|
||||
"""
|
||||
|
||||
|
||||
@@ -26,44 +26,42 @@ def get_weather(
|
||||
|
||||
|
||||
async def example_with_automatic_thread_creation() -> None:
|
||||
"""Example showing automatic thread creation (service-managed thread)."""
|
||||
"""Example showing automatic thread creation."""
|
||||
print("=== Automatic Thread Creation Example ===")
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
AzureAIClient(async_credential=credential).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
|
||||
first_query = "What's the weather like in Seattle?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query)
|
||||
print(f"Agent: {first_result.text}")
|
||||
query1 = "What's the weather like in Seattle?"
|
||||
print(f"User: {query1}")
|
||||
result1 = await agent.run(query1)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# Second conversation - still no thread provided, will create another new thread
|
||||
second_query = "What was the last city I asked about?"
|
||||
print(f"\nUser: {second_query}")
|
||||
second_result = await agent.run(second_query)
|
||||
print(f"Agent: {second_result.text}")
|
||||
query2 = "What was the last city I asked about?"
|
||||
print(f"\nUser: {query2}")
|
||||
result2 = await agent.run(query2)
|
||||
print(f"Agent: {result2.text}")
|
||||
print("Note: Each call creates a separate thread, so the agent doesn't remember previous context.\n")
|
||||
|
||||
|
||||
async def example_with_thread_persistence() -> None:
|
||||
"""Example showing thread persistence across multiple conversations."""
|
||||
print("=== Thread Persistence Example ===")
|
||||
print("Using the same thread across multiple conversations to maintain context.\n")
|
||||
async def example_with_thread_persistence_in_memory() -> None:
|
||||
"""
|
||||
Example showing thread persistence across multiple conversations.
|
||||
In this example, messages are stored in-memory.
|
||||
"""
|
||||
print("=== Thread Persistence Example (In-Memory) ===")
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
AzureAIClient(async_credential=credential).create_agent(
|
||||
name="BasicWeatherAgent",
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
@@ -72,81 +70,81 @@ async def example_with_thread_persistence() -> None:
|
||||
thread = agent.get_new_thread()
|
||||
|
||||
# First conversation
|
||||
first_query = "What's the weather like in Tokyo?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query, thread=thread)
|
||||
print(f"Agent: {first_result.text}")
|
||||
query1 = "What's the weather like in Tokyo?"
|
||||
print(f"User: {query1}")
|
||||
result1 = await agent.run(query1, thread=thread)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# Second conversation using the same thread - maintains context
|
||||
second_query = "How about London?"
|
||||
print(f"\nUser: {second_query}")
|
||||
second_result = await agent.run(second_query, thread=thread)
|
||||
print(f"Agent: {second_result.text}")
|
||||
query2 = "How about London?"
|
||||
print(f"\nUser: {query2}")
|
||||
result2 = await agent.run(query2, thread=thread)
|
||||
print(f"Agent: {result2.text}")
|
||||
|
||||
# Third conversation - agent should remember both previous cities
|
||||
third_query = "Which of the cities I asked about has better weather?"
|
||||
print(f"\nUser: {third_query}")
|
||||
third_result = await agent.run(third_query, thread=thread)
|
||||
print(f"Agent: {third_result.text}")
|
||||
query3 = "Which of the cities I asked about has better weather?"
|
||||
print(f"\nUser: {query3}")
|
||||
result3 = await agent.run(query3, thread=thread)
|
||||
print(f"Agent: {result3.text}")
|
||||
print("Note: The agent remembers context from previous messages in the same thread.\n")
|
||||
|
||||
|
||||
async def example_with_existing_thread_id() -> None:
|
||||
"""Example showing how to work with an existing thread ID from the service."""
|
||||
"""
|
||||
Example showing how to work with an existing thread ID from the service.
|
||||
In this example, messages are stored on the server using Azure AI conversation state.
|
||||
"""
|
||||
print("=== Existing Thread ID Example ===")
|
||||
print("Using a specific thread ID to continue an existing conversation.\n")
|
||||
|
||||
# First, create a conversation and capture the thread ID
|
||||
existing_thread_id = None
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
AzureAIClient(async_credential=credential).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()
|
||||
first_query = "What's the weather in Paris?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query, thread=thread)
|
||||
print(f"Agent: {first_result.text}")
|
||||
|
||||
query1 = "What's the weather in Paris?"
|
||||
print(f"User: {query1}")
|
||||
# Enable Azure AI conversation state by setting `store` parameter to True
|
||||
result1 = await agent.run(query1, thread=thread, store=True)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# The thread ID is set after the first response
|
||||
existing_thread_id = thread.service_thread_id
|
||||
print(f"Thread ID: {existing_thread_id}")
|
||||
|
||||
if existing_thread_id:
|
||||
print("\n--- Continuing with the same thread ID in a new agent instance ---")
|
||||
if existing_thread_id:
|
||||
print("\n--- Continuing with the same thread ID in a new agent instance ---")
|
||||
|
||||
# Create a new agent instance but use the existing thread ID
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(thread_id=existing_thread_id, async_credential=credential),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
):
|
||||
# Create a thread with the existing ID
|
||||
thread = AgentThread(service_thread_id=existing_thread_id)
|
||||
async with (
|
||||
AzureAIClient(async_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 = AgentThread(service_thread_id=existing_thread_id)
|
||||
|
||||
second_query = "What was the last city I asked about?"
|
||||
print(f"User: {second_query}")
|
||||
second_result = await agent.run(second_query, thread=thread)
|
||||
print(f"Agent: {second_result.text}")
|
||||
print("Note: The agent continues the conversation from the previous thread.\n")
|
||||
query2 = "What was the last city I asked about?"
|
||||
print(f"User: {query2}")
|
||||
result2 = await agent.run(query2, thread=thread, store=True)
|
||||
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:
|
||||
print("=== Azure AI Chat Client Agent Thread Management Examples ===\n")
|
||||
print("=== Azure AI Agent Thread Management Examples ===\n")
|
||||
|
||||
await example_with_automatic_thread_creation()
|
||||
await example_with_thread_persistence()
|
||||
await example_with_thread_persistence_in_memory()
|
||||
await example_with_existing_thread_id()
|
||||
|
||||
|
||||
|
||||
+11
-9
@@ -4,15 +4,15 @@ import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework.azure import AzureAIAgentClientV2
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Azure AI Agent Basic Example
|
||||
|
||||
This sample demonstrates basic usage of AzureAIAgentClient.
|
||||
Shows both streaming and non-streaming responses with function tools.
|
||||
This sample demonstrates basic usage of AzureAIAgentClient to create agents with automatic
|
||||
lifecycle management. Shows both streaming and non-streaming responses with function tools.
|
||||
"""
|
||||
|
||||
|
||||
@@ -28,13 +28,14 @@ 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.
|
||||
# Since no Agent ID is provided, the agent will be automatically created
|
||||
# and deleted after getting a response
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClientV2(async_credential=credential).create_agent(
|
||||
name="BasicWeatherAgent",
|
||||
AzureAIAgentClient(async_credential=credential).create_agent(
|
||||
name="WeatherAgent",
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
@@ -49,13 +50,14 @@ 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.
|
||||
# Since no Agent ID is provided, the agent will be automatically created
|
||||
# and deleted after getting a response
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClientV2(async_credential=credential).create_agent(
|
||||
name="BasicWeatherAgent",
|
||||
AzureAIAgentClient(async_credential=credential).create_agent(
|
||||
name="WeatherAgent",
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import AgentThread, ChatAgent
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Azure AI Agent with Thread Management Example
|
||||
|
||||
This sample demonstrates thread management with Azure AI Agents, comparing
|
||||
automatic thread creation with explicit thread management for persistent context.
|
||||
"""
|
||||
|
||||
|
||||
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 example_with_automatic_thread_creation() -> None:
|
||||
"""Example showing automatic thread creation (service-managed thread)."""
|
||||
print("=== Automatic Thread Creation Example ===")
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
):
|
||||
# First conversation - no thread provided, will be created automatically
|
||||
first_query = "What's the weather like in Seattle?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query)
|
||||
print(f"Agent: {first_result.text}")
|
||||
|
||||
# Second conversation - still no thread provided, will create another new thread
|
||||
second_query = "What was the last city I asked about?"
|
||||
print(f"\nUser: {second_query}")
|
||||
second_result = await agent.run(second_query)
|
||||
print(f"Agent: {second_result.text}")
|
||||
print("Note: Each call creates a separate thread, so the agent doesn't remember previous context.\n")
|
||||
|
||||
|
||||
async def example_with_thread_persistence() -> None:
|
||||
"""Example showing thread persistence across multiple conversations."""
|
||||
print("=== Thread Persistence Example ===")
|
||||
print("Using the same thread across multiple conversations to maintain context.\n")
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
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()
|
||||
|
||||
# First conversation
|
||||
first_query = "What's the weather like in Tokyo?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query, thread=thread)
|
||||
print(f"Agent: {first_result.text}")
|
||||
|
||||
# Second conversation using the same thread - maintains context
|
||||
second_query = "How about London?"
|
||||
print(f"\nUser: {second_query}")
|
||||
second_result = await agent.run(second_query, thread=thread)
|
||||
print(f"Agent: {second_result.text}")
|
||||
|
||||
# Third conversation - agent should remember both previous cities
|
||||
third_query = "Which of the cities I asked about has better weather?"
|
||||
print(f"\nUser: {third_query}")
|
||||
third_result = await agent.run(third_query, thread=thread)
|
||||
print(f"Agent: {third_result.text}")
|
||||
print("Note: The agent remembers context from previous messages in the same thread.\n")
|
||||
|
||||
|
||||
async def example_with_existing_thread_id() -> None:
|
||||
"""Example showing how to work with an existing thread ID from the service."""
|
||||
print("=== Existing Thread ID Example ===")
|
||||
print("Using a specific thread ID to continue an existing conversation.\n")
|
||||
|
||||
# First, create a conversation and capture the thread ID
|
||||
existing_thread_id = None
|
||||
|
||||
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
# authentication option.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(async_credential=credential),
|
||||
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()
|
||||
first_query = "What's the weather in Paris?"
|
||||
print(f"User: {first_query}")
|
||||
first_result = await agent.run(first_query, thread=thread)
|
||||
print(f"Agent: {first_result.text}")
|
||||
|
||||
# The thread ID is set after the first response
|
||||
existing_thread_id = thread.service_thread_id
|
||||
print(f"Thread ID: {existing_thread_id}")
|
||||
|
||||
if existing_thread_id:
|
||||
print("\n--- Continuing with the same thread ID in a new agent instance ---")
|
||||
|
||||
# Create a new agent instance but use the existing thread ID
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
ChatAgent(
|
||||
chat_client=AzureAIAgentClient(thread_id=existing_thread_id, async_credential=credential),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent,
|
||||
):
|
||||
# Create a thread with the existing ID
|
||||
thread = AgentThread(service_thread_id=existing_thread_id)
|
||||
|
||||
second_query = "What was the last city I asked about?"
|
||||
print(f"User: {second_query}")
|
||||
second_result = await agent.run(second_query, thread=thread)
|
||||
print(f"Agent: {second_result.text}")
|
||||
print("Note: The agent continues the conversation from the previous thread.\n")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=== Azure AI Chat Client Agent Thread Management Examples ===\n")
|
||||
|
||||
await example_with_automatic_thread_creation()
|
||||
await example_with_thread_persistence()
|
||||
await example_with_existing_thread_id()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -1,152 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import AgentThread
|
||||
from agent_framework.azure import AzureAIAgentClientV2
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Azure AI Agent with Thread Management Example
|
||||
|
||||
This sample demonstrates thread management with Azure AI Agent, showing
|
||||
persistent conversation context and simplified response handling.
|
||||
"""
|
||||
|
||||
|
||||
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 example_with_automatic_thread_creation() -> None:
|
||||
"""Example showing automatic thread creation."""
|
||||
print("=== Automatic Thread Creation Example ===")
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClientV2(async_credential=credential).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}")
|
||||
result1 = await agent.run(query1)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# Second conversation - still no thread provided, will create another new thread
|
||||
query2 = "What was the last city I asked about?"
|
||||
print(f"\nUser: {query2}")
|
||||
result2 = await agent.run(query2)
|
||||
print(f"Agent: {result2.text}")
|
||||
print("Note: Each call creates a separate thread, so the agent doesn't remember previous context.\n")
|
||||
|
||||
|
||||
async def example_with_thread_persistence_in_memory() -> None:
|
||||
"""
|
||||
Example showing thread persistence across multiple conversations.
|
||||
In this example, messages are stored in-memory.
|
||||
"""
|
||||
print("=== Thread Persistence Example (In-Memory) ===")
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClientV2(async_credential=credential).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()
|
||||
|
||||
# First conversation
|
||||
query1 = "What's the weather like in Tokyo?"
|
||||
print(f"User: {query1}")
|
||||
result1 = await agent.run(query1, thread=thread)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# Second conversation using the same thread - maintains context
|
||||
query2 = "How about London?"
|
||||
print(f"\nUser: {query2}")
|
||||
result2 = await agent.run(query2, thread=thread)
|
||||
print(f"Agent: {result2.text}")
|
||||
|
||||
# Third conversation - agent should remember both previous cities
|
||||
query3 = "Which of the cities I asked about has better weather?"
|
||||
print(f"\nUser: {query3}")
|
||||
result3 = await agent.run(query3, thread=thread)
|
||||
print(f"Agent: {result3.text}")
|
||||
print("Note: The agent remembers context from previous messages in the same thread.\n")
|
||||
|
||||
|
||||
async def example_with_existing_thread_id() -> None:
|
||||
"""
|
||||
Example showing how to work with an existing thread ID from the service.
|
||||
In this example, messages are stored on the server using Azure AI conversation state.
|
||||
"""
|
||||
print("=== Existing Thread ID Example ===")
|
||||
|
||||
# First, create a conversation and capture the thread ID
|
||||
existing_thread_id = None
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClientV2(async_credential=credential).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()
|
||||
|
||||
query1 = "What's the weather in Paris?"
|
||||
print(f"User: {query1}")
|
||||
# Enable Azure AI conversation state by setting `store` parameter to True
|
||||
result1 = await agent.run(query1, thread=thread, store=True)
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# The thread ID is set after the first response
|
||||
existing_thread_id = thread.service_thread_id
|
||||
print(f"Thread ID: {existing_thread_id}")
|
||||
|
||||
if existing_thread_id:
|
||||
print("\n--- Continuing with the same thread ID in a new agent instance ---")
|
||||
|
||||
async with (
|
||||
AzureAIAgentClientV2(async_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 = AgentThread(service_thread_id=existing_thread_id)
|
||||
|
||||
query2 = "What was the last city I asked about?"
|
||||
print(f"User: {query2}")
|
||||
result2 = await agent.run(query2, thread=thread, store=True)
|
||||
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:
|
||||
print("=== Azure AI Agent Thread Management Examples ===\n")
|
||||
|
||||
await example_with_automatic_thread_creation()
|
||||
await example_with_thread_persistence_in_memory()
|
||||
await example_with_existing_thread_id()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user