forked from a2aproject/a2a-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfastapi_app.py
More file actions
121 lines (100 loc) · 3.99 KB
/
fastapi_app.py
File metadata and controls
121 lines (100 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import logging
from typing import Any
from fastapi import FastAPI
from a2a.server.apps.jsonrpc.jsonrpc_app import (
JSONRPCApplication,
)
from a2a.types import A2ARequest
from a2a.utils.constants import (
AGENT_CARD_WELL_KNOWN_PATH,
DEFAULT_RPC_URL,
EXTENDED_AGENT_CARD_PATH,
PREV_AGENT_CARD_WELL_KNOWN_PATH,
)
logger = logging.getLogger(__name__)
class A2AFastAPI(FastAPI):
"""A FastAPI application that adds A2A-specific OpenAPI components."""
_a2a_components_added: bool = False
def openapi(self) -> dict[str, Any]:
"""Generates the OpenAPI schema for the application."""
openapi_schema = super().openapi()
if not self._a2a_components_added:
a2a_request_schema = A2ARequest.model_json_schema(
ref_template='#/components/schemas/{model}'
)
defs = a2a_request_schema.pop('$defs', {})
component_schemas = openapi_schema.setdefault(
'components', {}
).setdefault('schemas', {})
component_schemas.update(defs)
component_schemas['A2ARequest'] = a2a_request_schema
self._a2a_components_added = True
return openapi_schema
class A2AFastAPIApplication(JSONRPCApplication):
"""A FastAPI application implementing the A2A protocol server endpoints.
Handles incoming JSON-RPC requests, routes them to the appropriate
handler methods, and manages response generation including Server-Sent Events
(SSE).
"""
def add_routes_to_app(
self,
app: FastAPI,
agent_card_url: str = AGENT_CARD_WELL_KNOWN_PATH,
rpc_url: str = DEFAULT_RPC_URL,
extended_agent_card_url: str = EXTENDED_AGENT_CARD_PATH,
) -> None:
"""Adds the routes to the FastAPI application.
Args:
app: The FastAPI application to add the routes to.
agent_card_url: The URL for the agent card endpoint.
rpc_url: The URL for the A2A JSON-RPC endpoint.
extended_agent_card_url: The URL for the authenticated extended agent card endpoint.
"""
app.post(
rpc_url,
openapi_extra={
'requestBody': {
'content': {
'application/json': {
'schema': {
'$ref': '#/components/schemas/A2ARequest'
}
}
},
'required': True,
'description': 'A2ARequest',
}
},
)(self._handle_requests)
app.get(agent_card_url)(self._handle_get_agent_card)
if agent_card_url == AGENT_CARD_WELL_KNOWN_PATH:
# For backward compatibility, serve the agent card at the deprecated path as well.
# TODO: remove in a future release
app.get(PREV_AGENT_CARD_WELL_KNOWN_PATH)(
self._handle_get_agent_card
)
if self.agent_card.supports_authenticated_extended_card:
app.get(extended_agent_card_url)(
self._handle_get_authenticated_extended_agent_card
)
def build(
self,
agent_card_url: str = AGENT_CARD_WELL_KNOWN_PATH,
rpc_url: str = DEFAULT_RPC_URL,
extended_agent_card_url: str = EXTENDED_AGENT_CARD_PATH,
**kwargs: Any,
) -> FastAPI:
"""Builds and returns the FastAPI application instance.
Args:
agent_card_url: The URL for the agent card endpoint.
rpc_url: The URL for the A2A JSON-RPC endpoint.
extended_agent_card_url: The URL for the authenticated extended agent card endpoint.
**kwargs: Additional keyword arguments to pass to the FastAPI constructor.
Returns:
A configured FastAPI application instance.
"""
app = A2AFastAPI(**kwargs)
self.add_routes_to_app(
app, agent_card_url, rpc_url, extended_agent_card_url
)
return app