Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/a2a/server/request_handlers/grpc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,14 @@ def build(self, context: grpc.aio.ServicerContext) -> ServerCallContext:
types.InvalidParamsError: grpc.StatusCode.INVALID_ARGUMENT,
types.InternalError: grpc.StatusCode.INTERNAL,
types.TaskNotFoundError: grpc.StatusCode.NOT_FOUND,
types.TaskNotCancelableError: grpc.StatusCode.UNIMPLEMENTED,
types.TaskNotCancelableError: grpc.StatusCode.FAILED_PRECONDITION,
Comment thread
ishymko marked this conversation as resolved.
types.PushNotificationNotSupportedError: grpc.StatusCode.UNIMPLEMENTED,
types.UnsupportedOperationError: grpc.StatusCode.UNIMPLEMENTED,
types.ContentTypeNotSupportedError: grpc.StatusCode.UNIMPLEMENTED,
types.ContentTypeNotSupportedError: grpc.StatusCode.INVALID_ARGUMENT,
types.InvalidAgentResponseError: grpc.StatusCode.INTERNAL,
types.AuthenticatedExtendedCardNotConfiguredError: grpc.StatusCode.FAILED_PRECONDITION,
types.ExtensionSupportRequiredError: grpc.StatusCode.FAILED_PRECONDITION,
types.VersionNotSupportedError: grpc.StatusCode.UNIMPLEMENTED,
}


Expand Down
4 changes: 4 additions & 0 deletions src/a2a/server/request_handlers/jsonrpc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
A2AError,
AuthenticatedExtendedCardNotConfiguredError,
ContentTypeNotSupportedError,
ExtensionSupportRequiredError,
InternalError,
InvalidAgentResponseError,
InvalidParamsError,
Comment thread
ishymko marked this conversation as resolved.
Expand All @@ -46,6 +47,7 @@
TaskNotCancelableError,
TaskNotFoundError,
UnsupportedOperationError,
VersionNotSupportedError,
)
from a2a.utils.helpers import maybe_await, validate
from a2a.utils.telemetry import SpanKind, trace_class
Expand All @@ -66,6 +68,8 @@
InvalidParamsError: JSONRPCError,
InvalidRequestError: JSONRPCError,
MethodNotFoundError: JSONRPCError,
ExtensionSupportRequiredError: JSONRPCError,
VersionNotSupportedError: JSONRPCError,
}


Expand Down
4 changes: 4 additions & 0 deletions src/a2a/server/request_handlers/response_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
A2AError,
AuthenticatedExtendedCardNotConfiguredError,
ContentTypeNotSupportedError,
ExtensionSupportRequiredError,
InternalError,
InvalidAgentResponseError,
InvalidParamsError,
Comment thread
ishymko marked this conversation as resolved.
Expand All @@ -40,6 +41,7 @@
TaskNotCancelableError,
TaskNotFoundError,
UnsupportedOperationError,
VersionNotSupportedError,
)


Expand All @@ -55,6 +57,8 @@
InvalidRequestError: JSONRPCError,
MethodNotFoundError: JSONRPCError,
InternalError: JSONRPCInternalError,
ExtensionSupportRequiredError: JSONRPCError,
VersionNotSupportedError: JSONRPCError,
}


Expand Down
4 changes: 4 additions & 0 deletions src/a2a/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from a2a.utils.errors import (
AuthenticatedExtendedCardNotConfiguredError,
ContentTypeNotSupportedError,
ExtensionSupportRequiredError,
InternalError,
InvalidAgentResponseError,
InvalidParamsError,
Expand All @@ -63,6 +64,7 @@
TaskNotCancelableError,
TaskNotFoundError,
UnsupportedOperationError,
VersionNotSupportedError,
)


Expand Down Expand Up @@ -99,6 +101,7 @@
'ContentTypeNotSupportedError',
'DeleteTaskPushNotificationConfigRequest',
'DeviceCodeOAuthFlow',
'ExtensionSupportRequiredError',
'GetExtendedAgentCardRequest',
'GetTaskPushNotificationConfigRequest',
'GetTaskRequest',
Expand Down Expand Up @@ -139,4 +142,5 @@
'TaskStatus',
'TaskStatusUpdateEvent',
'UnsupportedOperationError',
'VersionNotSupportedError',
]
4 changes: 4 additions & 0 deletions src/a2a/utils/error_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
A2AError,
AuthenticatedExtendedCardNotConfiguredError,
ContentTypeNotSupportedError,
ExtensionSupportRequiredError,
InternalError,
InvalidAgentResponseError,
InvalidParamsError,
Expand All @@ -37,6 +38,7 @@
TaskNotCancelableError,
TaskNotFoundError,
UnsupportedOperationError,
VersionNotSupportedError,
)


