Skip to content

Align BaggageBuilder and Outputmessages middleware#187

Merged
nikhilNava merged 11 commits intomainfrom
copilot/implement-baggage-middleware-python
Mar 3, 2026
Merged

Align BaggageBuilder and Outputmessages middleware#187
nikhilNava merged 11 commits intomainfrom
copilot/implement-baggage-middleware-python

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

Manual testing
Baggage and outputs can now be set automatically using the middleware.

    "name": "Chat gpt-4o-mini",
    "context": {
        "trace_id": "0x38450fdd1383989d9c2abadd54cef526",
        "span_id": "0x167b776d77c63441",
        "trace_state": "[]"
    },
    "kind": "SpanKind.CLIENT",
    "parent_id": "0x46f72b83108d8113",
    "start_time": "2026-03-02T18:02:00.210340Z",
    "end_time": "2026-03-02T18:02:02.550658Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {
        "operation.source": "SDK",
        "gen_ai.conversation.item.link": "http://localhost:56150/_connector",
        "gen_ai.agent.upn": "b7a3a940-b39a-4a82-9629-0048f947f80a",
        "gen_ai.channel.name": "msteams",
        "gen_ai.system": "az.ai.agent365",
        "gen_ai.agent.id": "84d06baf-416c-4a43-a22d-f2ee93ea9e7e",
        "gen_ai.agent.name": "Azure OpenAI Agent",
        "gen_ai.agent.description": "An AI agent powered by Azure OpenAI",
        "gen_ai.agent.applicationid": "4a380e3b-7092-4d73-bb9d-b6a54702684af",
        "gen_ai.conversation.id": "b84d4c7e-9d83-403f-8f66-22644ff5b0bf",
        "tenant.id": "badf1f56-284d-4dc5-ac59-0dd53900e743",
        "gen_ai.input.messages": "Compute 15 % 4",
        "gen_ai.operation.name": "Chat",
        "gen_ai.request.model": "gpt-4o-mini",
        "gen_ai.provider.name": "Azure OpenAI",
        "gen_ai.output.messages": "\"15 % 4 equals 3. \\n\\nThis is because when you divide 15 by 4, the quotient is 3 and the remainder is 3.\"",
        "gen_ai.usage.input_tokens": "33",
        "gen_ai.usage.output_tokens": "34",
        "gen_ai.response.finish_reasons": "[\"stop\"]"
    },
    "events": [],
    "links": [],
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.38.0",
            "service.namespace": "AzureOpenAiKairoTesting",
            "service.name": "AzureOpenAiKairoTracing"
        },
        "schema_url": ""
    }
}
{
    "name": "output_messages 84d06baf-416c-4a43-a22d-f2ee93ea9e7e",
    "context": {
        "trace_id": "0x38450fdd1383989d9c2abadd54cef526",
        "span_id": "0x7f45a1dc264cfc23",
        "trace_state": "[]"
    },
    "kind": "SpanKind.CLIENT",
    "parent_id": "0x46f72b83108d8113",
    "start_time": "2026-03-02T18:02:02.550658Z",
    "end_time": "2026-03-02T18:02:02.552928Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {
        "operation.source": "SDK",
        "gen_ai.conversation.item.link": "http://localhost:56150/_connector",
        "gen_ai.system": "az.ai.agent365",
        "gen_ai.operation.name": "output_messages",
        "gen_ai.agent.id": "84d06baf-416c-4a43-a22d-f2ee93ea9e7e",
        "gen_ai.agent.name": "nikhilcPermTest",
        "gen_ai.agent.description": "agenticUser",
        "gen_ai.agent.upn": "b7a3a940-b39a-4a82-9629-0048f947f80a",
        "tenant.id": "badf1f56-284d-4dc5-ac59-0dd53900e743",
        "gen_ai.output.messages": "[\"15 % 4 equals 3. \\n\\nThis is because when you divide 15 by 4, the quotient is 3 and the remainder is 3.\"]",
        "gen_ai.conversation.id": "b84d4c7e-9d83-403f-8f66-22644ff5b0bf",
        "gen_ai.execution.type": "HumanToAgent",
        "gen_ai.channel.name": "msteams",
        "gen_ai.caller.id": "a92962f3-9ed4-4bcd-9ae0-ad0002b6ca76",
        "gen_ai.caller.name": "Alex Wilber"
    },
    "events": [],
    "links": [],
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.38.0",
            "service.namespace": "AzureOpenAiKairoTesting",
            "service.name": "AzureOpenAiKairoTracing"
        },
        "schema_url": ""
    }
}
{
    "name": "invoke_agent Azure OpenAI Agent",
    "context": {
        "trace_id": "0x38450fdd1383989d9c2abadd54cef526",
        "span_id": "0x46f72b83108d8113",
        "trace_state": "[]"
    },
    "kind": "SpanKind.CLIENT",
    "parent_id": null,
    "start_time": "2026-03-02T18:01:59.050044Z",
    "end_time": "2026-03-02T18:02:02.555195Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {
        "operation.source": "SDK",
        "gen_ai.conversation.item.link": "http://localhost:56150/_connector",
        "gen_ai.agent.upn": "b7a3a940-b39a-4a82-9629-0048f947f80a",
        "gen_ai.channel.name": "msteams",
        "gen_ai.caller.id": "a92962f3-9ed4-4bcd-9ae0-ad0002b6ca76",
        "gen_ai.caller.name": "Alex Wilber",
        "gen_ai.system": "az.ai.agent365",
        "gen_ai.operation.name": "invoke_agent",
        "gen_ai.agent.id": "84d06baf-416c-4a43-a22d-f2ee93ea9e7e",
        "gen_ai.agent.name": "Azure OpenAI Agent",
        "gen_ai.agent.description": "An AI agent powered by Azure OpenAI",
        "gen_ai.agent.applicationid": "4a380e3b-7092-4d73-bb9d-b6a54702684af",
        "gen_ai.conversation.id": "b84d4c7e-9d83-403f-8f66-22644ff5b0bf",
        "tenant.id": "badf1f56-284d-4dc5-ac59-0dd53900e743",
        "session.id": "b84d4c7e-9d83-403f-8f66-22644ff5b0bf",
        "gen_ai.execution.type": "HumanToAgent",
        "gen_ai.input.messages": "[\"Compute 15 % 4\"]"
    },
    "events": [],
    "links": [],
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.38.0",
            "service.namespace": "AzureOpenAiKairoTesting",
            "service.name": "AzureOpenAiKairoTracing"
        },
        "schema_url": ""
    }
}

