From b38bc13d5e7ddec82c32e82636fd024f3af277d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 23 Jun 2026 10:45:50 -0700 Subject: [PATCH 1/4] before and after turn middleware hooks --- .../hosting/core/app/_type_defs.py | 2 +- .../hosting/core/app/agent_application.py | 37 ++ .../hosting/core/app/oauth/authorization.py | 10 + .../app/_oauth/test_authorization.py | 4 + .../proactive/test_conversation_builder.py | 1 - .../test_conversation_reference_builder.py | 1 - .../app/proactive/test_proactive.py | 1 - .../app/test_agent_application.py | 341 +++++++++++++++++- 8 files changed, 392 insertions(+), 5 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/_type_defs.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/_type_defs.py index f5ceb61a2..2520a2941 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/_type_defs.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/_type_defs.py @@ -12,4 +12,4 @@ class RouteHandler(Protocol[StateT]): - def __call__(self, context: TurnContext, state: StateT) -> Awaitable[None]: ... + def __call__(self, context: TurnContext, state: StateT, /) -> Awaitable[None]: ... diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py index 1b76103ba..66f382bea 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py @@ -159,6 +159,15 @@ def __init__( if authorization: self._auth = authorization else: + if not connection_manager: + logger.error( + "AgentApplication: connection_manager is required for Authorization.", + stack_info=True, + ) + raise ApplicationError(""" + The `AgentApplication` requires a `connection_manager` to initialize the `Authorization` instance. + """) + auth_options = { key: value for key, value in configuration.items() @@ -244,6 +253,34 @@ def proactive(self) -> Proactive: """) return self._proactive + def before_turn( + self, handler: Callable[[TurnContext, TurnState], Awaitable[bool]] + ) -> Callable[[TurnContext, TurnState], Awaitable[bool]]: + """ + Adds a handler to be called before each turn of the conversation. + + :param handler: A function that takes a TurnContext and a TurnState and returns an Awaitable. + :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :return: The added handler. + :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + """ + self._internal_before_turn.append(handler) + return handler + + def after_turn( + self, handler: Callable[[TurnContext, TurnState], Awaitable[bool]] + ) -> Callable[[TurnContext, TurnState], Awaitable[bool]]: + """ + Adds a handler to be called after each turn of the conversation. + + :param handler: A function that takes a TurnContext and a TurnState and returns an Awaitable. + :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :return: The added handler. + :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + """ + self._internal_after_turn.append(handler) + return handler + def add_route( self, selector: RouteSelector, diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py index a69f74e3a..fa70e8476 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py @@ -126,6 +126,16 @@ def _init_handlers(self) -> None: auth_handler=auth_handler, ) + @property + def connection_manager(self) -> Connections: + """ + The connection manager for the authorization instance. + + :return: The connection manager. + :rtype: :class:`microsoft_agents.hosting.core.app.connections.Connections` + """ + return self._connection_manager + @staticmethod def _sign_in_state_key(context: TurnContext) -> str: """Generate a unique storage key for the sign-in state based on the context. diff --git a/tests/hosting_core/app/_oauth/test_authorization.py b/tests/hosting_core/app/_oauth/test_authorization.py index c6e6e020e..81cdd6e74 100644 --- a/tests/hosting_core/app/_oauth/test_authorization.py +++ b/tests/hosting_core/app/_oauth/test_authorization.py @@ -187,6 +187,10 @@ def test_resolve_handler(self, connection_manager, storage, auth_handler_id): auth_handler_id, **handler_config ) + def test_connection_manager_property(self, connection_manager, storage): + auth = Authorization(storage, connection_manager, **ENV_DICT) + assert auth.connection_manager is connection_manager + def test_sign_in_state_key(self, mocker, connection_manager, storage): auth = Authorization(storage, connection_manager, **ENV_DICT) context = self.TurnContext(mocker) diff --git a/tests/hosting_core/app/proactive/test_conversation_builder.py b/tests/hosting_core/app/proactive/test_conversation_builder.py index eab7ded16..931e44ea5 100644 --- a/tests/hosting_core/app/proactive/test_conversation_builder.py +++ b/tests/hosting_core/app/proactive/test_conversation_builder.py @@ -11,7 +11,6 @@ ) from microsoft_agents.hosting.core.authorization import ClaimsIdentity - # --------------------------------------------------------------------------- # Helper # --------------------------------------------------------------------------- diff --git a/tests/hosting_core/app/proactive/test_conversation_reference_builder.py b/tests/hosting_core/app/proactive/test_conversation_reference_builder.py index 4ab646e29..98d2bc4fb 100644 --- a/tests/hosting_core/app/proactive/test_conversation_reference_builder.py +++ b/tests/hosting_core/app/proactive/test_conversation_reference_builder.py @@ -10,7 +10,6 @@ _service_url_for_channel, ) - # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- diff --git a/tests/hosting_core/app/proactive/test_proactive.py b/tests/hosting_core/app/proactive/test_proactive.py index f3afa664e..d7c73f518 100644 --- a/tests/hosting_core/app/proactive/test_proactive.py +++ b/tests/hosting_core/app/proactive/test_proactive.py @@ -26,7 +26,6 @@ from microsoft_agents.hosting.core.authorization import ClaimsIdentity from microsoft_agents.hosting.core.channel_adapter import ChannelAdapter - # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- diff --git a/tests/hosting_core/app/test_agent_application.py b/tests/hosting_core/app/test_agent_application.py index 40e184d5d..548718034 100644 --- a/tests/hosting_core/app/test_agent_application.py +++ b/tests/hosting_core/app/test_agent_application.py @@ -15,6 +15,38 @@ ApplicationOptions, TurnState, ) +from microsoft_agents.hosting.core.app.app_error import ApplicationError +from microsoft_agents.hosting.core.app.oauth import Authorization +from tests._common.testing_objects import TestingConnectionManager as _ConnectionManager + + +def _make_event_activity() -> Activity: + """Minimal event Activity with all fields required by state loading.""" + return Activity( + type=ActivityTypes.event, + channel_id="test_channel", + conversation={"id": "test_conv"}, + from_property={"id": "test_user"}, + ) + + +def _make_integration_app() -> AgentApplication: + """AgentApplication wired for on_turn integration tests (no typing, no mention-strip).""" + app = AgentApplication[TurnState]( + options=ApplicationOptions( + storage=MemoryStorage(), + start_typing_timer=False, + remove_recipient_mention=False, + ), + authorization=Authorization( + storage=MemoryStorage(), + connection_manager=_ConnectionManager(), + ), + ) + # Shadow class-level lists with fresh instance-level lists for test isolation + app._internal_before_turn = [] + app._internal_after_turn = [] + return app class StubAdapter: @@ -45,6 +77,24 @@ async def send_activity(self, activity): self.responded = True +def make_auth(): + return Authorization( + storage=MemoryStorage(), + connection_manager=_ConnectionManager(), + ) + + +def make_app(): + app = AgentApplication[TurnState]( + options=ApplicationOptions(storage=MemoryStorage()), + authorization=make_auth(), + ) + # Reset to instance-level lists to isolate tests from the class-level defaults + app._internal_before_turn = [] + app._internal_after_turn = [] + return app + + @pytest.mark.asyncio async def test_on_turn_no_typing_when_start_typing_timer_false(): """When start_typing_timer=False, no typing indicators should be sent.""" @@ -53,7 +103,8 @@ async def test_on_turn_no_typing_when_start_typing_timer_false(): options=ApplicationOptions( storage=MemoryStorage(), start_typing_timer=False, - ) + ), + authorization=make_auth(), ) context = StubTurnContext( @@ -94,3 +145,291 @@ async def test_on_turn_no_typing_when_start_typing_timer_false(): # No on_send_activities hook should have been registered assert len(context._on_send_handlers) == 0 + + +# --------------------------------------------------------------------------- +# AgentApplication.__init__ guard: connection_manager required +# --------------------------------------------------------------------------- + + +def test_init_raises_without_authorization_or_connection_manager(): + with pytest.raises(ApplicationError): + AgentApplication[TurnState](options=ApplicationOptions(storage=MemoryStorage())) + + +def test_init_succeeds_when_authorization_provided_without_connection_manager(): + auth = make_auth() + app = AgentApplication[TurnState]( + options=ApplicationOptions(storage=MemoryStorage()), + authorization=auth, + ) + assert app.auth is auth + + +# --------------------------------------------------------------------------- +# before_turn / after_turn – registration +# --------------------------------------------------------------------------- + + +def test_before_turn_registers_handler(): + app = make_app() + + async def handler(ctx, state): + return True + + app.before_turn(handler) + assert handler in app._internal_before_turn + + +def test_after_turn_registers_handler(): + app = make_app() + + async def handler(ctx, state): + return True + + app.after_turn(handler) + assert handler in app._internal_after_turn + + +def test_before_turn_multiple_handlers_preserved_in_order(): + app = make_app() + + async def first(ctx, state): + return True + + async def second(ctx, state): + return True + + app.before_turn(first) + app.before_turn(second) + assert app._internal_before_turn == [first, second] + + +def test_after_turn_multiple_handlers_preserved_in_order(): + app = make_app() + + async def first(ctx, state): + return True + + async def second(ctx, state): + return True + + app.after_turn(first) + app.after_turn(second) + assert app._internal_after_turn == [first, second] + + +# --------------------------------------------------------------------------- +# before_turn / after_turn – execution via middleware helpers +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_run_before_turn_middleware_calls_handler_with_context_and_state(): + app = make_app() + calls = [] + + async def handler(ctx, state): + calls.append((ctx, state)) + return True + + app.before_turn(handler) + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_before_turn_middleware(context, state) + + assert result is True + assert len(calls) == 1 + assert calls[0] == (context, state) + + +@pytest.mark.asyncio +async def test_run_before_turn_middleware_returns_false_and_stops_on_false_handler(): + app = make_app() + calls = [] + + async def first(ctx, state): + calls.append("first") + return False + + async def second(ctx, state): + calls.append("second") + return True + + app.before_turn(first) + app.before_turn(second) + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_before_turn_middleware(context, state) + + assert result is False + assert calls == ["first"] + + +@pytest.mark.asyncio +async def test_run_before_turn_middleware_returns_true_when_no_handlers(): + app = make_app() + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_before_turn_middleware(context, state) + + assert result is True + + +@pytest.mark.asyncio +async def test_run_after_turn_middleware_calls_handler_with_context_and_state(): + app = make_app() + calls = [] + + async def handler(ctx, state): + calls.append((ctx, state)) + return True + + app.after_turn(handler) + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_after_turn_middleware(context, state) + + assert result is True + assert len(calls) == 1 + assert calls[0] == (context, state) + + +@pytest.mark.asyncio +async def test_run_after_turn_middleware_returns_false_and_stops_on_false_handler(): + app = make_app() + calls = [] + + async def first(ctx, state): + calls.append("first") + return False + + async def second(ctx, state): + calls.append("second") + return True + + app.after_turn(first) + app.after_turn(second) + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_after_turn_middleware(context, state) + + assert result is False + assert calls == ["first"] + + +@pytest.mark.asyncio +async def test_run_after_turn_middleware_returns_true_when_no_handlers(): + app = make_app() + + context = StubTurnContext(Activity(type=ActivityTypes.event)) + state = TurnState() + result = await app._run_after_turn_middleware(context, state) + + assert result is True + + +# --------------------------------------------------------------------------- +# Integration tests: before_turn / after_turn through on_turn +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_on_turn_calls_before_turn_handler(): + app = _make_integration_app() + calls = [] + + async def before(ctx, state): + calls.append("before") + return True + + app.before_turn(before) + await app.on_turn(StubTurnContext(_make_event_activity())) + + assert calls == ["before"] + + +@pytest.mark.asyncio +async def test_on_turn_calls_after_turn_handler(): + app = _make_integration_app() + calls = [] + + async def after(ctx, state): + calls.append("after") + return True + + app.after_turn(after) + await app.on_turn(StubTurnContext(_make_event_activity())) + + assert calls == ["after"] + + +@pytest.mark.asyncio +async def test_on_turn_before_turn_false_skips_activity_handler(): + app = _make_integration_app() + calls = [] + + async def before(ctx, state): + calls.append("before") + return False + + app.before_turn(before) + + @app.activity(ActivityTypes.event) + async def on_event(ctx, state): + calls.append("event") + + await app.on_turn(StubTurnContext(_make_event_activity())) + + assert calls == ["before"] + + +@pytest.mark.asyncio +async def test_on_turn_execution_order_before_activity_after(): + app = _make_integration_app() + calls = [] + + async def before(ctx, state): + calls.append("before") + return True + + async def after(ctx, state): + calls.append("after") + return True + + app.before_turn(before) + app.after_turn(after) + + @app.activity(ActivityTypes.event) + async def on_event(ctx, state): + calls.append("event") + + await app.on_turn(StubTurnContext(_make_event_activity())) + + assert calls == ["before", "event", "after"] + + +@pytest.mark.asyncio +async def test_on_turn_after_turn_false_still_runs_after_activity_handler(): + """after_turn returning False stops state save but does not prevent the activity handler.""" + app = _make_integration_app() + calls = [] + + async def after(ctx, state): + calls.append("after") + return False + + app.after_turn(after) + + @app.activity(ActivityTypes.event) + async def on_event(ctx, state): + calls.append("event") + + await app.on_turn(StubTurnContext(_make_event_activity())) + + assert calls == ["event", "after"] From 7aa7fd49c13ecdda33e4fe9fe83bb7710eb4094f Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 23 Jun 2026 11:01:09 -0700 Subject: [PATCH 2/4] Addressing PR feedback --- .../hosting/core/app/agent_application.py | 20 +++++++++---------- .../hosting/core/app/oauth/authorization.py | 6 ++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py index 66f382bea..79ac1c60a 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py @@ -164,9 +164,9 @@ def __init__( "AgentApplication: connection_manager is required for Authorization.", stack_info=True, ) - raise ApplicationError(""" - The `AgentApplication` requires a `connection_manager` to initialize the `Authorization` instance. - """) + raise ApplicationError( + "The `AgentApplication` requires a `connection_manager` to initialize the `Authorization` instance." + ) auth_options = { key: value @@ -254,12 +254,12 @@ def proactive(self) -> Proactive: return self._proactive def before_turn( - self, handler: Callable[[TurnContext, TurnState], Awaitable[bool]] - ) -> Callable[[TurnContext, TurnState], Awaitable[bool]]: + self, handler: Callable[[TurnContext, StateT], Awaitable[bool]] + ) -> Callable[[TurnContext, StateT], Awaitable[bool]]: """ Adds a handler to be called before each turn of the conversation. - :param handler: A function that takes a TurnContext and a TurnState and returns an Awaitable. + :param handler: A function that takes a TurnContext and a StateT and returns an Awaitable. :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] :return: The added handler. :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] @@ -268,12 +268,12 @@ def before_turn( return handler def after_turn( - self, handler: Callable[[TurnContext, TurnState], Awaitable[bool]] - ) -> Callable[[TurnContext, TurnState], Awaitable[bool]]: + self, handler: Callable[[TurnContext, StateT], Awaitable[bool]] + ) -> Callable[[TurnContext, StateT], Awaitable[bool]]: """ Adds a handler to be called after each turn of the conversation. - :param handler: A function that takes a TurnContext and a TurnState and returns an Awaitable. + :param handler: A function that takes a TurnContext and a StateT and returns an Awaitable. :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] :return: The added handler. :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] @@ -296,7 +296,7 @@ def add_route( :param selector: A function that takes a TurnContext and returns a boolean indicating whether the route should be selected. :type selector: Callable[[:class:`microsoft_agents.hosting.core.turn_context.TurnContext`], bool] - :param handler: A function that takes a TurnContext and a TurnState and returns an Awaitable. + :param handler: A function that takes a TurnContext and a StateT and returns an Awaitable. :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] :param is_invoke: Whether the route is for an invoke activity, defaults to False :type is_invoke: bool, Optional diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py index fa70e8476..9370474e5 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py @@ -3,10 +3,8 @@ Licensed under the MIT License. """ -from datetime import datetime import logging -from typing import TypeVar, Optional, Callable, Awaitable, Generic, cast -import jwt +from typing import Optional, Callable, Awaitable, cast from microsoft_agents.activity import Activity, Channels, SignInConstants, TokenResponse from microsoft_agents.activity.activity_types import ActivityTypes @@ -132,7 +130,7 @@ def connection_manager(self) -> Connections: The connection manager for the authorization instance. :return: The connection manager. - :rtype: :class:`microsoft_agents.hosting.core.app.connections.Connections` + :rtype: :class:`microsoft_agents.hosting.core.authorization.Connections` """ return self._connection_manager From 9a511e4fbd5715c11d1bef9545963d93d31e14a2 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 23 Jun 2026 11:16:56 -0700 Subject: [PATCH 3/4] Fixing tests --- .../hosting/core/app/agent_application.py | 8 +++++--- .../hosting/core/app/oauth/authorization.py | 2 ++ tests/hosting_core/app/test_agent_application_routes.py | 9 ++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py index 98cc3077c..e2254fba6 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py @@ -71,9 +71,9 @@ class AgentApplication(Agent, Generic[StateT]): _adapter: Optional[ChannelServiceAdapter] = None _auth: Optional[Authorization] = None _proactive: Optional[Proactive] = None - _internal_before_turn: list[Callable[[TurnContext, StateT], Awaitable[bool]]] = [] - _internal_after_turn: list[Callable[[TurnContext, StateT], Awaitable[bool]]] = [] - _route_list: _RouteList[StateT] = _RouteList[StateT]() + _internal_before_turn: list[Callable[[TurnContext, StateT], Awaitable[bool]]] + _internal_after_turn: list[Callable[[TurnContext, StateT], Awaitable[bool]]] + _route_list: _RouteList[StateT] _error: Optional[Callable[[TurnContext, Exception], Awaitable[None]]] = None _turn_state_factory: Optional[Callable[[TurnContext], StateT]] = None @@ -98,6 +98,8 @@ def __init__( :type kwargs: Any """ self._route_list = _RouteList[StateT]() + self._internal_before_turn = [] + self._internal_after_turn = [] configuration = kwargs diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py index 9370474e5..542b2866e 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/authorization.py @@ -129,6 +129,8 @@ def connection_manager(self) -> Connections: """ The connection manager for the authorization instance. + The connection manager is responsible for managing the connections to the various authentication providers. + :return: The connection manager. :rtype: :class:`microsoft_agents.hosting.core.authorization.Connections` """ diff --git a/tests/hosting_core/app/test_agent_application_routes.py b/tests/hosting_core/app/test_agent_application_routes.py index 80a448bfc..fcb6548db 100644 --- a/tests/hosting_core/app/test_agent_application_routes.py +++ b/tests/hosting_core/app/test_agent_application_routes.py @@ -14,6 +14,8 @@ ApplicationOptions, TurnState, ) +from microsoft_agents.hosting.core.app.oauth import Authorization +from tests._common.testing_objects import TestingConnectionManager as _ConnectionManager class _StubAdapter: @@ -26,8 +28,13 @@ async def send_activities(self, context, activities): def _make_app() -> AgentApplication[TurnState]: + storage = MemoryStorage() return AgentApplication[TurnState]( - options=ApplicationOptions(storage=MemoryStorage()) + options=ApplicationOptions(storage=storage), + authorization=Authorization( + storage=storage, + connection_manager=_ConnectionManager(), + ), ) From 1b57e9c8e02e424eeb067b88efddfca888f2ff39 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 23 Jun 2026 12:07:43 -0700 Subject: [PATCH 4/4] Fix docstring type ref --- .../hosting/core/app/agent_application.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py index e2254fba6..9f8bf2209 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py @@ -262,9 +262,9 @@ def before_turn( Adds a handler to be called before each turn of the conversation. :param handler: A function that takes a TurnContext and a StateT and returns an Awaitable. - :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :type handler: Callable[[TurnContext, StateT], Awaitable[bool]] :return: The added handler. - :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :rtype: Callable[[TurnContext, StateT], Awaitable[bool]] """ self._internal_before_turn.append(handler) return handler @@ -276,9 +276,9 @@ def after_turn( Adds a handler to be called after each turn of the conversation. :param handler: A function that takes a TurnContext and a StateT and returns an Awaitable. - :type handler: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :type handler: Callable[[TurnContext, StateT], Awaitable[bool]] :return: The added handler. - :rtype: :class:`microsoft_agents.hosting.core.app._type_defs.RouteHandler`[StateT] + :rtype: Callable[[TurnContext, StateT], Awaitable[bool]] """ self._internal_after_turn.append(handler) return handler