Expand Down Expand Up @@ -74,6 +76,8 @@
ContentTypeNotSupportedError: 415,
InvalidAgentResponseError: 502,
AuthenticatedExtendedCardNotConfiguredError: 404,
ExtensionSupportRequiredError: 400,
VersionNotSupportedError: 400,
}


Expand Down
2 changes: 2 additions & 0 deletions src/a2a/utils/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ class VersionNotSupportedError(A2AError):
ContentTypeNotSupportedError: -32005,
InvalidAgentResponseError: -32006,
AuthenticatedExtendedCardNotConfiguredError: -32007,
ExtensionSupportRequiredError: -32008,
VersionNotSupportedError: -32009,
InvalidParamsError: -32602,
InvalidRequestError: -32600,
MethodNotFoundError: -32601,
Expand Down
56 changes: 55 additions & 1 deletion tests/integration/test_client_server_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,24 @@
TaskStatus,
TaskStatusUpdateEvent,
)
from a2a.utils.constants import TransportProtocol
from a2a.utils.constants import (
TransportProtocol,
)
from a2a.utils.errors import (
AuthenticatedExtendedCardNotConfiguredError,
ContentTypeNotSupportedError,
ExtensionSupportRequiredError,
InternalError,
InvalidAgentResponseError,
InvalidParamsError,
InvalidRequestError,
MethodNotFoundError,
PushNotificationNotSupportedError,
TaskNotCancelableError,
TaskNotFoundError,
UnsupportedOperationError,
VersionNotSupportedError,
)
from a2a.utils.signing import (
create_agent_card_signer,
create_signature_verifier,
Expand Down Expand Up @@ -788,6 +805,43 @@ async def test_client_get_signed_base_and_extended_cards(
await client.close()


@pytest.mark.asyncio
@pytest.mark.parametrize(
'error_cls',
[
TaskNotFoundError,
TaskNotCancelableError,
PushNotificationNotSupportedError,
UnsupportedOperationError,
ContentTypeNotSupportedError,
InvalidAgentResponseError,
AuthenticatedExtendedCardNotConfiguredError,
ExtensionSupportRequiredError,
VersionNotSupportedError,
],
)
async def test_client_handles_a2a_errors(transport_setups, error_cls) -> None:
"""Integration test to verify error propagation from handler to client."""
client = transport_setups.client
handler = transport_setups.handler

# Mock the handler to raise the error
handler.on_get_task.side_effect = error_cls('Test error message')

params = GetTaskRequest(id='some-id')

# We expect the client to raise the same error_cls.
with pytest.raises(error_cls) as exc_info:
await client.get_task(request=params)

assert 'Test error message' in str(exc_info.value)

# Reset side_effect for other tests
handler.on_get_task.side_effect = None

await client.close()


@pytest.mark.asyncio
@pytest.mark.parametrize(
'request_kwargs, expected_error_code',
Expand Down
23 changes: 2 additions & 21 deletions tests/server/request_handlers/test_grpc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,6 @@ async def test_get_task_not_found(
)


@pytest.mark.asyncio
async def test_cancel_task_server_error(
grpc_handler: GrpcHandler,
mock_request_handler: AsyncMock,
mock_grpc_context: AsyncMock,
) -> None:
"""Test CancelTask call when handler raises A2AError."""
request_proto = a2a_pb2.CancelTaskRequest(id='task-1')
error = types.TaskNotCancelableError()
mock_request_handler.on_cancel_task.side_effect = error

await grpc_handler.CancelTask(request_proto, mock_grpc_context)

mock_grpc_context.abort.assert_awaited_once_with(
grpc.StatusCode.UNIMPLEMENTED,
'Task cannot be canceled',
)


@pytest.mark.asyncio
async def test_send_streaming_message(
grpc_handler: GrpcHandler,
Expand Down Expand Up @@ -340,7 +321,7 @@ async def test_list_tasks_success(
),
(
types.TaskNotCancelableError(),
grpc.StatusCode.UNIMPLEMENTED,
grpc.StatusCode.FAILED_PRECONDITION,
'TaskNotCancelableError',
),
(
Expand All @@ -355,7 +336,7 @@ async def test_list_tasks_success(
),
(
types.ContentTypeNotSupportedError(),
grpc.StatusCode.UNIMPLEMENTED,
grpc.StatusCode.INVALID_ARGUMENT,
'ContentTypeNotSupportedError',
),
(
Expand Down
Loading