Skip to content

Commit 64ce06e

Browse files
CopilotnikhilNava
andcommitted
Update ObservabilityHostingManager.configure to use ChannelAdapter type 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>
1 parent c858b8b commit 64ce06e

File tree

2 files changed

+37
-44
lines changed

2 files changed

+37
-44
lines changed

libraries/microsoft-agents-a365-observability-hosting/microsoft_agents_a365/observability/hosting/middleware/observability_hosting_manager.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,15 @@
77

88
import logging
99
from dataclasses import dataclass
10-
from typing import Protocol
1110

12-
from microsoft_agents.hosting.core import Middleware
11+
from microsoft_agents.hosting.core import ChannelAdapter
1312

1413
from .baggage_middleware import BaggageMiddleware
1514
from .output_logging_middleware import OutputLoggingMiddleware
1615

1716
logger = logging.getLogger(__name__)
1817

1918

20-
class _AdapterLike(Protocol):
21-
"""Protocol for adapter objects that support middleware registration."""
22-
23-
def use(self, middleware: Middleware) -> object: ...
24-
25-
2619
@dataclass
2720
class ObservabilityHostingOptions:
2821
"""Configuration options for the hosting observability layer."""
@@ -53,20 +46,28 @@ def __init__(self) -> None:
5346
@classmethod
5447
def configure(
5548
cls,
56-
adapter: _AdapterLike | None = None,
57-
options: ObservabilityHostingOptions | None = None,
49+
adapter: ChannelAdapter,
50+
options: ObservabilityHostingOptions,
5851
) -> ObservabilityHostingManager:
5952
"""Configure the singleton instance and register middleware on the adapter.
6053
6154
Subsequent calls after the first are no-ops and return the existing instance.
6255
6356
Args:
64-
adapter: An adapter that supports ``.use()`` for middleware registration.
65-
options: Configuration options. Defaults are used when ``None``.
57+
adapter: The channel adapter to register middleware on.
58+
options: Configuration options controlling which middleware to enable.
6659
6760
Returns:
6861
The singleton :class:`ObservabilityHostingManager` instance.
62+
63+
Raises:
64+
TypeError: If *adapter* or *options* is ``None``.
6965
"""
66+
if adapter is None:
67+
raise TypeError("adapter must not be None")
68+
if options is None:
69+
raise TypeError("options must not be None")
70+
7071
if cls._instance is not None:
7172
logger.warning(
7273
"[ObservabilityHostingManager] Already configured. "
@@ -76,26 +77,19 @@ def configure(
7677

7778
instance = cls()
7879

79-
if adapter is not None:
80-
opts = options or ObservabilityHostingOptions()
80+
if options.enable_baggage:
81+
adapter.use(BaggageMiddleware())
82+
logger.info("[ObservabilityHostingManager] BaggageMiddleware registered.")
8183

82-
if opts.enable_baggage:
83-
adapter.use(BaggageMiddleware())
84-
logger.info("[ObservabilityHostingManager] BaggageMiddleware registered.")
84+
if options.enable_output_logging:
85+
adapter.use(OutputLoggingMiddleware())
86+
logger.info("[ObservabilityHostingManager] OutputLoggingMiddleware registered.")
8587

86-
if opts.enable_output_logging:
87-
adapter.use(OutputLoggingMiddleware())
88-
logger.info("[ObservabilityHostingManager] OutputLoggingMiddleware registered.")
89-
90-
logger.info(
91-
"[ObservabilityHostingManager] Configured. Baggage: %s, OutputLogging: %s.",
92-
opts.enable_baggage,
93-
opts.enable_output_logging,
94-
)
95-
else:
96-
logger.warning(
97-
"[ObservabilityHostingManager] No adapter provided. No middleware registered."
98-
)
88+
logger.info(
89+
"[ObservabilityHostingManager] Configured. Baggage: %s, OutputLogging: %s.",
90+
options.enable_baggage,
91+
options.enable_output_logging,
92+
)
9993

10094
cls._instance = instance
10195
return instance

tests/observability/hosting/middleware/test_observability_hosting_manager.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,23 @@ def _reset_singleton():
2727
def test_configure_returns_instance():
2828
"""configure() should return an ObservabilityHostingManager instance."""
2929
adapter = MagicMock()
30-
instance = ObservabilityHostingManager.configure(adapter)
30+
instance = ObservabilityHostingManager.configure(adapter, ObservabilityHostingOptions())
3131
assert isinstance(instance, ObservabilityHostingManager)
3232

3333

3434
def test_configure_is_singleton():
3535
"""Subsequent configure() calls should return the same instance."""
3636
adapter = MagicMock()
37-
first = ObservabilityHostingManager.configure(adapter)
38-
second = ObservabilityHostingManager.configure(adapter)
37+
options = ObservabilityHostingOptions()
38+
first = ObservabilityHostingManager.configure(adapter, options)
39+
second = ObservabilityHostingManager.configure(adapter, options)
3940
assert first is second
4041

4142

4243
def test_configure_registers_baggage_middleware_by_default():
4344
"""By default, BaggageMiddleware should be registered."""
4445
adapter = MagicMock()
45-
ObservabilityHostingManager.configure(adapter)
46+
ObservabilityHostingManager.configure(adapter, ObservabilityHostingOptions())
4647

4748
# The adapter.use should have been called once (only BaggageMiddleware by default)
4849
assert adapter.use.call_count == 1
@@ -82,16 +83,14 @@ def test_configure_disables_all():
8283
adapter.use.assert_not_called()
8384

8485

85-
def test_configure_no_adapter():
86-
"""When no adapter is provided, no middleware should be registered."""
87-
instance = ObservabilityHostingManager.configure()
88-
assert isinstance(instance, ObservabilityHostingManager)
86+
def test_configure_raises_on_none_adapter():
87+
"""configure() should raise TypeError when adapter is None."""
88+
with pytest.raises(TypeError, match="adapter must not be None"):
89+
ObservabilityHostingManager.configure(None, ObservabilityHostingOptions())
8990

9091

91-
def test_configure_no_adapter_subsequent_call_ignored():
92-
"""Subsequent calls after no-adapter configure should still be no-ops."""
93-
first = ObservabilityHostingManager.configure()
92+
def test_configure_raises_on_none_options():
93+
"""configure() should raise TypeError when options is None."""
9494
adapter = MagicMock()
95-
second = ObservabilityHostingManager.configure(adapter)
96-
assert first is second
97-
adapter.use.assert_not_called()
95+
with pytest.raises(TypeError, match="options must not be None"):
96+
ObservabilityHostingManager.configure(adapter, None)

0 commit comments

Comments
 (0)