Skip to content

Commit 5b2475e

Browse files
committed
Merge branch '1.0-dev' of https://github.com/sokoliva/a2a-python into 1.0-dev
2 parents 2f94c4e + 4be2064 commit 5b2475e

43 files changed

Lines changed: 1604 additions & 2538 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

samples/hello_world_agent.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@
1111
from a2a.compat.v0_3.grpc_handler import CompatGrpcHandler
1212
from a2a.server.agent_execution.agent_executor import AgentExecutor
1313
from a2a.server.agent_execution.context import RequestContext
14-
from a2a.server.apps import A2AFastAPIApplication, A2ARESTFastAPIApplication
1514
from a2a.server.events.event_queue import EventQueue
1615
from a2a.server.request_handlers import GrpcHandler
1716
from a2a.server.request_handlers.default_request_handler import (
1817
DefaultRequestHandler,
1918
)
19+
from a2a.server.routes import (
20+
create_agent_card_routes,
21+
create_jsonrpc_routes,
22+
create_rest_routes,
23+
)
2024
from a2a.server.tasks.inmemory_task_store import InMemoryTaskStore
2125
from a2a.server.tasks.task_updater import TaskUpdater
2226
from a2a.types import (
@@ -165,22 +169,22 @@ async def serve(
165169
AgentInterface(
166170
protocol_binding='JSONRPC',
167171
protocol_version='1.0',
168-
url=f'http://{host}:{port}/a2a/jsonrpc/',
172+
url=f'http://{host}:{port}/a2a/jsonrpc',
169173
),
170174
AgentInterface(
171175
protocol_binding='JSONRPC',
172176
protocol_version='0.3',
173-
url=f'http://{host}:{port}/a2a/jsonrpc/',
177+
url=f'http://{host}:{port}/a2a/jsonrpc',
174178
),
175179
AgentInterface(
176180
protocol_binding='HTTP+JSON',
177181
protocol_version='1.0',
178-
url=f'http://{host}:{port}/a2a/rest/',
182+
url=f'http://{host}:{port}/a2a/rest',
179183
),
180184
AgentInterface(
181185
protocol_binding='HTTP+JSON',
182186
protocol_version='0.3',
183-
url=f'http://{host}:{port}/a2a/rest/',
187+
url=f'http://{host}:{port}/a2a/rest',
184188
),
185189
],
186190
)
@@ -190,22 +194,25 @@ async def serve(
190194
agent_executor=SampleAgentExecutor(), task_store=task_store
191195
)
192196

