diff --git a/python/samples/02-agents/harness/build_your_own_claw/claw_step03_scaling_capabilities.py b/python/samples/02-agents/harness/build_your_own_claw/claw_step03_scaling_capabilities.py index 9c2d31254f2..dbab85a8b55 100644 --- a/python/samples/02-agents/harness/build_your_own_claw/claw_step03_scaling_capabilities.py +++ b/python/samples/02-agents/harness/build_your_own_claw/claw_step03_scaling_capabilities.py @@ -58,9 +58,9 @@ import httpx from agent_framework import ( - AggregatingSkillsSource, Agent, AgentModeProvider, + AggregatingSkillsSource, DeduplicatingSkillsSource, FileAccessProvider, FileSkillsSource, @@ -84,7 +84,6 @@ # subprocess script runner used to execute file-based skill scripts. sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from console import build_observers_with_planning, run_agent_async # noqa: E402 - from subprocess_script_runner import subprocess_script_runner # noqa: E402 _SAMPLE_DIR = Path(__file__).resolve().parent diff --git a/python/samples/02-agents/observability/README.md b/python/samples/02-agents/observability/README.md index a94a199a535..4ed36c0c4b6 100644 --- a/python/samples/02-agents/observability/README.md +++ b/python/samples/02-agents/observability/README.md @@ -78,6 +78,16 @@ configure_otel_providers(exporters=exporters) Many third-party OTel packages ship their own setup helpers (for example, Azure Monitor's `configure_azure_monitor()`). You can use those directly — Agent Framework instrumentation is on by default, so no extra wiring is needed. To also capture sensitive data, call `enable_sensitive_telemetry()` from `agent_framework.observability`. +The [Microsoft OpenTelemetry Distro](https://pypi.org/project/microsoft-opentelemetry/) bundles this pattern into a single call. Install it with `pip install microsoft-opentelemetry`, then call `use_microsoft_opentelemetry()`, which wires up the OpenTelemetry providers/exporters (optionally including Azure Monitor) and enables Agent Framework instrumentation: + +```python +from microsoft.opentelemetry import use_microsoft_opentelemetry + +# Sets up OpenTelemetry providers/exporters and enables Agent Framework instrumentation. +# Pass enable_azure_monitor=True to also configure the Azure Monitor exporter. +use_microsoft_opentelemetry(enable_azure_monitor=True) +``` + ```python from azure.monitor.opentelemetry import configure_azure_monitor from agent_framework.observability import create_resource, enable_sensitive_telemetry @@ -334,6 +344,7 @@ This folder contains different samples demonstrating how to use telemetry in var | [configure_otel_providers_with_parameters.py](./configure_otel_providers_with_parameters.py) | Create custom exporters with specific configuration and pass them to `configure_otel_providers()`. | | [agent_observability.py](./agent_observability.py) | Telemetry collection for an agentic application with tool calls. | | [foundry_tracing.py](./foundry_tracing.py) | Azure Monitor integration with Microsoft Foundry. | +| [microsoft_opentelemetry_distro.py](./microsoft_opentelemetry_distro.py) | One-call setup with the Microsoft OpenTelemetry Distro (`use_microsoft_opentelemetry()`), optionally enabling Azure Monitor. | | [workflow_observability.py](./workflow_observability.py) | Telemetry collection for a workflow with multiple executors and message passing. | | [advanced_manual_setup_console_output.py](./advanced_manual_setup_console_output.py) | Advanced: manual setup of exporters and providers with console output — useful for understanding how observability works under the hood. | | [advanced_zero_code.py](./advanced_zero_code.py) | Advanced: zero-code provider/exporter setup using the `opentelemetry-instrument` CLI wrapper. | diff --git a/python/samples/02-agents/observability/microsoft_opentelemetry_distro.py b/python/samples/02-agents/observability/microsoft_opentelemetry_distro.py new file mode 100644 index 00000000000..7eb3ea61d15 --- /dev/null +++ b/python/samples/02-agents/observability/microsoft_opentelemetry_distro.py @@ -0,0 +1,79 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "agent-framework-foundry", +# "microsoft-opentelemetry", +# ] +# /// +# Run with any PEP 723 compatible runner, e.g.: +# uv run python/samples/02-agents/observability/microsoft_opentelemetry_distro.py + +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from random import randint +from typing import Annotated + +from agent_framework import Agent, tool +from agent_framework.foundry import FoundryChatClient +from agent_framework.observability import get_tracer +from azure.identity import AzureCliCredential +from dotenv import load_dotenv +from microsoft.opentelemetry import use_microsoft_opentelemetry +from opentelemetry.trace import SpanKind +from opentelemetry.trace.span import format_trace_id +from pydantic import Field + +# Load environment variables from .env file +load_dotenv() + + +@tool(approval_mode="never_require") +async def get_weather( + location: Annotated[str, Field(description="The location to get the weather for.")], +) -> str: + """Get the weather for a given location.""" + await asyncio.sleep(randint(0, 10) / 10.0) # Simulate a network call + 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 main(): + # Set up Azure monitor exporters for telemetry + # This will automatically enable instrumentation for Agent Framework + # Install the Microsoft OpenTelemetry Distro package to enable this functionality: + # pip install microsoft-opentelemetry + # Requires the following environment variables to be set: + # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 + # APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey... + use_microsoft_opentelemetry(enable_azure_monitor=True) + + questions = [ + "What's the weather in Amsterdam?", + "and in Paris, and which is better?", + "Why is the sky blue?", + ] + + with get_tracer().start_as_current_span( + "Scenario: Agent Chat", kind=SpanKind.CLIENT + ) as current_span: + print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}") + + agent = Agent( + client=FoundryChatClient(credential=AzureCliCredential()), + tools=get_weather, + name="WeatherAgent", + instructions="You are a weather assistant.", + id="weather-agent", + ) + session = agent.create_session() + for question in questions: + print(f"\nUser: {question}") + print(f"{agent.name}: ", end="") + async for update in agent.run(question, session=session, stream=True): + if update.text: + print(update.text, end="") + + +if __name__ == "__main__": + asyncio.run(main())