From 54b51ec23b698938b0e8da8da09892205505d16d Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 12:58:47 -0700 Subject: [PATCH 01/11] Enable Agent Framework message events Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 3 ++ README.md | 4 ++ .../_agent_framework/_trace_instrumentor.py | 15 ++++++- .../test_trace_instrumentor.py | 45 +++++++++++++++++-- tests/test_agent_framework_integration.py | 5 ++- 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43dafd04..0c086bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ dict/string payloads. Execute-tool payload serialization is non-throwing: unserializable payloads record `{"serialization_error": "Failed to serialize execute tool payload."}` instead of failing the span. - Add explicit custom baggage APIs and propagate opted-in attributes to supported GenAI spans, including unmodeled operations. ([#264](https://github.com/microsoft/opentelemetry-distro-python/pull/264)) +- Enable Agent Framework GenAI message events by default when supported, with + an `instrumentation_options["agent_framework"]["enable_message_events"]` + override. - Add Python-native `InvokeAgentScope` request and response parameter models that emit OpenTelemetry GenAI semantic attributes, including structured system instructions and cache read/write token counts, introduced by .NET diff --git a/README.md b/README.md index b0601355..37636056 100644 --- a/README.md +++ b/README.md @@ -294,10 +294,14 @@ use_microsoft_opentelemetry( instrumentation_options={ "flask": {"enabled": False}, "openai": {"enabled": True}, + "agent_framework": {"enable_message_events": False}, }, ) ``` +Agent Framework message events are enabled by default. Set +`enable_message_events` to `False` as shown above to disable them. + ### Default Instrumentations When `enable_a365=True` Microsoft OpenTelemetry **automatically disables the diff --git a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py index 9e87068d..6872d001 100644 --- a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py +++ b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py @@ -5,6 +5,7 @@ import logging from collections.abc import Collection +from inspect import Parameter, signature from typing import Any from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore[attr-defined] @@ -36,10 +37,22 @@ def _instrument(self, **kwargs: Any) -> None: # Enable the Agent Framework SDK's built-in span generation so users # don't need to call enable_instrumentation() manually. enable_sensitive_data = kwargs.get("enable_sensitive_data", False) + enable_message_events = kwargs.get("enable_message_events", True) try: from agent_framework.observability import enable_instrumentation - enable_instrumentation(enable_sensitive_data=enable_sensitive_data) + enable_kwargs = {"enable_sensitive_data": enable_sensitive_data} + parameters = signature(enable_instrumentation).parameters + if "enable_message_events" in parameters or any( + parameter.kind == Parameter.VAR_KEYWORD for parameter in parameters.values() + ): + enable_kwargs["enable_message_events"] = enable_message_events + else: + _logger.debug( + "Agent Framework SDK does not support configuring message events. " + "Upgrade Agent Framework to use enable_message_events." + ) + enable_instrumentation(**enable_kwargs) self._af_instrumentation_enabled = True except ImportError as exc: _logger.debug( diff --git a/tests/agent_framework/test_trace_instrumentor.py b/tests/agent_framework/test_trace_instrumentor.py index a4af9567..fb7faef7 100644 --- a/tests/agent_framework/test_trace_instrumentor.py +++ b/tests/agent_framework/test_trace_instrumentor.py @@ -94,7 +94,7 @@ def test_instrument_calls_enable_instrumentation_when_available(self, mock_get_p instrumentor = AgentFrameworkInstrumentor() instrumentor._instrument() - mock_enable.assert_called_once_with(enable_sensitive_data=False) + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True) self.assertTrue(instrumentor._af_instrumentation_enabled) @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") @@ -114,7 +114,46 @@ def test_instrument_enables_sensitive_data_when_kwarg_set(self, mock_get_provide instrumentor = AgentFrameworkInstrumentor() instrumentor._instrument(enable_sensitive_data=True) - mock_enable.assert_called_once_with(enable_sensitive_data=True) + mock_enable.assert_called_once_with(enable_sensitive_data=True, enable_message_events=True) + self.assertTrue(instrumentor._af_instrumentation_enabled) + + @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") + def test_instrument_can_disable_message_events(self, mock_get_provider): + mock_get_provider.return_value = MagicMock() + mock_enable = MagicMock() + + with patch.dict( + "sys.modules", + { + "agent_framework": MagicMock(), + "agent_framework.observability": MagicMock(enable_instrumentation=mock_enable), + }, + ): + instrumentor = AgentFrameworkInstrumentor() + instrumentor._instrument(enable_message_events=False) + + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=False) + self.assertTrue(instrumentor._af_instrumentation_enabled) + + @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") + def test_instrument_supports_legacy_enable_instrumentation_signature(self, mock_get_provider): + mock_get_provider.return_value = MagicMock() + mock_enable = MagicMock() + + def legacy_enable_instrumentation(*, enable_sensitive_data=None, force=False): + mock_enable(enable_sensitive_data=enable_sensitive_data, force=force) + + with patch.dict( + "sys.modules", + { + "agent_framework": MagicMock(), + "agent_framework.observability": MagicMock(enable_instrumentation=legacy_enable_instrumentation), + }, + ): + instrumentor = AgentFrameworkInstrumentor() + instrumentor._instrument(enable_sensitive_data=True) + + mock_enable.assert_called_once_with(enable_sensitive_data=True, force=False) self.assertTrue(instrumentor._af_instrumentation_enabled) @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") @@ -214,7 +253,7 @@ def test_enable_instrumentation_called_in_azure_monitor_only_scenario(self, mock instrumentor._instrument() # AF SDK enabled, span processor added, enricher NOT registered. - mock_enable.assert_called_once_with(enable_sensitive_data=False) + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True) self.assertTrue(instrumentor._af_instrumentation_enabled) mock_provider.add_span_processor.assert_called_once() self.assertFalse(instrumentor._owns_enricher) diff --git a/tests/test_agent_framework_integration.py b/tests/test_agent_framework_integration.py index 6286d633..eb5f0fff 100644 --- a/tests/test_agent_framework_integration.py +++ b/tests/test_agent_framework_integration.py @@ -97,7 +97,10 @@ def test_enable_sensitive_data_kwarg(self, mock_get_provider): with patch.dict("sys.modules", {"agent_framework.observability": mock_af_obs}): inst = AgentFrameworkInstrumentor() inst._instrument(enable_sensitive_data=True) - mock_af_obs.enable_instrumentation.assert_called_once_with(enable_sensitive_data=True) + mock_af_obs.enable_instrumentation.assert_called_once_with( + enable_sensitive_data=True, + enable_message_events=True, + ) class TestAgentFrameworkSpanProcessor(unittest.TestCase): From 7295be86a0c5d7a4b8ec0861243c580598ec4a0b Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:02:21 -0700 Subject: [PATCH 02/11] Document Agent Framework options Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- README.md | 21 +++++++++++++++--- .../_agent_framework/_trace_instrumentor.py | 7 +++--- .../test_trace_instrumentor.py | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c086bb1..6353c8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ `{"serialization_error": "Failed to serialize execute tool payload."}` instead of failing the span. - Add explicit custom baggage APIs and propagate opted-in attributes to supported GenAI spans, including unmodeled operations. ([#264](https://github.com/microsoft/opentelemetry-distro-python/pull/264)) - Enable Agent Framework GenAI message events by default when supported, with - an `instrumentation_options["agent_framework"]["enable_message_events"]` - override. + `enable_message_events` and `force` overrides under + `instrumentation_options["agent_framework"]`. - Add Python-native `InvokeAgentScope` request and response parameter models that emit OpenTelemetry GenAI semantic attributes, including structured system instructions and cache read/write token counts, introduced by .NET diff --git a/README.md b/README.md index 37636056..3b056d40 100644 --- a/README.md +++ b/README.md @@ -291,16 +291,31 @@ Toggle individual instrumentations: ```python use_microsoft_opentelemetry( + enable_sensitive_data=True, instrumentation_options={ "flask": {"enabled": False}, "openai": {"enabled": True}, - "agent_framework": {"enable_message_events": False}, + "agent_framework": { + "enabled": True, + "enable_message_events": True, + "force": False, + }, }, ) ``` -Agent Framework message events are enabled by default. Set -`enable_message_events` to `False` as shown above to disable them. +Agent Framework supports the following configuration: + +| Option | Default | Description | +|---|---|---| +| `enabled` | `True` | Enable automatic Agent Framework instrumentation. | +| `enable_sensitive_data` | `False` | Enable prompt, completion, tool argument, and tool result capture. Set this as a top-level `use_microsoft_opentelemetry()` option. | +| `enable_message_events` | `True` | Emit baseline OpenTelemetry GenAI message events when sensitive-data capture is enabled. | +| `force` | `False` | Re-enable Agent Framework instrumentation after it was explicitly disabled with `disable_instrumentation()`. | + +Set Agent Framework-specific values under +`instrumentation_options["agent_framework"]`. The shared +`enable_sensitive_data` option is configured at the top level. ### Default Instrumentations When `enable_a365=True` diff --git a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py index 6872d001..080b315f 100644 --- a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py +++ b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py @@ -43,15 +43,16 @@ def _instrument(self, **kwargs: Any) -> None: enable_kwargs = {"enable_sensitive_data": enable_sensitive_data} parameters = signature(enable_instrumentation).parameters - if "enable_message_events" in parameters or any( - parameter.kind == Parameter.VAR_KEYWORD for parameter in parameters.values() - ): + accepts_kwargs = any(parameter.kind == Parameter.VAR_KEYWORD for parameter in parameters.values()) + if "enable_message_events" in parameters or accepts_kwargs: enable_kwargs["enable_message_events"] = enable_message_events else: _logger.debug( "Agent Framework SDK does not support configuring message events. " "Upgrade Agent Framework to use enable_message_events." ) + if "force" in kwargs and ("force" in parameters or accepts_kwargs): + enable_kwargs["force"] = kwargs["force"] enable_instrumentation(**enable_kwargs) self._af_instrumentation_enabled = True except ImportError as exc: diff --git a/tests/agent_framework/test_trace_instrumentor.py b/tests/agent_framework/test_trace_instrumentor.py index fb7faef7..039bcaf0 100644 --- a/tests/agent_framework/test_trace_instrumentor.py +++ b/tests/agent_framework/test_trace_instrumentor.py @@ -135,6 +135,28 @@ def test_instrument_can_disable_message_events(self, mock_get_provider): mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=False) self.assertTrue(instrumentor._af_instrumentation_enabled) + @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") + def test_instrument_can_force_reenable_instrumentation(self, mock_get_provider): + mock_get_provider.return_value = MagicMock() + mock_enable = MagicMock() + + with patch.dict( + "sys.modules", + { + "agent_framework": MagicMock(), + "agent_framework.observability": MagicMock(enable_instrumentation=mock_enable), + }, + ): + instrumentor = AgentFrameworkInstrumentor() + instrumentor._instrument(force=True) + + mock_enable.assert_called_once_with( + enable_sensitive_data=False, + enable_message_events=True, + force=True, + ) + self.assertTrue(instrumentor._af_instrumentation_enabled) + @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") def test_instrument_supports_legacy_enable_instrumentation_signature(self, mock_get_provider): mock_get_provider.return_value = MagicMock() From d4acab202117949d112cd91f6de39a531277bf78 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:04:10 -0700 Subject: [PATCH 03/11] Narrow Agent Framework configuration docs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- README.md | 17 ++++---------- .../_agent_framework/_trace_instrumentor.py | 2 -- .../test_trace_instrumentor.py | 22 ------------------- 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6353c8d0..0c086bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ `{"serialization_error": "Failed to serialize execute tool payload."}` instead of failing the span. - Add explicit custom baggage APIs and propagate opted-in attributes to supported GenAI spans, including unmodeled operations. ([#264](https://github.com/microsoft/opentelemetry-distro-python/pull/264)) - Enable Agent Framework GenAI message events by default when supported, with - `enable_message_events` and `force` overrides under - `instrumentation_options["agent_framework"]`. + an `instrumentation_options["agent_framework"]["enable_message_events"]` + override. - Add Python-native `InvokeAgentScope` request and response parameter models that emit OpenTelemetry GenAI semantic attributes, including structured system instructions and cache read/write token counts, introduced by .NET diff --git a/README.md b/README.md index 3b056d40..b982d57c 100644 --- a/README.md +++ b/README.md @@ -298,24 +298,15 @@ use_microsoft_opentelemetry( "agent_framework": { "enabled": True, "enable_message_events": True, - "force": False, }, }, ) ``` -Agent Framework supports the following configuration: - -| Option | Default | Description | -|---|---|---| -| `enabled` | `True` | Enable automatic Agent Framework instrumentation. | -| `enable_sensitive_data` | `False` | Enable prompt, completion, tool argument, and tool result capture. Set this as a top-level `use_microsoft_opentelemetry()` option. | -| `enable_message_events` | `True` | Emit baseline OpenTelemetry GenAI message events when sensitive-data capture is enabled. | -| `force` | `False` | Re-enable Agent Framework instrumentation after it was explicitly disabled with `disable_instrumentation()`. | - -Set Agent Framework-specific values under -`instrumentation_options["agent_framework"]`. The shared -`enable_sensitive_data` option is configured at the top level. +For Agent Framework, `enable_sensitive_data` controls prompt, completion, +tool argument, and tool result capture. Message events are enabled by default +when the installed Agent Framework version supports them and can be disabled +with `instrumentation_options["agent_framework"]["enable_message_events"]`. ### Default Instrumentations When `enable_a365=True` diff --git a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py index 080b315f..90dbe943 100644 --- a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py +++ b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py @@ -51,8 +51,6 @@ def _instrument(self, **kwargs: Any) -> None: "Agent Framework SDK does not support configuring message events. " "Upgrade Agent Framework to use enable_message_events." ) - if "force" in kwargs and ("force" in parameters or accepts_kwargs): - enable_kwargs["force"] = kwargs["force"] enable_instrumentation(**enable_kwargs) self._af_instrumentation_enabled = True except ImportError as exc: diff --git a/tests/agent_framework/test_trace_instrumentor.py b/tests/agent_framework/test_trace_instrumentor.py index 039bcaf0..fb7faef7 100644 --- a/tests/agent_framework/test_trace_instrumentor.py +++ b/tests/agent_framework/test_trace_instrumentor.py @@ -135,28 +135,6 @@ def test_instrument_can_disable_message_events(self, mock_get_provider): mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=False) self.assertTrue(instrumentor._af_instrumentation_enabled) - @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") - def test_instrument_can_force_reenable_instrumentation(self, mock_get_provider): - mock_get_provider.return_value = MagicMock() - mock_enable = MagicMock() - - with patch.dict( - "sys.modules", - { - "agent_framework": MagicMock(), - "agent_framework.observability": MagicMock(enable_instrumentation=mock_enable), - }, - ): - instrumentor = AgentFrameworkInstrumentor() - instrumentor._instrument(force=True) - - mock_enable.assert_called_once_with( - enable_sensitive_data=False, - enable_message_events=True, - force=True, - ) - self.assertTrue(instrumentor._af_instrumentation_enabled) - @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") def test_instrument_supports_legacy_enable_instrumentation_signature(self, mock_get_provider): mock_get_provider.return_value = MagicMock() From b97f008a94dc34db94cf95a52d66f42cf0733f61 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:03:41 -0700 Subject: [PATCH 04/11] Document Agent Framework version and sample Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 1 + samples/microsoft_agent_framework/README.md | 6 ++++++ samples/microsoft_agent_framework/sample_maf_agent.py | 10 +++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b982d57c..aaab7a11 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,7 @@ For Agent Framework, `enable_sensitive_data` controls prompt, completion, tool argument, and tool result capture. Message events are enabled by default when the installed Agent Framework version supports them and can be disabled with `instrumentation_options["agent_framework"]["enable_message_events"]`. +Message-event configuration requires Agent Framework 1.19.0 or later. ### Default Instrumentations When `enable_a365=True` diff --git a/samples/microsoft_agent_framework/README.md b/samples/microsoft_agent_framework/README.md index 7e32c40e..5ac62b1b 100644 --- a/samples/microsoft_agent_framework/README.md +++ b/samples/microsoft_agent_framework/README.md @@ -7,6 +7,7 @@ Learn more about the Microsoft Agent Framework in our [GitHub repository](https: ## Prerequisites - Python 3.10+ +- Agent Framework 1.19.0+ for message-event configuration - A [Foundry project](https://learn.microsoft.com/en-us/azure/foundry/tutorials/quickstart-create-foundry-resources?tabs=portal) endpoint and model - (Optional) An [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/create-workspace-resource?tabs=portal) resource (for the connection string) - (Optional) An [Aspire Dashboard](https://aspire.dev/dashboard/overview/#standalone-mode) to visualize traces (if you want to use a local OpenTelemetry Collector) @@ -61,3 +62,8 @@ Microsoft Agent Framework is natively instrumented with OpenTelemetry, so you ca ```bash python sample_maf_agent.py ``` + +The sample enables sensitive-data capture and Agent Framework GenAI message +events. Sensitive data can include prompts, completions, tool arguments, and +tool results. Review your data-handling requirements before enabling it in +production. diff --git a/samples/microsoft_agent_framework/sample_maf_agent.py b/samples/microsoft_agent_framework/sample_maf_agent.py index 171a88d5..6f566a35 100644 --- a/samples/microsoft_agent_framework/sample_maf_agent.py +++ b/samples/microsoft_agent_framework/sample_maf_agent.py @@ -31,7 +31,15 @@ async def get_weather( async def main(): # Set up Azure monitor exporters for telemetry # This will automatically enable instrumentation for Agent Framework - use_microsoft_opentelemetry(enable_azure_monitor=True) + use_microsoft_opentelemetry( + enable_azure_monitor=True, + enable_sensitive_data=True, + instrumentation_options={ + "agent_framework": { + "enable_message_events": True, + }, + }, + ) questions = [ "What's the weather in Amsterdam?", From 51d797d0d1b305504481e2533e1bdc29470a1e7a Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:07:41 -0700 Subject: [PATCH 05/11] Test Agent Framework message events API Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- tests/test_agent_framework_integration.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_agent_framework_integration.py b/tests/test_agent_framework_integration.py index eb5f0fff..b5a7e593 100644 --- a/tests/test_agent_framework_integration.py +++ b/tests/test_agent_framework_integration.py @@ -29,6 +29,18 @@ class TestAgentFrameworkInstrumentationConfig(unittest.TestCase): def test_agent_framework_in_supported_libraries(self): self.assertIn("agent_framework", _SUPPORTED_INSTRUMENTED_LIBRARIES) + def test_enable_instrumentation_supports_message_events(self): + """The installed Agent Framework must expose the API required by this integration.""" + from inspect import signature + + from agent_framework.observability import enable_instrumentation + + self.assertIn( + "enable_message_events", + signature(enable_instrumentation).parameters, + "Agent Framework must provide enable_message_events; upgrade the agent-framework dependency.", + ) + class TestAgentFrameworkInstrumentorLifecycle(unittest.TestCase): """Verify the AgentFrameworkInstrumentor can be activated and torn down.""" From 07b1374a4597b65ba56d96632c0c3e6a11b1d961 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:08:23 -0700 Subject: [PATCH 06/11] Require Agent Framework 1.19 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- pyproject.toml | 2 +- samples/microsoft_agent_framework/requirements.txt | 2 +- .../opentelemetry/_agent_framework/_trace_instrumentor.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dc9e850e..c0d11f10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ [project.optional-dependencies] agent-framework = [ - "agent-framework>=1.4.0", + "agent-framework>=1.19.0", ] openai-agents = [ "openai-agents>=0.0.7", diff --git a/samples/microsoft_agent_framework/requirements.txt b/samples/microsoft_agent_framework/requirements.txt index 8f1d3aef..c494c8b4 100644 --- a/samples/microsoft_agent_framework/requirements.txt +++ b/samples/microsoft_agent_framework/requirements.txt @@ -1,3 +1,3 @@ -agent-framework-core +agent-framework-core>=1.19.0 agent-framework-foundry microsoft-opentelemetry \ No newline at end of file diff --git a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py index 90dbe943..9fcd1e69 100644 --- a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py +++ b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py @@ -14,7 +14,7 @@ from microsoft.opentelemetry._agent_framework._span_processor import AgentFrameworkSpanProcessor _logger = logging.getLogger(__name__) -_instruments = ("agent-framework >= 1.0.0",) +_instruments = ("agent-framework >= 1.19.0",) class AgentFrameworkInstrumentor(BaseInstrumentor): From 69a30cd25ad3dd68d3851325fac64ef21b3dad95 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:11:01 -0700 Subject: [PATCH 07/11] Keep version requirements out of docs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 1 - samples/microsoft_agent_framework/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/README.md b/README.md index aaab7a11..b982d57c 100644 --- a/README.md +++ b/README.md @@ -307,7 +307,6 @@ For Agent Framework, `enable_sensitive_data` controls prompt, completion, tool argument, and tool result capture. Message events are enabled by default when the installed Agent Framework version supports them and can be disabled with `instrumentation_options["agent_framework"]["enable_message_events"]`. -Message-event configuration requires Agent Framework 1.19.0 or later. ### Default Instrumentations When `enable_a365=True` diff --git a/samples/microsoft_agent_framework/README.md b/samples/microsoft_agent_framework/README.md index 5ac62b1b..c37e357a 100644 --- a/samples/microsoft_agent_framework/README.md +++ b/samples/microsoft_agent_framework/README.md @@ -7,7 +7,6 @@ Learn more about the Microsoft Agent Framework in our [GitHub repository](https: ## Prerequisites - Python 3.10+ -- Agent Framework 1.19.0+ for message-event configuration - A [Foundry project](https://learn.microsoft.com/en-us/azure/foundry/tutorials/quickstart-create-foundry-resources?tabs=portal) endpoint and model - (Optional) An [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/create-workspace-resource?tabs=portal) resource (for the connection string) - (Optional) An [Aspire Dashboard](https://aspire.dev/dashboard/overview/#standalone-mode) to visualize traces (if you want to use a local OpenTelemetry Collector) From 8d36e1976175b335c15f4f73b835f096e9c00436 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:49:40 -0700 Subject: [PATCH 08/11] Link changelog entry to pull request Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c086bb1..32ca2729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Enable Agent Framework GenAI message events by default when supported, with an `instrumentation_options["agent_framework"]["enable_message_events"]` override. + ([#270](https://github.com/microsoft/opentelemetry-distro-python/pull/270)) - Add Python-native `InvokeAgentScope` request and response parameter models that emit OpenTelemetry GenAI semantic attributes, including structured system instructions and cache read/write token counts, introduced by .NET From b0ed7981199a19548cd1a062a27822db0b07eee7 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:22:51 -0700 Subject: [PATCH 09/11] Address Agent Framework review feedback Forward and document the force option, cover forced re-enablement, and move the optional dependency API contract into the integration suite that installs Agent Framework. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 3 +++ .../_agent_framework/_trace_instrumentor.py | 17 +++++++----- .../agentframework/test_api_contract.py | 13 ++++++++++ .../test_trace_instrumentor.py | 26 ++++++++++++++++--- tests/test_agent_framework_integration.py | 13 +--------- 5 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 tests/a365/integration/agentframework/test_api_contract.py diff --git a/README.md b/README.md index b982d57c..5475d7d6 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,7 @@ use_microsoft_opentelemetry( "agent_framework": { "enabled": True, "enable_message_events": True, + "force": True, }, }, ) @@ -307,6 +308,8 @@ For Agent Framework, `enable_sensitive_data` controls prompt, completion, tool argument, and tool result capture. Message events are enabled by default when the installed Agent Framework version supports them and can be disabled with `instrumentation_options["agent_framework"]["enable_message_events"]`. +Set `instrumentation_options["agent_framework"]["force"]` to `True` to +re-enable Agent Framework instrumentation after it was previously disabled. ### Default Instrumentations When `enable_a365=True` diff --git a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py index 9fcd1e69..018d2075 100644 --- a/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py +++ b/src/microsoft/opentelemetry/_agent_framework/_trace_instrumentor.py @@ -38,19 +38,22 @@ def _instrument(self, **kwargs: Any) -> None: # don't need to call enable_instrumentation() manually. enable_sensitive_data = kwargs.get("enable_sensitive_data", False) enable_message_events = kwargs.get("enable_message_events", True) + force = kwargs.get("force", False) try: from agent_framework.observability import enable_instrumentation enable_kwargs = {"enable_sensitive_data": enable_sensitive_data} parameters = signature(enable_instrumentation).parameters accepts_kwargs = any(parameter.kind == Parameter.VAR_KEYWORD for parameter in parameters.values()) - if "enable_message_events" in parameters or accepts_kwargs: - enable_kwargs["enable_message_events"] = enable_message_events - else: - _logger.debug( - "Agent Framework SDK does not support configuring message events. " - "Upgrade Agent Framework to use enable_message_events." - ) + optional_kwargs = { + "enable_message_events": enable_message_events, + "force": force, + } + for name, value in optional_kwargs.items(): + if name in parameters or accepts_kwargs: + enable_kwargs[name] = value + else: + _logger.debug("Agent Framework SDK does not support configuring %s.", name) enable_instrumentation(**enable_kwargs) self._af_instrumentation_enabled = True except ImportError as exc: diff --git a/tests/a365/integration/agentframework/test_api_contract.py b/tests/a365/integration/agentframework/test_api_contract.py new file mode 100644 index 00000000..2820fb97 --- /dev/null +++ b/tests/a365/integration/agentframework/test_api_contract.py @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +from inspect import signature + +from agent_framework.observability import enable_instrumentation + + +def test_enable_instrumentation_supports_distro_options(): + parameters = signature(enable_instrumentation).parameters + + assert "enable_message_events" in parameters + assert "force" in parameters diff --git a/tests/agent_framework/test_trace_instrumentor.py b/tests/agent_framework/test_trace_instrumentor.py index fb7faef7..d56bdf35 100644 --- a/tests/agent_framework/test_trace_instrumentor.py +++ b/tests/agent_framework/test_trace_instrumentor.py @@ -94,7 +94,7 @@ def test_instrument_calls_enable_instrumentation_when_available(self, mock_get_p instrumentor = AgentFrameworkInstrumentor() instrumentor._instrument() - mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True) + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True, force=False) self.assertTrue(instrumentor._af_instrumentation_enabled) @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") @@ -114,7 +114,7 @@ def test_instrument_enables_sensitive_data_when_kwarg_set(self, mock_get_provide instrumentor = AgentFrameworkInstrumentor() instrumentor._instrument(enable_sensitive_data=True) - mock_enable.assert_called_once_with(enable_sensitive_data=True, enable_message_events=True) + mock_enable.assert_called_once_with(enable_sensitive_data=True, enable_message_events=True, force=False) self.assertTrue(instrumentor._af_instrumentation_enabled) @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") @@ -132,7 +132,25 @@ def test_instrument_can_disable_message_events(self, mock_get_provider): instrumentor = AgentFrameworkInstrumentor() instrumentor._instrument(enable_message_events=False) - mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=False) + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=False, force=False) + self.assertTrue(instrumentor._af_instrumentation_enabled) + + @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") + def test_instrument_can_force_reenable_instrumentation(self, mock_get_provider): + mock_get_provider.return_value = MagicMock() + mock_enable = MagicMock() + + with patch.dict( + "sys.modules", + { + "agent_framework": MagicMock(), + "agent_framework.observability": MagicMock(enable_instrumentation=mock_enable), + }, + ): + instrumentor = AgentFrameworkInstrumentor() + instrumentor._instrument(force=True) + + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True, force=True) self.assertTrue(instrumentor._af_instrumentation_enabled) @patch("microsoft.opentelemetry._agent_framework._trace_instrumentor.get_tracer_provider") @@ -253,7 +271,7 @@ def test_enable_instrumentation_called_in_azure_monitor_only_scenario(self, mock instrumentor._instrument() # AF SDK enabled, span processor added, enricher NOT registered. - mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True) + mock_enable.assert_called_once_with(enable_sensitive_data=False, enable_message_events=True, force=False) self.assertTrue(instrumentor._af_instrumentation_enabled) mock_provider.add_span_processor.assert_called_once() self.assertFalse(instrumentor._owns_enricher) diff --git a/tests/test_agent_framework_integration.py b/tests/test_agent_framework_integration.py index b5a7e593..dbec30a0 100644 --- a/tests/test_agent_framework_integration.py +++ b/tests/test_agent_framework_integration.py @@ -29,18 +29,6 @@ class TestAgentFrameworkInstrumentationConfig(unittest.TestCase): def test_agent_framework_in_supported_libraries(self): self.assertIn("agent_framework", _SUPPORTED_INSTRUMENTED_LIBRARIES) - def test_enable_instrumentation_supports_message_events(self): - """The installed Agent Framework must expose the API required by this integration.""" - from inspect import signature - - from agent_framework.observability import enable_instrumentation - - self.assertIn( - "enable_message_events", - signature(enable_instrumentation).parameters, - "Agent Framework must provide enable_message_events; upgrade the agent-framework dependency.", - ) - class TestAgentFrameworkInstrumentorLifecycle(unittest.TestCase): """Verify the AgentFrameworkInstrumentor can be activated and torn down.""" @@ -112,6 +100,7 @@ def test_enable_sensitive_data_kwarg(self, mock_get_provider): mock_af_obs.enable_instrumentation.assert_called_once_with( enable_sensitive_data=True, enable_message_events=True, + force=False, ) From 311c59415cbd3ce49d070e9828b494147fea6203 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:26:45 -0700 Subject: [PATCH 10/11] Skip Agent Framework contract without extra Keep the API contract in the integration suite while allowing the base pytest environments to collect tests without the optional Agent Framework dependency. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- tests/a365/integration/agentframework/test_api_contract.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/a365/integration/agentframework/test_api_contract.py b/tests/a365/integration/agentframework/test_api_contract.py index 2820fb97..27ee1310 100644 --- a/tests/a365/integration/agentframework/test_api_contract.py +++ b/tests/a365/integration/agentframework/test_api_contract.py @@ -3,11 +3,13 @@ from inspect import signature -from agent_framework.observability import enable_instrumentation +import pytest + +observability = pytest.importorskip("agent_framework.observability") def test_enable_instrumentation_supports_distro_options(): - parameters = signature(enable_instrumentation).parameters + parameters = signature(observability.enable_instrumentation).parameters assert "enable_message_events" in parameters assert "force" in parameters From 3248cb337f00d2112a3377b01e0d18a24d91050a Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:06:56 -0700 Subject: [PATCH 11/11] Remove Agent Framework API contract test Avoid conditional loading of the optional Agent Framework dependency; the minimum version and instrumentor behavior remain covered by package metadata and unit tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../agentframework/test_api_contract.py | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 tests/a365/integration/agentframework/test_api_contract.py diff --git a/tests/a365/integration/agentframework/test_api_contract.py b/tests/a365/integration/agentframework/test_api_contract.py deleted file mode 100644 index 27ee1310..00000000 --- a/tests/a365/integration/agentframework/test_api_contract.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -from inspect import signature - -import pytest - -observability = pytest.importorskip("agent_framework.observability") - - -def test_enable_instrumentation_supports_distro_options(): - parameters = signature(observability.enable_instrumentation).parameters - - assert "enable_message_events" in parameters - assert "force" in parameters