diff --git a/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py new file mode 100644 index 000000000000..8315ed2b228d --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py @@ -0,0 +1,79 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to perform CRUD operations on External Agents + using the synchronous AIProjectClient. + + External Agents are a preview feature. They register third-party agents hosted + outside Microsoft Foundry. Registration is metadata-only: Foundry uses the + OpenTelemetry agent identifier to light up traces and evaluations for spans + emitted by your external agent. + +USAGE: + python sample_external_agents_crud.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. +""" + +import os + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + ExternalAgentDefinition, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, +): + agent_name = "sample-external-agent" + otel_agent_id = "sample-external-agent" + + try: + project_client.agents.delete(agent_name, force=True) + print(f"External agent `{agent_name}` deleted") + except ResourceNotFoundError: + pass + + created = project_client.agents.create_version( + agent_name=agent_name, + definition=ExternalAgentDefinition(otel_agent_id=otel_agent_id), + description="External agent registered by the azure-ai-projects sample.", + metadata={"sample": "external_agents_crud", "status": "created"}, + ) + print(f"Created external agent: {created.name} version={created.version} otel_agent_id={otel_agent_id}") + + fetched_agent = project_client.agents.get(agent_name) + print(f"Retrieved external agent: {fetched_agent.name} latest_version={fetched_agent.versions.latest.version}") + + fetched_version = project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Retrieved external agent version: {fetched_version.name} version={fetched_version.version}") + + external_agents = list(project_client.agents.list(kind="external", limit=10)) + print(f"Found {len(external_agents)} external agents or more") + for external_agent in external_agents: + print(f" - {external_agent.name} ({external_agent.id})") + + deleted = project_client.agents.delete(agent_name, force=True) + print(f"Deleted external agent: {deleted.name} deleted={deleted.deleted}") \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py new file mode 100644 index 000000000000..6ae6e887c837 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py @@ -0,0 +1,87 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to perform CRUD operations on External Agents + using the asynchronous AIProjectClient. + + External Agents are a preview feature. They register third-party agents hosted + outside Microsoft Foundry. Registration is metadata-only: Foundry uses the + OpenTelemetry agent identifier to light up traces and evaluations for spans + emitted by your external agent. + +USAGE: + python sample_external_agents_crud_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv aiohttp + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. +""" + +import asyncio +import os + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity.aio import DefaultAzureCredential + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import ( + ExternalAgentDefinition, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + + +async def main() -> None: + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + agent_name = "sample-external-agent" + otel_agent_id = "sample-external-agent" + + try: + await project_client.agents.delete(agent_name, force=True) + print(f"External agent `{agent_name}` deleted") + except ResourceNotFoundError: + pass + + created = await project_client.agents.create_version( + agent_name=agent_name, + definition=ExternalAgentDefinition(otel_agent_id=otel_agent_id), + description="External agent registered by the azure-ai-projects sample.", + metadata={"sample": "external_agents_crud", "status": "created"}, + ) + print(f"Created external agent: {created.name} version={created.version} otel_agent_id={otel_agent_id}") + + fetched_agent = await project_client.agents.get(agent_name) + print(f"Retrieved external agent: {fetched_agent.name} latest_version={fetched_agent.versions.latest.version}") + + fetched_version = await project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Retrieved external agent version: {fetched_version.name} version={fetched_version.version}") + + external_agents = [] + async for external_agent in project_client.agents.list(kind="external", limit=10): + external_agents.append(external_agent) + print(f"Found {len(external_agents)} external agents or more") + for external_agent in external_agents: + print(f" - {external_agent.name} ({external_agent.id})") + + deleted = await project_client.agents.delete(agent_name, force=True) + print(f"Deleted external agent: {deleted.name} deleted={deleted.deleted}") + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_samples.py index b6bc0593a102..0c1449b6c9a9 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_samples.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_samples.py @@ -85,6 +85,7 @@ def test_memory_samples(self, sample_path: str, **kwargs) -> None: get_sample_paths( "agents", samples_to_skip=[ + "sample_external_agents_crud.py", # Skipped until recordings are available. "sample_workflow_multi_agent.py", # No issue to run. Just postpone recording. "sample_workflow_multi_agent_with_mcp_approval.py", # No issue to run. Just postpone recording. ], diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py b/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py index 401374346664..c4b46ef8a6a7 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py @@ -71,7 +71,10 @@ async def test_memory_samples(self, sample_path: str, **kwargs) -> None: "sample_path", get_async_sample_paths( "agents", - samples_to_skip=["sample_workflow_multi_agent_async.py"], + samples_to_skip=[ + "sample_external_agents_crud_async.py", # Skipped until recordings are available. + "sample_workflow_multi_agent_async.py", + ], ), ) @servicePreparer()