Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -47,8 +46,10 @@ def channel_service_route_table(
routes = RouteTableDef()
service_routes = ChannelServiceRoutes(handler, base_url)

def json_response(data: dict) -> Response:
return Response(body=json.dumps(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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
Expand All @@ -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:
Expand All @@ -47,8 +49,16 @@ async def deserialize_from_body(
return target_model.model_validate(body)

@staticmethod
def serialize_model(model_or_list: AgentsModel | list[AgentsModel]) -> dict:
"""Serialize model or list of models to JSON-compatible 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 or list of dicts."""
if isinstance(model_or_list, AgentsModel):
return model_or_list.model_dump(
mode="json", exclude_unset=True, by_alias=True
Expand Down Expand Up @@ -107,7 +117,7 @@ async def delete_activity(self, request: HttpRequestProtocol) -> None:
activity_id,
)

async def get_activity_members(self, request: HttpRequestProtocol) -> dict:
async def get_activity_members(self, request: HttpRequestProtocol) -> list[dict]:
Comment thread
rodrigobr-msft marked this conversation as resolved.
"""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")
Expand Down Expand Up @@ -136,7 +146,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(
Expand Down Expand Up @@ -177,7 +189,9 @@ async def delete_conversation_member(self, request: HttpRequestProtocol) -> dict
conversation_id,
member_id,
)
return self.serialize_model(result)
if result:
return self.serialize_model(result)
return {}

async def send_conversation_history(self, request: HttpRequestProtocol) -> dict:
"""Handle POST /v3/conversations/{conversation_id}/activities/history."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment thread
rodrigobr-msft marked this conversation as resolved.
Comment thread
rodrigobr-msft marked this conversation as resolved.

super().__init__(channel_service_client_factory)
super().__init__(factory)

async def process_request(
self, request: HttpRequestProtocol, agent: Agent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion libraries/microsoft-agents-hosting-fastapi/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Comment thread
rodrigobr-msft marked this conversation as resolved.

@app.post("/api/messages")
Expand Down
Loading