193-
rest_app_builder = A2ARESTFastAPIApplication(
197+
rest_routes = create_rest_routes(
194198
agent_card=agent_card,
195-
http_handler=request_handler,
199+
request_handler=request_handler,
200+
path_prefix='/a2a/rest',
196201
enable_v0_3_compat=True,
197202
)
198-
rest_app = rest_app_builder.build()
199-
200-
jsonrpc_app_builder = A2AFastAPIApplication(
203+
jsonrpc_routes = create_jsonrpc_routes(
201204
agent_card=agent_card,
202-
http_handler=request_handler,
205+
request_handler=request_handler,
206+
rpc_url='/a2a/jsonrpc',
203207
enable_v0_3_compat=True,
204208
)
205-
209+
agent_card_routes = create_agent_card_routes(
210+
agent_card=agent_card,
211+
)
206212
app = FastAPI()
207-
jsonrpc_app_builder.add_routes_to_app(app, rpc_url='/a2a/jsonrpc/')
208-
app.mount('/a2a/rest', rest_app)
213+
app.routes.extend(jsonrpc_routes)
214+
app.routes.extend(agent_card_routes)
215+
app.routes.extend(rest_routes)
209216

210217
grpc_server = grpc.aio.server()
211218
grpc_server.add_insecure_port(f'{host}:{grpc_port}')

src/a2a/compat/v0_3/jsonrpc_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
if TYPE_CHECKING:
1111
from starlette.requests import Request
1212

13-
from a2a.server.apps.jsonrpc.jsonrpc_app import CallContextBuilder
1413
from a2a.server.request_handlers.request_handler import RequestHandler
14+
from a2a.server.routes import CallContextBuilder
1515
from a2a.types.a2a_pb2 import AgentCard
1616

1717
_package_starlette_installed = True

src/a2a/compat/v0_3/rest_adapter.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,8 @@
3333

3434
from a2a.compat.v0_3 import conversions
3535
from a2a.compat.v0_3.rest_handler import REST03Handler
36-
from a2a.server.apps.jsonrpc.jsonrpc_app import (
37-
CallContextBuilder,
38-
DefaultCallContextBuilder,
39-
)
40-
from a2a.server.apps.rest.rest_adapter import RESTAdapterInterface
4136
from a2a.server.context import ServerCallContext
37+
from a2a.server.routes import CallContextBuilder, DefaultCallContextBuilder
4238
from a2a.utils.error_handlers import (
4339
rest_error_handler,
4440
rest_stream_error_handler,
@@ -53,7 +49,7 @@
5349
logger = logging.getLogger(__name__)
5450

5551

56-
class REST03Adapter(RESTAdapterInterface):
52+
class REST03Adapter:
5753
"""Adapter to make RequestHandler work with v0.3 RESTful API.
5854
5955
Defines v0.3 REST request processors and their routes, as well as managing response generation including Server-Sent Events (SSE).

src/a2a/contrib/tasks/vertex_task_converter.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
try:
2+
from google.genai import types as genai_types
23
from vertexai import types as vertexai_types
34
except ImportError as e:
45
raise ImportError(
@@ -25,70 +26,70 @@
2526

2627

2728
_TO_SDK_TASK_STATE = {
28-
vertexai_types.State.STATE_UNSPECIFIED: TaskState.unknown,
29-
vertexai_types.State.SUBMITTED: TaskState.submitted,
30-
vertexai_types.State.WORKING: TaskState.working,
31-
vertexai_types.State.COMPLETED: TaskState.completed,
32-
vertexai_types.State.CANCELLED: TaskState.canceled,
33-
vertexai_types.State.FAILED: TaskState.failed,
34-
vertexai_types.State.REJECTED: TaskState.rejected,
35-
vertexai_types.State.INPUT_REQUIRED: TaskState.input_required,
36-
vertexai_types.State.AUTH_REQUIRED: TaskState.auth_required,
29+
vertexai_types.A2aTaskState.STATE_UNSPECIFIED: TaskState.unknown,
30+
vertexai_types.A2aTaskState.SUBMITTED: TaskState.submitted,
31+
vertexai_types.A2aTaskState.WORKING: TaskState.working,
32+
vertexai_types.A2aTaskState.COMPLETED: TaskState.completed,
33+
vertexai_types.A2aTaskState.CANCELLED: TaskState.canceled,
34+
vertexai_types.A2aTaskState.FAILED: TaskState.failed,
35+
vertexai_types.A2aTaskState.REJECTED: TaskState.rejected,
36+
vertexai_types.A2aTaskState.INPUT_REQUIRED: TaskState.input_required,
37+
vertexai_types.A2aTaskState.AUTH_REQUIRED: TaskState.auth_required,
3738
}
3839

3940
_SDK_TO_STORED_TASK_STATE = {v: k for k, v in _TO_SDK_TASK_STATE.items()}
4041

4142

42-
def to_sdk_task_state(stored_state: vertexai_types.State) -> TaskState:
43+
def to_sdk_task_state(stored_state: vertexai_types.A2aTaskState) -> TaskState:
4344
"""Converts a proto A2aTask.State to a TaskState enum."""
4445
return _TO_SDK_TASK_STATE.get(stored_state, TaskState.unknown)
4546

4647

47-
def to_stored_task_state(task_state: TaskState) -> vertexai_types.State:
48+
def to_stored_task_state(task_state: TaskState) -> vertexai_types.A2aTaskState:
4849
"""Converts a TaskState enum to a proto A2aTask.State enum value."""
4950
return _SDK_TO_STORED_TASK_STATE.get(
50-
task_state, vertexai_types.State.STATE_UNSPECIFIED
51+
task_state, vertexai_types.A2aTaskState.STATE_UNSPECIFIED
5152
)
5253

5354

54-
def to_stored_part(part: Part) -> vertexai_types.Part:
55+
def to_stored_part(part: Part) -> genai_types.Part:
5556
"""Converts a SDK Part to a proto Part."""
5657
if isinstance(part.root, TextPart):
57-
return vertexai_types.Part(text=part.root.text)
58+
return genai_types.Part(text=part.root.text)
5859
if isinstance(part.root, DataPart):
5960
data_bytes = json.dumps(part.root.data).encode('utf-8')
60-
return vertexai_types.Part(
61-
inline_data=vertexai_types.Blob(
61+
return genai_types.Part(
62+
inline_data=genai_types.Blob(
6263
mime_type='application/json', data=data_bytes
6364
)
6465
)
6566
if isinstance(part.root, FilePart):
6667
file_content = part.root.file
6768
if isinstance(file_content, FileWithBytes):
6869
decoded_bytes = base64.b64decode(file_content.bytes)
69-
return vertexai_types.Part(
70-
inline_data=vertexai_types.Blob(
70+
return genai_types.Part(
71+
inline_data=genai_types.Blob(
7172
mime_type=file_content.mime_type or '', data=decoded_bytes
7273
)
7374
)
7475
if isinstance(file_content, FileWithUri):
75-
return vertexai_types.Part(
76-
file_data=vertexai_types.FileData(
76+
return genai_types.Part(
77+
file_data=genai_types.FileData(
7778
mime_type=file_content.mime_type or '',
7879
file_uri=file_content.uri,
7980
)
8081
)
8182
raise ValueError(f'Unsupported part type: {type(part.root)}')
8283

8384

84-
def to_sdk_part(stored_part: vertexai_types.Part) -> Part:
85+
def to_sdk_part(stored_part: genai_types.Part) -> Part:
8586
"""Converts a proto Part to a SDK Part."""
8687
if stored_part.text:
8788
return Part(root=TextPart(text=stored_part.text))
8889
if stored_part.inline_data:
89-
encoded_bytes = base64.b64encode(stored_part.inline_data.data).decode(
90-
'utf-8'
91-
)
90+
encoded_bytes = base64.b64encode(
91+
stored_part.inline_data.data or b''
92+
).decode('utf-8')
9293
return Part(
9394
root=FilePart(
9495
file=FileWithBytes(
@@ -97,7 +98,7 @@ def to_sdk_part(stored_part: vertexai_types.Part) -> Part:
9798
)
9899
)
99100
)
100-
if stored_part.file_data:
101+
if stored_part.file_data and stored_part.file_data.file_uri:
101102
return Part(
102103
root=FilePart(
103104
file=FileWithUri(

src/a2a/server/apps/__init__.py

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/a2a/server/apps/jsonrpc/__init__.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)