From 5ba954ff45dc1b1967cb0301efcbfa5469088023 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 10 Jul 2026 14:07:30 -0700 Subject: [PATCH 1/7] Fixing core.http modules --- .../aiohttp/channel_service_route_table.py | 2 +- .../core/http/_channel_service_routes.py | 36 +++++++++++++------ .../hosting/core/http/_http_adapter_base.py | 16 ++++++--- .../hosting/core/http/_http_response.py | 2 +- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py index 3a2acad49..7daddf1d0 100644 --- a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py +++ b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py @@ -47,7 +47,7 @@ def channel_service_route_table( routes = RouteTableDef() service_routes = ChannelServiceRoutes(handler, base_url) - def json_response(data: dict) -> Response: + def json_response(data: dict | list[dict]) -> Response: return Response(body=json.dumps(data), content_type="application/json") @routes.post(base_url + "/v3/conversations/{conversation_id}/activities") diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py index 3c7e5bcbe..ef62f4845 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py @@ -3,7 +3,7 @@ """Channel service route definitions (framework-agnostic logic).""" -from typing import Type +from typing import Type, TypeVar, overload from microsoft_agents.activity import ( AgentsModel, @@ -16,6 +16,8 @@ from ._http_request_protocol import HttpRequestProtocol +AgentsModelT = TypeVar("AgentsModelT", bound=AgentsModel) + class ChannelServiceRoutes: """Defines the Channel Service API routes and their handlers. @@ -36,8 +38,8 @@ def __init__(self, handler: ChannelApiHandlerProtocol, base_url: str = ""): @staticmethod async def deserialize_from_body( - request: HttpRequestProtocol, target_model: Type[AgentsModel] - ) -> AgentsModel: + request: HttpRequestProtocol, target_model: Type[AgentsModelT] + ) -> AgentsModelT: """Deserialize request body to target model.""" content_type = request.headers.get("Content-Type", "") if "application/json" not in content_type: @@ -47,7 +49,15 @@ async def deserialize_from_body( return target_model.model_validate(body) @staticmethod - def serialize_model(model_or_list: AgentsModel | list[AgentsModel]) -> dict: + @overload + def serialize_model(model_or_list: AgentsModelT) -> dict: ... + @staticmethod + @overload + def serialize_model(model_or_list: list[AgentsModelT]) -> list[dict]: ... + @staticmethod + def serialize_model( + model_or_list: AgentsModelT | list[AgentsModelT], + ) -> dict | list[dict]: """Serialize model or list of models to JSON-compatible dict.""" if isinstance(model_or_list, AgentsModel): return model_or_list.model_dump( @@ -97,17 +107,21 @@ async def update_activity(self, request: HttpRequestProtocol) -> dict: ) return self.serialize_model(result) - async def delete_activity(self, request: HttpRequestProtocol) -> None: + async def delete_activity(self, request: HttpRequestProtocol) -> dict: """Handle DELETE /v3/conversations/{conversation_id}/activities/{activity_id}.""" conversation_id = request.get_path_param("conversation_id") activity_id = request.get_path_param("activity_id") - await self.handler.on_delete_activity( + res = await self.handler.on_delete_activity( request.get_claims_identity(), conversation_id, activity_id, ) + if res: + return self.serialize_model(res) + else: + return {} - async def get_activity_members(self, request: HttpRequestProtocol) -> dict: + async def get_activity_members(self, request: HttpRequestProtocol) -> list[dict]: """Handle GET /v3/conversations/{conversation_id}/activities/{activity_id}/members.""" conversation_id = request.get_path_param("conversation_id") activity_id = request.get_path_param("activity_id") @@ -136,7 +150,9 @@ async def get_conversations(self, request: HttpRequestProtocol) -> dict: ) return self.serialize_model(result) - async def get_conversation_members(self, request: HttpRequestProtocol) -> dict: + async def get_conversation_members( + self, request: HttpRequestProtocol + ) -> list[dict]: """Handle GET /v3/conversations/{conversation_id}/members.""" conversation_id = request.get_path_param("conversation_id") result = await self.handler.on_get_conversation_members( @@ -172,12 +188,12 @@ async def delete_conversation_member(self, request: HttpRequestProtocol) -> dict """Handle DELETE /v3/conversations/{conversation_id}/members/{member_id}.""" conversation_id = request.get_path_param("conversation_id") member_id = request.get_path_param("member_id") - result = await self.handler.on_delete_conversation_member( + await self.handler.on_delete_conversation_member( request.get_claims_identity(), conversation_id, member_id, ) - return self.serialize_model(result) + return {} async def send_conversation_history(self, request: HttpRequestProtocol) -> dict: """Handle POST /v3/conversations/{conversation_id}/activities/history.""" diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_adapter_base.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_adapter_base.py index 4ea5438b6..ca84c0c20 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_adapter_base.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_adapter_base.py @@ -58,12 +58,18 @@ async def on_turn_error(context: TurnContext, error: Exception): self.on_turn_error = on_turn_error - channel_service_client_factory = ( - channel_service_client_factory - or RestChannelServiceClientFactory(connection_manager) - ) + factory: ChannelServiceClientFactoryBase + + if channel_service_client_factory: + factory = channel_service_client_factory + else: + if not connection_manager: + raise ValueError( + "HttpAdapterBase.__init__: Either channel_service_client_factory or connection_manager must be provided." + ) + factory = RestChannelServiceClientFactory(connection_manager) - super().__init__(channel_service_client_factory) + super().__init__(factory) async def process_request( self, request: HttpRequestProtocol, agent: Agent diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_response.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_response.py index 955ff2ad9..efe686574 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_response.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_http_response.py @@ -28,7 +28,7 @@ def ok(body: Any = None) -> HttpResponse: @staticmethod def accepted() -> HttpResponse: """Create 202 Accepted response.""" - return HttpResponse(status_code=202) + return HttpResponse(status_code=202, content_type=None) @staticmethod def json(body: Any, status_code: int = 200) -> HttpResponse: From 1762674f56717678d14224bc0ac0b4602f195bb6 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Mon, 13 Jul 2026 10:02:18 -0700 Subject: [PATCH 2/7] Another commit --- .../hosting/core/http/_channel_service_routes.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py index ef62f4845..162c2a7d4 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py @@ -107,19 +107,15 @@ async def update_activity(self, request: HttpRequestProtocol) -> dict: ) return self.serialize_model(result) - async def delete_activity(self, request: HttpRequestProtocol) -> dict: + async def delete_activity(self, request: HttpRequestProtocol) -> None: """Handle DELETE /v3/conversations/{conversation_id}/activities/{activity_id}.""" conversation_id = request.get_path_param("conversation_id") activity_id = request.get_path_param("activity_id") - res = await self.handler.on_delete_activity( + await self.handler.on_delete_activity( request.get_claims_identity(), conversation_id, activity_id, ) - if res: - return self.serialize_model(res) - else: - return {} async def get_activity_members(self, request: HttpRequestProtocol) -> list[dict]: """Handle GET /v3/conversations/{conversation_id}/activities/{activity_id}/members.""" From 70462d8d635f67ef5365840fa1178e890b280183 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Mon, 13 Jul 2026 10:10:31 -0700 Subject: [PATCH 3/7] Another commit --- .../hosting/core/http/_channel_service_routes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py index 162c2a7d4..b7f2d3d74 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py @@ -184,11 +184,13 @@ async def delete_conversation_member(self, request: HttpRequestProtocol) -> dict """Handle DELETE /v3/conversations/{conversation_id}/members/{member_id}.""" conversation_id = request.get_path_param("conversation_id") member_id = request.get_path_param("member_id") - await self.handler.on_delete_conversation_member( + result = await self.handler.on_delete_conversation_member( request.get_claims_identity(), conversation_id, member_id, ) + if result: + return self.serialize_model(result) return {} async def send_conversation_history(self, request: HttpRequestProtocol) -> dict: From 4410181a51be86a0d5136a05f0abdcc4460eb591 Mon Sep 17 00:00:00 2001 From: rodrigobr-msft Date: Mon, 13 Jul 2026 10:15:47 -0700 Subject: [PATCH 4/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../hosting/core/http/_channel_service_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py index b7f2d3d74..beca9fba7 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/http/_channel_service_routes.py @@ -58,7 +58,7 @@ def serialize_model(model_or_list: list[AgentsModelT]) -> list[dict]: ... def serialize_model( model_or_list: AgentsModelT | list[AgentsModelT], ) -> dict | list[dict]: - """Serialize model or list of models to JSON-compatible dict.""" + """Serialize model or list of models to JSON-compatible dict or list of dicts.""" if isinstance(model_or_list, AgentsModel): return model_or_list.model_dump( mode="json", exclude_unset=True, by_alias=True From c2107146722f613ab9c3a8723f9a6f0aa70b5ce8 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Mon, 13 Jul 2026 10:45:42 -0700 Subject: [PATCH 5/7] Another commit --- .../hosting/aiohttp/channel_service_route_table.py | 3 +-- .../microsoft_agents/hosting/aiohttp/cloud_adapter.py | 4 ++-- libraries/microsoft-agents-hosting-fastapi/readme.md | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py index 7daddf1d0..bde28e93e 100644 --- a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py +++ b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py @@ -1,6 +1,5 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import json from aiohttp.web import RouteTableDef, Request, Response @@ -48,7 +47,7 @@ def channel_service_route_table( service_routes = ChannelServiceRoutes(handler, base_url) def json_response(data: dict | list[dict]) -> Response: - return Response(body=json.dumps(data), content_type="application/json") + return Response(body=data, content_type="application/json") @routes.post(base_url + "/v3/conversations/{conversation_id}/activities") async def send_to_conversation(request: Request): diff --git a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py index 88373953e..659163409 100644 --- a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py +++ b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py @@ -45,8 +45,8 @@ class CloudAdapter(HttpAdapterBase, AgentHttpAdapter): def __init__( self, *, - connection_manager: Connections = None, - channel_service_client_factory: ChannelServiceClientFactoryBase = None, + connection_manager: Connections | None = None, + channel_service_client_factory: ChannelServiceClientFactoryBase | None = None, ): """ Initializes a new instance of the CloudAdapter class. diff --git a/libraries/microsoft-agents-hosting-fastapi/readme.md b/libraries/microsoft-agents-hosting-fastapi/readme.md index 7de12b5df..ecd6007e7 100644 --- a/libraries/microsoft-agents-hosting-fastapi/readme.md +++ b/libraries/microsoft-agents-hosting-fastapi/readme.md @@ -96,7 +96,8 @@ from microsoft_agents.hosting.fastapi import start_agent_process, CloudAdapter from microsoft_agents.hosting.core.app import AgentApplication app = FastAPI() -adapter = CloudAdapter() +connection_manager = MsalConnectionManager(**agents_sdk_config) +adapter = CloudAdapter(connection_manager=connection_manager) agent_app = AgentApplication() @app.post("/api/messages") From d717f3a1013f876f1470925cf66c761ac4350962 Mon Sep 17 00:00:00 2001 From: rodrigobr-msft Date: Mon, 13 Jul 2026 11:10:58 -0700 Subject: [PATCH 6/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../hosting/aiohttp/channel_service_route_table.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py index bde28e93e..8cc7bd7d9 100644 --- a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py +++ b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py @@ -46,8 +46,9 @@ def channel_service_route_table( routes = RouteTableDef() service_routes = ChannelServiceRoutes(handler, base_url) - def json_response(data: dict | list[dict]) -> Response: - return Response(body=data, content_type="application/json") +def json_response(data: dict | list[dict]) -> Response: + import json + return Response(text=json.dumps(data), content_type="application/json") @routes.post(base_url + "/v3/conversations/{conversation_id}/activities") async def send_to_conversation(request: Request): From c18b4a518096e9b35d4810fe1fe1edbf5106839d Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Mon, 13 Jul 2026 11:16:22 -0700 Subject: [PATCH 7/7] Formatting --- .../hosting/aiohttp/channel_service_route_table.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py index 8cc7bd7d9..eb9ace8da 100644 --- a/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py +++ b/libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/channel_service_route_table.py @@ -46,8 +46,9 @@ def channel_service_route_table( routes = RouteTableDef() service_routes = ChannelServiceRoutes(handler, base_url) -def json_response(data: dict | list[dict]) -> Response: + def json_response(data: dict | list[dict]) -> Response: import json + return Response(text=json.dumps(data), content_type="application/json") @routes.post(base_url + "/v3/conversations/{conversation_id}/activities")