33import traceback
44from abc import ABC , abstractmethod
55from collections .abc import AsyncGenerator
6- from typing import Any
6+ from typing import Any , Union
77
8+ from fastapi import FastAPI
89from pydantic import ValidationError
910from sse_starlette .sse import EventSourceResponse
1011from starlette .applications import Starlette
1112from starlette .requests import Request
1213from starlette .responses import JSONResponse , Response
13- from starlette .routing import Route
1414
1515from a2a .server .context import ServerCallContext
1616from a2a .server .request_handlers .jsonrpc_handler import JSONRPCHandler
1717from a2a .server .request_handlers .request_handler import RequestHandler
18- from a2a .types import (A2AError , A2ARequest , AgentCard , CancelTaskRequest ,
19- GetTaskPushNotificationConfigRequest , GetTaskRequest ,
20- InternalError , InvalidRequestError , JSONParseError ,
21- JSONRPCError , JSONRPCErrorResponse , JSONRPCResponse ,
22- SendMessageRequest , SendStreamingMessageRequest ,
23- SendStreamingMessageResponse ,
24- SetTaskPushNotificationConfigRequest ,
25- TaskResubscriptionRequest , UnsupportedOperationError )
18+ from a2a .server .context import ServerCallContext
19+ from a2a .types import (
20+ A2AError ,
21+ A2ARequest ,
22+ AgentCard ,
23+ CancelTaskRequest ,
24+ GetTaskPushNotificationConfigRequest ,
25+ GetTaskRequest ,
26+ InternalError ,
27+ InvalidRequestError ,
28+ JSONParseError ,
29+ JSONRPCError ,
30+ JSONRPCErrorResponse ,
31+ JSONRPCResponse ,
32+ SendMessageRequest ,
33+ SendStreamingMessageRequest ,
34+ SendStreamingMessageResponse ,
35+ SetTaskPushNotificationConfigRequest ,
36+ TaskResubscriptionRequest ,
37+ UnsupportedOperationError ,
38+ )
39+
2640from a2a .utils .errors import MethodNotImplementedError
2741
2842logger = logging .getLogger (__name__ )
@@ -36,19 +50,19 @@ def build(self, request: Request) -> ServerCallContext:
3650 """Builds a ServerCallContext from a Starlette Request."""
3751
3852
39- class A2AStarletteApplication :
40- """A Starlette application implementing the A2A protocol server endpoints .
53+ class JSONRPCApplication ( ABC ) :
54+ """Base class for A2A applications .
4155
42- Handles incoming JSON-RPC requests, routes them to the appropriate
43- handler methods, and manages response generation including Server-Sent Events
44- (SSE).
56+ Args:
57+ agent_card: The AgentCard describing the agent's capabilities.
58+ http_handler: The handler instance responsible for processing A2A
59+ requests via http.
4560 """
4661
4762 def __init__ (
4863 self ,
4964 agent_card : AgentCard ,
5065 http_handler : RequestHandler ,
51- extended_agent_card : AgentCard | None = None ,
5266 context_builder : CallContextBuilder | None = None ,
5367 ):
5468 """Initializes the A2AStarletteApplication.
@@ -57,24 +71,14 @@ def __init__(
5771 agent_card: The AgentCard describing the agent's capabilities.
5872 http_handler: The handler instance responsible for processing A2A
5973 requests via http.
60- extended_agent_card: An optional, distinct AgentCard to be served
61- at the authenticated extended card endpoint.
6274 context_builder: The CallContextBuilder used to construct the
6375 ServerCallContext passed to the http_handler. If None, no
6476 ServerCallContext is passed.
6577 """
6678 self .agent_card = agent_card
67- self .extended_agent_card = extended_agent_card
6879 self .handler = JSONRPCHandler (
6980 agent_card = agent_card , request_handler = http_handler
7081 )
71- if (
72- self .agent_card .supportsAuthenticatedExtendedCard
73- and self .extended_agent_card is None
74- ):
75- logger .error (
76- 'AgentCard.supportsAuthenticatedExtendedCard is True, but no extended_agent_card was provided. The /agent/authenticatedExtendedCard endpoint will return 404.'
77- )
7882 self ._context_builder = context_builder
7983
8084 def _generate_error_response (
@@ -317,104 +321,25 @@ async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
317321 Returns:
318322 A JSONResponse containing the agent card data.
319323 """
320- # The public agent card is a direct serialization of the agent_card
321- # provided at initialization.
322324 return JSONResponse (
323325 self .agent_card .model_dump (mode = 'json' , exclude_none = True )
324326 )
325327
326- async def _handle_get_authenticated_extended_agent_card (
327- self , request : Request
328- ) -> JSONResponse :
329- """Handles GET requests for the authenticated extended agent card."""
330- if not self .agent_card .supportsAuthenticatedExtendedCard :
331- return JSONResponse (
332- {'error' : 'Extended agent card not supported or not enabled.' },
333- status_code = 404 ,
334- )
335-
336- # If an explicit extended_agent_card is provided, serve that.
337- if self .extended_agent_card :
338- return JSONResponse (
339- self .extended_agent_card .model_dump (
340- mode = 'json' , exclude_none = True
341- )
342- )
343- # If supportsAuthenticatedExtendedCard is true, but no specific
344- # extended_agent_card was provided during server initialization,
345- # return a 404
346- return JSONResponse (
347- {'error' : 'Authenticated extended agent card is supported but not configured on the server.' },
348- status_code = 404 ,
349- )
350-
351- def routes (
352- self ,
353- agent_card_url : str = '/.well-known/agent.json' ,
354- extended_agent_card_url : str = '/agent/authenticatedExtendedCard' ,
355- rpc_url : str = '/' ,
356- ) -> list [Route ]:
357- """Returns the Starlette Routes for handling A2A requests.
358-
359- Args:
360- agent_card_url: The URL path for the agent card endpoint.
361- rpc_url: The URL path for the A2A JSON-RPC endpoint (POST requests).
362- extended_agent_card_url: The URL for the authenticated extended agent card endpoint.
363-
364- Returns:
365- A list of Starlette Route objects.
366- """
367- app_routes = [
368- Route (
369- rpc_url ,
370- self ._handle_requests ,
371- methods = ['POST' ],
372- name = 'a2a_handler' ,
373- ),
374- Route (
375- agent_card_url ,
376- self ._handle_get_agent_card ,
377- methods = ['GET' ],
378- name = 'agent_card' ,
379- ),
380- ]
381-
382- if self .agent_card .supportsAuthenticatedExtendedCard :
383- app_routes .append (
384- Route (
385- extended_agent_card_url ,
386- self ._handle_get_authenticated_extended_agent_card ,
387- methods = ['GET' ],
388- name = 'authenticated_extended_agent_card' ,
389- )
390- )
391- return app_routes
392-
328+ @abstractmethod
393329 def build (
394330 self ,
395331 agent_card_url : str = '/.well-known/agent.json' ,
396- extended_agent_card_url : str = '/agent/authenticatedExtendedCard' ,
397332 rpc_url : str = '/' ,
398333 ** kwargs : Any ,
399- ) -> Starlette :
400- """Builds and returns the Starlette application instance.
334+ ) -> Union [ Starlette , FastAPI ] :
335+ """Builds and returns the FastAPI application instance.
401336
402337 Args:
403- agent_card_url: The URL path for the agent card endpoint.
404- rpc_url: The URL path for the A2A JSON-RPC endpoint (POST requests).
405- extended_agent_card_url: The URL for the authenticated extended agent card endpoint.
406- **kwargs: Additional keyword arguments to pass to the Starlette
407- constructor.
338+ agent_card_url: The URL for the agent card endpoint.
339+ rpc_url: The URL for the A2A JSON-RPC endpoint
340+ **kwargs: Additional keyword arguments to pass to the FastAPI constructor.
408341
409342 Returns:
410- A configured Starlette application instance.
343+ A configured FastAPI application instance.
411344 """
412- app_routes = self .routes (
413- agent_card_url , extended_agent_card_url , rpc_url
414- )
415- if 'routes' in kwargs :
416- kwargs ['routes' ].extend (app_routes )
417- else :
418- kwargs ['routes' ] = app_routes
419-
420- return Starlette (** kwargs )
345+ pass
0 commit comments