from abc import ABC, abstractmethod from typing import Any, Callable from arcade_core.schema import ToolCallRequest, ToolCallResponse, ToolDefinition from pydantic import BaseModel CatalogResponse = list[ToolDefinition] HealthCheckResponse = dict[str, str] JSONResponse = dict[str, Any] ResponseData = CatalogResponse | ToolCallResponse | HealthCheckResponse class RequestData(BaseModel): """ The raw data for a request to a worker. This is not intended to represent everything about an HTTP request, but just the essential info a framework integration will need to extract from the request. """ path: str """The path of the request.""" method: str """The method of the request.""" body_json: JSONResponse | None = None """The deserialized body of the request (e.g. JSON)""" class Router(ABC): """ A router is responsible for adding routes to the underlying framework hosting the worker. """ @abstractmethod def add_route( self, endpoint_path: str, handler: Callable, method: str, require_auth: bool = True, response_type: type[ResponseData] | None = None, **kwargs: Any, ) -> None: """ Add a route to the router. """ pass @abstractmethod def add_mount(self, path: str, app: Any, name: str | None = None) -> None: """Mount an ASGI application at the specified path. This is optional for routers to implement. If not implemented, MCPComponent will raise NotImplementedError. Args: path: The URL path to mount the app at app: The ASGI application to mount name: Optional name for the mount """ raise NotImplementedError("This router does not support mounting ASGI applications") class Worker(ABC): """ A Worker represents a collection of tools that is hosted inside a web framework and can be called by an Engine. """ @abstractmethod def get_catalog(self) -> CatalogResponse: """ Get the catalog of tools available in the worker. """ pass @abstractmethod async def call_tool(self, request: ToolCallRequest) -> ToolCallResponse: """ Send a request to call a tool to the Worker """ pass @abstractmethod def health_check(self) -> HealthCheckResponse: """ Perform a health check of the worker """ pass class WorkerComponent(ABC): def __init__(self, worker: Worker) -> None: self.worker = worker @abstractmethod def register(self, router: Router) -> None: """ Register the component with the given router. """ pass @abstractmethod async def __call__(self, request: RequestData) -> ResponseData: """ Handle the request. """ pass