The logic callback type in BaggageMiddleware and OutputLoggingMiddleware was changed to Callable[[], Awaitable] to match runtime behavior, but this diverges from the upstream Middleware Protocol which defines Callable[[TurnContext], Awaitable]. All reference implementations (e.g. TranscriptLoggerMiddleware) follow the Protocol signature. Additionally, tests had redundant cases that could be consolidated.

Type annotation

  • Reverted logic type to Callable[[TurnContext], Awaitable] in both middlewares to match the Middleware Protocol in microsoft-agents-hosting-core

Agentic gating

  • _derive_agent_details gates on activity.is_agentic_request() and returns None for non-agentic requests, preventing spans with empty agent_id
  • Test recipient uses role="agenticAppInstance" to exercise the agentic code path

Test consolidation (31 → 28 tests, same coverage)

  • Removed test_baggage_middleware_calls_logic — already proven by test_baggage_middleware_propagates_baggage
  • Merged test_send_handler_creates_output_scope_for_messages and test_send_handler_disposes_scope_on_success (duplicate success-path setup)
  • Merged test_configure_returns_instance into test_configure_is_singleton
  • Parametrized 4 middleware registration tests → test_configure_registers_expected_middlewares
  • Parametrized 2 TypeError tests → test_configure_raises_on_none

Cleanup

  • Removed unused logging/logger from baggage_middleware.py

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…ingManager

Implement Python equivalents of the Node.js PR #210 middleware:
- BaggageMiddleware: propagates OpenTelemetry baggage from TurnContext
- OutputLoggingMiddleware: creates OutputScope spans for outgoing messages
- ObservabilityHostingManager: singleton to configure hosting middleware
- 19 unit tests covering all three middleware components

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement middleware in Python from Node.js code Add BaggageMiddleware, OutputLoggingMiddleware, and ObservabilityHostingManager Feb 27, 2026
…pe and require non-None params

- Replace _AdapterLike protocol with actual ChannelAdapter from microsoft_agents.hosting.core
- Make adapter and options required (non-optional) parameters
- Raise TypeError if either is None
- Update tests to match new contract

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
…d of direct attribute access

- Change adapter param type from ChannelAdapter to MiddlewareSet (the actual
  middleware registration object)
