@@ -33,26 +33,50 @@ class RESTAdapter:
3333 manages response generation including Server-Sent Events (SSE).
3434 """
3535
36- def __init__ (
36+ def __init__ ( # noqa: PLR0913
3737 self ,
3838 agent_card : AgentCard ,
3939 http_handler : RequestHandler ,
40+ extended_agent_card : AgentCard | None = None ,
4041 context_builder : CallContextBuilder | None = None ,
42+ card_modifier : Callable [[AgentCard ], AgentCard ] | None = None ,
43+ extended_card_modifier : Callable [
44+ [AgentCard , ServerCallContext ], AgentCard
45+ ]
46+ | None = None ,
4147 ):
4248 """Initializes the RESTApplication.
4349
4450 Args:
4551 agent_card: The AgentCard describing the agent's capabilities.
4652 http_handler: The handler instance responsible for processing A2A
4753 requests via http.
54+ extended_agent_card: An optional, distinct AgentCard to be served
55+ at the authenticated extended card endpoint.
4856 context_builder: The CallContextBuilder used to construct the
4957 ServerCallContext passed to the http_handler. If None, no
5058 ServerCallContext is passed.
59+ card_modifier: An optional callback to dynamically modify the public
60+ agent card before it is served.
61+ extended_card_modifier: An optional callback to dynamically modify
62+ the extended agent card before it is served. It receives the
63+ call context.
5164 """
5265 self .agent_card = agent_card
66+ self .extended_agent_card = extended_agent_card
67+ self .card_modifier = card_modifier
68+ self .extended_card_modifier = extended_card_modifier
5369 self .handler = RESTHandler (
5470 agent_card = agent_card , request_handler = http_handler
5571 )
72+ if (
73+ self .agent_card .supports_authenticated_extended_card
74+ and self .extended_agent_card is None
75+ and self .extended_card_modifier is None
76+ ):
77+ logger .error (
78+ 'AgentCard.supports_authenticated_extended_card is True, but no extended_agent_card was provided. The /agent/authenticatedExtendedCard endpoint will return 404.'
79+ )
5680 self ._context_builder = context_builder or DefaultCallContextBuilder ()
5781
5882 @rest_error_handler
@@ -84,35 +108,41 @@ async def event_generator(
84108 )
85109
86110 @rest_error_handler
87- async def handle_get_agent_card (self , request : Request ) -> JSONResponse :
111+ async def handle_get_agent_card (
112+ self , request : Request , call_context : ServerCallContext | None = None
113+ ) -> JSONResponse | Response :
88114 """Handles GET requests for the agent card endpoint.
89115
90116 Args:
91117 request: The incoming Starlette Request object.
118+ call_context: ServerCallContext
92119
93120 Returns:
94121 A JSONResponse containing the agent card data.
95122 """
96- if self .agent_card .supports_authenticated_extended_card :
97- return await self .handle_authenticated_agent_card (request ) # type: ignore[return-value]
123+ card_to_serve = self .agent_card
124+ if self .card_modifier :
125+ card_to_serve = self .card_modifier (card_to_serve )
98126
99- # The public agent card is a direct serialization of the agent_card
100- # provided at initialization.
101127 return JSONResponse (
102- self .agent_card .model_dump (mode = 'json' , exclude_none = True )
128+ card_to_serve .model_dump (
129+ exclude_none = True ,
130+ by_alias = True ,
131+ )
103132 )
104133
105134 @rest_error_handler
106135 async def handle_authenticated_agent_card (
107- self , request : Request
108- ) -> JSONResponse :
136+ self , request : Request , call_context : ServerCallContext | None = None
137+ ) -> JSONResponse | Response :
109138 """Hook for per credential agent card response.
110139
111140 If a dynamic card is needed based on the credentials provided in the request
112141 override this method and return the customized content.
113142
114143 Args:
115144 request: The incoming Starlette Request object.
145+ call_context: ServerCallContext
116146
117147 Returns:
118148 A JSONResponse containing the authenticated card.
@@ -123,8 +153,29 @@ async def handle_authenticated_agent_card(
123153 message = 'Authenticated card not supported'
124154 )
125155 )
156+ card_to_serve = self .extended_agent_card
157+
158+ if self .extended_card_modifier :
159+ context = self ._context_builder .build (request )
160+ # If no base extended card is provided, pass the public card to the modifier
161+ base_card = card_to_serve if card_to_serve else self .agent_card
162+ card_to_serve = self .extended_card_modifier (base_card , context )
163+
164+ if card_to_serve :
165+ return JSONResponse (
166+ card_to_serve .model_dump (
167+ exclude_none = True ,
168+ by_alias = True ,
169+ )
170+ )
171+ # If supports_authenticated_extended_card is true, but no
172+ # extended_agent_card was provided, and no modifier produced a card,
173+ # return a 404.
126174 return JSONResponse (
127- self .agent_card .model_dump (mode = 'json' , exclude_none = True )
175+ {
176+ 'error' : 'Authenticated extended agent card is supported but not configured on the server.'
177+ },
178+ status_code = 404 ,
128179 )
129180
130181 def routes (self ) -> dict [tuple [str , str ], Callable [[Request ], Any ]]:
@@ -177,7 +228,13 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]:
177228 ('/v1/tasks' , 'GET' ): functools .partial (
178229 self ._handle_request , self .handler .list_tasks
179230 ),
180- ('/v1/card' , 'GET' ): self .handle_get_agent_card ,
231+ ('v1/well_known/agent_json' , 'GET' ): functools .partial (
232+ self ._handle_request , self .handle_get_agent_card
233+ ),
181234 }
235+ if self .agent_card .supports_authenticated_extended_card :
236+ routes [('/v1/card' , 'GET' )] = functools .partial (
237+ self ._handle_request , self .handle_authenticated_agent_card
238+ )
182239
183240 return routes
0 commit comments