diff --git a/CHANGELOG.md b/CHANGELOG.md index 98a797c1..5829868d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ([#269](https://github.com/microsoft/opentelemetry-distro-python/pull/269)) ### Bugs Fixed +- Handle activities without a recipient when extracting Agent365 tenant baggage. - Restore MOT version propagation after OneSettings initialization order caused the exporter version to take precedence over the Microsoft OpenTelemetry distro version ([#275](https://github.com/microsoft/opentelemetry-distro-python/pull/275)) - Restrict A365 identity and baggage enrichment to recognized GenAI spans while preserving supported span-start signals. ([#265](https://github.com/microsoft/opentelemetry-distro-python/pull/265)) diff --git a/src/microsoft/opentelemetry/a365/hosting/scope_helpers/utils.py b/src/microsoft/opentelemetry/a365/hosting/scope_helpers/utils.py index 87bd0ccb..aba2c4e5 100644 --- a/src/microsoft/opentelemetry/a365/hosting/scope_helpers/utils.py +++ b/src/microsoft/opentelemetry/a365/hosting/scope_helpers/utils.py @@ -92,7 +92,10 @@ def get_target_agent_pairs(activity: Activity) -> Iterator[tuple[str, Any]]: def get_tenant_id_pair(activity: Activity) -> Iterator[tuple[str, Any]]: - yield TENANT_ID_KEY, activity.recipient.tenant_id + rec = activity.recipient + if not rec: + return + yield TENANT_ID_KEY, rec.tenant_id def get_channel_pairs(activity: Activity) -> Iterator[tuple[str, Any]]: diff --git a/tests/a365/hosting/scope_helpers/test_populate_baggage.py b/tests/a365/hosting/scope_helpers/test_populate_baggage.py index d3ce5fc3..d3f1d031 100644 --- a/tests/a365/hosting/scope_helpers/test_populate_baggage.py +++ b/tests/a365/hosting/scope_helpers/test_populate_baggage.py @@ -11,7 +11,7 @@ from microsoft_agents.activity import Activity, ChannelAccount, ConversationAccount from microsoft_agents.hosting.core import TurnContext -from microsoft.opentelemetry.a365.core.constants import USER_ID_KEY +from microsoft.opentelemetry.a365.core.constants import TENANT_ID_KEY, USER_ID_KEY from microsoft.opentelemetry.a365.core.middleware.baggage_builder import BaggageBuilder from microsoft.opentelemetry.a365.hosting.scope_helpers.populate_baggage import populate @@ -45,3 +45,16 @@ def test_populate(): # Verify specific expected baggage keys were set assert USER_ID_KEY in builder._pairs assert builder._pairs[USER_ID_KEY] == "caller-id" + + +def test_populate_without_recipient(): + activity = Activity( + type="message", + from_property=ChannelAccount(aad_object_id="caller-id"), + ) + turn_context = TurnContext(MagicMock(), activity) + builder = BaggageBuilder() + + assert populate(builder, turn_context) is builder + assert builder._pairs[USER_ID_KEY] == "caller-id" + assert TENANT_ID_KEY not in builder._pairs diff --git a/tests/a365/hosting/scope_helpers/test_scope_helper_utils.py b/tests/a365/hosting/scope_helpers/test_scope_helper_utils.py index d4582aee..bfa31057 100644 --- a/tests/a365/hosting/scope_helpers/test_scope_helper_utils.py +++ b/tests/a365/hosting/scope_helpers/test_scope_helper_utils.py @@ -78,6 +78,18 @@ def test_get_tenant_id_pair(): assert (TENANT_ID_KEY, "test-tenant-id") in result +def test_get_tenant_id_pair_without_recipient(): + activity = Activity(type="message") + + assert not list(get_tenant_id_pair(activity)) + + +def test_get_tenant_id_pair_without_tenant_id(): + activity = Activity(type="message", recipient=ChannelAccount()) + + assert list(get_tenant_id_pair(activity)) == [(TENANT_ID_KEY, None)] + + def test_get_channel_pairs(): """Test get_channel_pairs extracts channel metadata.""" activity = Activity(type="message", channel_id="test-channel") diff --git a/uv.lock b/uv.lock index b1bf95d5..6f408cbb 100644 --- a/uv.lock +++ b/uv.lock @@ -3316,11 +3316,11 @@ wheels = [ [[package]] name = "oauthlib" -version = "3.3.1" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/d8/a1bcc8ba112a627f8ffbdc212a78ce18d3ac07e91a5ca65d27918eee25a1/oauthlib-4.0.0.tar.gz", hash = "sha256:efb274799819440f95b4ab3b818869f1ce9ae26c5beacba0201d1a1b76b54f86", size = 187232, upload-time = "2026-09-28T06:01:18.77Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f4/78229a1066068ca14fc60fb26cf7381cabe4382261392b90e5f9552722d4/oauthlib-4.0.0-py3-none-any.whl", hash = "sha256:624c28c13a0a59cabf9747dfa52af63be3e512a7f2714df16e91b5b3a145e6cd", size = 159715, upload-time = "2026-09-28T06:01:17.008Z" }, ] [[package]]