- Use activity.get_agentic_instance_id() instead of recipient.agentic_app_id
- Use activity.get_agentic_user() instead of recipient.agentic_user_id
- Update test to use agentic role for proper helper method behavior

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
Copilot AI changed the title Add BaggageMiddleware, OutputLoggingMiddleware, and ObservabilityHostingManager Use MiddlewareSet type for adapter param and Activity helper methods for agentic properties Mar 2, 2026
@github-actions
Copy link

github-actions bot commented Mar 2, 2026

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@nikhilNava nikhilNava marked this pull request as ready for review March 2, 2026 15:05
Copilot AI review requested due to automatic review settings March 2, 2026 15:05
@nikhilNava nikhilNava requested a review from a team as a code owner March 2, 2026 15:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the hosting-layer observability integration to (1) configure middleware against the concrete MiddlewareSet type with required parameters, and (2) align agentic identity extraction with the canonical Activity helper APIs.

Changes:

  • Tightens ObservabilityHostingManager.configure() to require a MiddlewareSet adapter + options (raising TypeError on None) and registers hosting middlewares accordingly.
  • Switches agentic property access to Activity.get_agentic_instance_id() / Activity.get_agentic_user() (vs direct recipient.* access).
  • Adds/updates unit tests for the new hosting middleware and configuration behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/observability/hosting/scope_helpers/test_scope_helper_utils.py Updates test data to use an agentic role so agentic helpers are exercised.
tests/observability/hosting/middleware/test_output_logging_middleware.py Adds tests covering output logging middleware send pipeline behavior.
tests/observability/hosting/middleware/test_observability_hosting_manager.py Adds tests for singleton configure semantics and required params.
tests/observability/hosting/middleware/test_baggage_middleware.py Adds tests for baggage propagation and async-reply skip behavior.
tests/observability/hosting/middleware/init.py Test package init added (copyright header only).
libraries/.../scope_helpers/utils.py Uses Activity helper methods for agentic instance/user IDs in target agent pairs.
libraries/.../middleware/output_logging_middleware.py Introduces middleware to create OutputScope spans for outgoing messages.
libraries/.../middleware/observability_hosting_manager.py Introduces singleton manager that registers hosting observability middleware.
libraries/.../middleware/baggage_middleware.py Introduces middleware that populates OpenTelemetry baggage from TurnContext.
libraries/.../middleware/init.py Exports the new middleware + manager symbols.
libraries/.../hosting/init.py Re-exports middleware/manager at the hosting package level.

…tead of ChannelAdapter

ChannelAdapter is an ABC (CloudAdapter extends ChannelServiceAdapter extends
ChannelAdapter). The adapter HAS-A MiddlewareSet (composition) — it is not one.
The configure() method only needs the middleware registration object, so accept
MiddlewareSet directly. Users pass adapter.middleware_set.

Rename parameter from 'adapter' to 'middleware_set' for clarity.

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
Copilot AI changed the title Use MiddlewareSet type for adapter param and Activity helper methods for agentic properties Use MiddlewareSet type and Activity helper methods in observability hosting Mar 2, 2026
@nikhilNava nikhilNava changed the title Use MiddlewareSet type and Activity helper methods in observability hosting Use middleware to set baggage builder and capture outputs automatically Mar 2, 2026
…request

- Fix `logic` type annotation from `Callable[[TurnContext], Awaitable]` to
  `Callable[[], Awaitable]` in both BaggageMiddleware and
  OutputLoggingMiddleware. At runtime, MiddlewareSet passes a zero-arg
  `call_next_middleware` closure, so the annotation now matches the callsite.

- Gate `_derive_agent_details` on `activity.is_agentic_request()` to avoid
  emitting spans with empty agent_id for non-agentic requests.

- Remove unused `logging`/`logger` from baggage_middleware.py.

- Update test recipient role from "assistant" to "agenticAppInstance" to
  exercise the intended agentic code path.

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
…leware Protocol; consolidate tests

Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
Copilot AI changed the title Use middleware to set baggage builder and capture outputs automatically Align middleware with Middleware Protocol; consolidate tests Mar 2, 2026
@nikhilNava nikhilNava enabled auto-merge (squash) March 2, 2026 18:56
juliomenendez
juliomenendez previously approved these changes Mar 2, 2026
@nikhilNava nikhilNava changed the title Align middleware with Middleware Protocol; consolidate tests Align BaggageBuilder and Outputmessages middleware Mar 3, 2026
@nikhilNava nikhilNava merged commit 5ce0785 into main Mar 3, 2026
9 checks passed
@nikhilNava nikhilNava deleted the copilot/implement-baggage-middleware-python branch March 3, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants