From 9b2f5f38128a43180cb707b42bc726b2bf882fff Mon Sep 17 00:00:00 2001 From: Ivan Shymko Date: Mon, 2 Mar 2026 10:29:32 +0000 Subject: [PATCH] refactor!(client): rename "callback" -> "push_notification_config" Currently client uses `callback` terminology for push notifications which doesn't match data model names coming from proto. In addition having `get_task` and `get_task_callback` side by side may give an impression that `get_task_callback` is some sort of an extension point for `get_task` rather than a completely different method. Re #702. --- src/a2a/client/base_client.py | 16 ++++----- src/a2a/client/client.py | 10 +++--- src/a2a/client/transports/base.py | 8 ++--- src/a2a/client/transports/grpc.py | 8 ++--- src/a2a/client/transports/jsonrpc.py | 8 ++--- src/a2a/client/transports/rest.py | 8 ++--- tests/client/transports/test_grpc_client.py | 28 ++++++++------- .../client/transports/test_jsonrpc_client.py | 12 +++---- tests/client/transports/test_rest_client.py | 8 ++--- .../test_default_push_notification_support.py | 2 +- .../test_client_server_integration.py | 36 ++++++++++--------- 11 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/a2a/client/base_client.py b/src/a2a/client/base_client.py index 5654f1fa4..76d6b1902 100644 --- a/src/a2a/client/base_client.py +++ b/src/a2a/client/base_client.py @@ -208,7 +208,7 @@ async def cancel_task( request, context=context, extensions=extensions ) - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -225,11 +225,11 @@ async def set_task_callback( Returns: The created or updated `TaskPushNotificationConfig` object. """ - return await self._transport.set_task_callback( + return await self._transport.create_task_push_notification_config( request, context=context, extensions=extensions ) - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -246,11 +246,11 @@ async def get_task_callback( Returns: A `TaskPushNotificationConfig` object containing the configuration. """ - return await self._transport.get_task_callback( + return await self._transport.get_task_push_notification_config( request, context=context, extensions=extensions ) - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -267,11 +267,11 @@ async def list_task_callback( Returns: A `ListTaskPushNotificationConfigsResponse` object. """ - return await self._transport.list_task_callback( + return await self._transport.list_task_push_notification_configs( request, context=context, extensions=extensions ) - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, @@ -285,7 +285,7 @@ async def delete_task_callback( context: The client call context. extensions: List of extensions to be activated. """ - await self._transport.delete_task_callback( + await self._transport.delete_task_push_notification_config( request, context=context, extensions=extensions ) diff --git a/src/a2a/client/client.py b/src/a2a/client/client.py index 004479315..c9063f4ed 100644 --- a/src/a2a/client/client.py +++ b/src/a2a/client/client.py @@ -71,7 +71,7 @@ class ClientConfig: push_notification_configs: list[PushNotificationConfig] = dataclasses.field( default_factory=list ) - """Push notification callbacks to use for every request.""" + """Push notification configurations to use for every request.""" extensions: list[str] = dataclasses.field(default_factory=list) """A list of extension URIs the client supports.""" @@ -161,7 +161,7 @@ async def cancel_task( """Requests the agent to cancel a specific task.""" @abstractmethod - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -171,7 +171,7 @@ async def set_task_callback( """Sets or updates the push notification configuration for a specific task.""" @abstractmethod - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -181,7 +181,7 @@ async def get_task_callback( """Retrieves the push notification configuration for a specific task.""" @abstractmethod - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -191,7 +191,7 @@ async def list_task_callback( """Lists push notification configurations for a specific task.""" @abstractmethod - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, diff --git a/src/a2a/client/transports/base.py b/src/a2a/client/transports/base.py index f578ba3e3..2d2c29873 100644 --- a/src/a2a/client/transports/base.py +++ b/src/a2a/client/transports/base.py @@ -94,7 +94,7 @@ async def cancel_task( """Requests the agent to cancel a specific task.""" @abstractmethod - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -104,7 +104,7 @@ async def set_task_callback( """Sets or updates the push notification configuration for a specific task.""" @abstractmethod - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -114,7 +114,7 @@ async def get_task_callback( """Retrieves the push notification configuration for a specific task.""" @abstractmethod - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -124,7 +124,7 @@ async def list_task_callback( """Lists push notification configurations for a specific task.""" @abstractmethod - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, diff --git a/src/a2a/client/transports/grpc.py b/src/a2a/client/transports/grpc.py index eb201ae96..97df8f724 100644 --- a/src/a2a/client/transports/grpc.py +++ b/src/a2a/client/transports/grpc.py @@ -175,7 +175,7 @@ async def cancel_task( metadata=self._get_grpc_metadata(extensions), ) - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -188,7 +188,7 @@ async def set_task_callback( metadata=self._get_grpc_metadata(extensions), ) - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -201,7 +201,7 @@ async def get_task_callback( metadata=self._get_grpc_metadata(extensions), ) - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -214,7 +214,7 @@ async def list_task_callback( metadata=self._get_grpc_metadata(extensions), ) - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, diff --git a/src/a2a/client/transports/jsonrpc.py b/src/a2a/client/transports/jsonrpc.py index 6ee5dd79a..02fef4047 100644 --- a/src/a2a/client/transports/jsonrpc.py +++ b/src/a2a/client/transports/jsonrpc.py @@ -303,7 +303,7 @@ async def cancel_task( response: Task = json_format.ParseDict(json_rpc_response.result, Task()) return response - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -335,7 +335,7 @@ async def set_task_callback( ) return response - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -367,7 +367,7 @@ async def get_task_callback( ) return response - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -402,7 +402,7 @@ async def list_task_callback( ) return response - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, diff --git a/src/a2a/client/transports/rest.py b/src/a2a/client/transports/rest.py index 3699f9feb..ddbf0208b 100644 --- a/src/a2a/client/transports/rest.py +++ b/src/a2a/client/transports/rest.py @@ -298,7 +298,7 @@ async def cancel_task( response: Task = ParseDict(response_data, Task()) return response - async def set_task_callback( + async def create_task_push_notification_config( self, request: CreateTaskPushNotificationConfigRequest, *, @@ -324,7 +324,7 @@ async def set_task_callback( ) return response - async def get_task_callback( + async def get_task_push_notification_config( self, request: GetTaskPushNotificationConfigRequest, *, @@ -356,7 +356,7 @@ async def get_task_callback( ) return response - async def list_task_callback( + async def list_task_push_notification_configs( self, request: ListTaskPushNotificationConfigsRequest, *, @@ -386,7 +386,7 @@ async def list_task_callback( ) return response - async def delete_task_callback( + async def delete_task_push_notification_config( self, request: DeleteTaskPushNotificationConfigRequest, *, diff --git a/tests/client/transports/test_grpc_client.py b/tests/client/transports/test_grpc_client.py index a4a85a202..a1faa7125 100644 --- a/tests/client/transports/test_grpc_client.py +++ b/tests/client/transports/test_grpc_client.py @@ -418,7 +418,7 @@ async def test_cancel_task( @pytest.mark.asyncio -async def test_set_task_callback_with_valid_task( +async def test_create_task_push_notification_config_with_valid_task( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_task_push_notification_config: TaskPushNotificationConfig, @@ -433,7 +433,9 @@ async def test_set_task_callback_with_valid_task( task_id='task-1', config=sample_task_push_notification_config.push_notification_config, ) - response = await grpc_transport.set_task_callback(request) + response = await grpc_transport.create_task_push_notification_config( + request + ) mock_grpc_stub.CreateTaskPushNotificationConfig.assert_awaited_once_with( request, @@ -448,7 +450,7 @@ async def test_set_task_callback_with_valid_task( @pytest.mark.asyncio -async def test_set_task_callback_with_invalid_task( +async def test_create_task_push_notification_config_with_invalid_task( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_push_notification_config: PushNotificationConfig, @@ -469,12 +471,14 @@ async def test_set_task_callback_with_invalid_task( # Note: The transport doesn't validate the response name format # It just returns the response from the stub - response = await grpc_transport.set_task_callback(request) + response = await grpc_transport.create_task_push_notification_config( + request + ) assert response.task_id == 'invalid-path-to-task-1' @pytest.mark.asyncio -async def test_get_task_callback_with_valid_task( +async def test_get_task_push_notification_config_with_valid_task( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_task_push_notification_config: TaskPushNotificationConfig, @@ -485,7 +489,7 @@ async def test_get_task_callback_with_valid_task( ) config_id = sample_task_push_notification_config.push_notification_config.id - response = await grpc_transport.get_task_callback( + response = await grpc_transport.get_task_push_notification_config( GetTaskPushNotificationConfigRequest( task_id='task-1', id=config_id, @@ -508,7 +512,7 @@ async def test_get_task_callback_with_valid_task( @pytest.mark.asyncio -async def test_get_task_callback_with_invalid_task( +async def test_get_task_push_notification_config_with_invalid_task( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_push_notification_config: PushNotificationConfig, @@ -521,7 +525,7 @@ async def test_get_task_callback_with_invalid_task( ) ) - response = await grpc_transport.get_task_callback( + response = await grpc_transport.get_task_push_notification_config( GetTaskPushNotificationConfigRequest( task_id='task-1', id='config-1', @@ -532,7 +536,7 @@ async def test_get_task_callback_with_invalid_task( @pytest.mark.asyncio -async def test_list_task_callback( +async def test_list_task_push_notification_configs( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_task_push_notification_config: TaskPushNotificationConfig, @@ -544,7 +548,7 @@ async def test_list_task_callback( ) ) - response = await grpc_transport.list_task_callback( + response = await grpc_transport.list_task_push_notification_configs( ListTaskPushNotificationConfigsRequest(task_id='task-1') ) @@ -562,7 +566,7 @@ async def test_list_task_callback( @pytest.mark.asyncio -async def test_delete_task_callback( +async def test_delete_task_push_notification_config( grpc_transport: GrpcTransport, mock_grpc_stub: AsyncMock, sample_task_push_notification_config: TaskPushNotificationConfig, @@ -570,7 +574,7 @@ async def test_delete_task_callback( """Test deleting task push notification config.""" mock_grpc_stub.DeleteTaskPushNotificationConfig.return_value = None - await grpc_transport.delete_task_callback( + await grpc_transport.delete_task_push_notification_config( DeleteTaskPushNotificationConfigRequest( task_id='task-1', id='config-1', diff --git a/tests/client/transports/test_jsonrpc_client.py b/tests/client/transports/test_jsonrpc_client.py index e2f64f7e7..b29697995 100644 --- a/tests/client/transports/test_jsonrpc_client.py +++ b/tests/client/transports/test_jsonrpc_client.py @@ -330,7 +330,7 @@ class TestTaskCallback: """Tests for the task callback methods.""" @pytest.mark.asyncio - async def test_get_task_callback_success( + async def test_get_task_push_notification_config_success( self, transport, mock_httpx_client ): """Test successful task callback retrieval.""" @@ -350,7 +350,7 @@ async def test_get_task_callback_success( task_id=f'{task_id}', id='config-1', ) - response = await transport.get_task_callback(request) + response = await transport.get_task_push_notification_config(request) assert isinstance(response, TaskPushNotificationConfig) call_args = mock_httpx_client.post.call_args @@ -358,7 +358,7 @@ async def test_get_task_callback_success( assert payload['method'] == 'GetTaskPushNotificationConfig' @pytest.mark.asyncio - async def test_list_task_callback_success( + async def test_list_task_push_notification_configs_success( self, transport, mock_httpx_client ): """Test successful task multiple callbacks retrieval.""" @@ -385,7 +385,7 @@ async def test_list_task_callback_success( request = ListTaskPushNotificationConfigsRequest( task_id=f'{task_id}', ) - response = await transport.list_task_callback(request) + response = await transport.list_task_push_notification_configs(request) assert len(response.configs) == 1 assert response.configs[0].task_id == task_id @@ -394,7 +394,7 @@ async def test_list_task_callback_success( assert payload['method'] == 'ListTaskPushNotificationConfigs' @pytest.mark.asyncio - async def test_delete_task_callback_success( + async def test_delete_task_push_notification_config_success( self, transport, mock_httpx_client ): """Test successful task callback deletion.""" @@ -414,7 +414,7 @@ async def test_delete_task_callback_success( task_id=f'{task_id}', id='config-1', ) - response = await transport.delete_task_callback(request) + response = await transport.delete_task_push_notification_config(request) mock_httpx_client.post.assert_called_once() assert response is None diff --git a/tests/client/transports/test_rest_client.py b/tests/client/transports/test_rest_client.py index 663d13284..768bebc8f 100644 --- a/tests/client/transports/test_rest_client.py +++ b/tests/client/transports/test_rest_client.py @@ -283,7 +283,7 @@ class TestTaskCallback: """Tests for the task callback methods.""" @pytest.mark.asyncio - async def test_list_task_callback_success( + async def test_list_task_push_notification_configs_success( self, mock_httpx_client: AsyncMock, mock_agent_card: MagicMock ): """Test successful task multiple callbacks retrieval.""" @@ -317,7 +317,7 @@ async def test_list_task_callback_success( request = ListTaskPushNotificationConfigsRequest( task_id=task_id, ) - response = await client.list_task_callback(request) + response = await client.list_task_push_notification_configs(request) assert len(response.configs) == 1 assert response.configs[0].task_id == task_id @@ -328,7 +328,7 @@ async def test_list_task_callback_success( assert f'/v1/tasks/{task_id}/pushNotificationConfigs' in call_args[0][1] @pytest.mark.asyncio - async def test_delete_task_callback_success( + async def test_delete_task_push_notification_config_success( self, mock_httpx_client: AsyncMock, mock_agent_card: MagicMock ): """Test successful task callback deletion.""" @@ -353,7 +353,7 @@ async def test_delete_task_callback_success( task_id=task_id, id='config-1', ) - await client.delete_task_callback(request) + await client.delete_task_push_notification_config(request) mock_build_request.assert_called_once() call_args = mock_build_request.call_args diff --git a/tests/e2e/push_notifications/test_default_push_notification_support.py b/tests/e2e/push_notifications/test_default_push_notification_support.py index 47469417c..a7247b064 100644 --- a/tests/e2e/push_notifications/test_default_push_notification_support.py +++ b/tests/e2e/push_notifications/test_default_push_notification_support.py @@ -199,7 +199,7 @@ async def test_notification_triggering_after_config_change_e2e( # Set the push notification config. token = uuid.uuid4().hex - await a2a_client.set_task_callback( + await a2a_client.create_task_push_notification_config( CreateTaskPushNotificationConfigRequest( task_id=f'{task.id}', config=PushNotificationConfig( diff --git a/tests/integration/test_client_server_integration.py b/tests/integration/test_client_server_integration.py index 8284f1d07..90c23ef05 100644 --- a/tests/integration/test_client_server_integration.py +++ b/tests/integration/test_client_server_integration.py @@ -583,7 +583,7 @@ def channel_factory(address: str) -> Channel: pytest.param('rest_setup', id='REST'), ], ) -async def test_http_transport_set_task_callback( +async def test_http_transport_create_task_push_notification_config( transport_setup_fixture: str, request ) -> None: transport_setup: TransportSetup = request.getfixturevalue( @@ -597,7 +597,9 @@ async def test_http_transport_set_task_callback( task_id='task-callback-123', config=CALLBACK_CONFIG.push_notification_config, ) - result = await transport.set_task_callback(request=params) + result = await transport.create_task_push_notification_config( + request=params + ) # TaskPushNotificationConfig has 'push_notification_config' assert ( @@ -619,7 +621,7 @@ async def test_http_transport_set_task_callback( @pytest.mark.asyncio -async def test_grpc_transport_set_task_callback( +async def test_grpc_transport_create_task_push_notification_config( grpc_server_and_handler: tuple[str, AsyncMock], agent_card: AgentCard, ) -> None: @@ -636,7 +638,9 @@ def channel_factory(address: str) -> Channel: task_id='task-callback-123', config=CALLBACK_CONFIG.push_notification_config, ) - result = await transport.set_task_callback(request=params) + result = await transport.create_task_push_notification_config( + request=params + ) # TaskPushNotificationConfig has 'push_notification_config' assert ( @@ -664,7 +668,7 @@ def channel_factory(address: str) -> Channel: pytest.param('rest_setup', id='REST'), ], ) -async def test_http_transport_get_task_callback( +async def test_http_transport_get_task_push_notification_config( transport_setup_fixture: str, request ) -> None: transport_setup: TransportSetup = request.getfixturevalue( @@ -678,7 +682,7 @@ async def test_http_transport_get_task_callback( task_id=f'{CALLBACK_CONFIG.task_id}', id=CALLBACK_CONFIG.push_notification_config.id, ) - result = await transport.get_task_callback(request=params) + result = await transport.get_task_push_notification_config(request=params) # TaskPushNotificationConfig has 'name' and 'push_notification_config' assert result.task_id == CALLBACK_CONFIG.task_id @@ -697,7 +701,7 @@ async def test_http_transport_get_task_callback( @pytest.mark.asyncio -async def test_grpc_transport_get_task_callback( +async def test_grpc_transport_get_task_push_notification_config( grpc_server_and_handler: tuple[str, AsyncMock], agent_card: AgentCard, ) -> None: @@ -714,7 +718,7 @@ def channel_factory(address: str) -> Channel: task_id=f'{CALLBACK_CONFIG.task_id}', id=CALLBACK_CONFIG.push_notification_config.id, ) - result = await transport.get_task_callback(request=params) + result = await transport.get_task_push_notification_config(request=params) # TaskPushNotificationConfig has 'name' and 'push_notification_config' assert result.task_id == CALLBACK_CONFIG.task_id @@ -739,7 +743,7 @@ def channel_factory(address: str) -> Channel: pytest.param('rest_setup', id='REST'), ], ) -async def test_http_transport_list_task_callback( +async def test_http_transport_list_task_push_notification_configs( transport_setup_fixture: str, request ) -> None: transport_setup: TransportSetup = request.getfixturevalue( @@ -751,7 +755,7 @@ async def test_http_transport_list_task_callback( params = ListTaskPushNotificationConfigsRequest( task_id=f'{CALLBACK_CONFIG.task_id}', ) - result = await transport.list_task_callback(request=params) + result = await transport.list_task_push_notification_configs(request=params) assert len(result.configs) == 1 assert result.configs[0].task_id == CALLBACK_CONFIG.task_id @@ -762,7 +766,7 @@ async def test_http_transport_list_task_callback( @pytest.mark.asyncio -async def test_grpc_transport_list_task_callback( +async def test_grpc_transport_list_task_push_notification_configs( grpc_server_and_handler: tuple[str, AsyncMock], agent_card: AgentCard, ) -> None: @@ -777,7 +781,7 @@ def channel_factory(address: str) -> Channel: params = ListTaskPushNotificationConfigsRequest( task_id=f'{CALLBACK_CONFIG.task_id}', ) - result = await transport.list_task_callback(request=params) + result = await transport.list_task_push_notification_configs(request=params) assert len(result.configs) == 1 assert result.configs[0].task_id == CALLBACK_CONFIG.task_id @@ -794,7 +798,7 @@ def channel_factory(address: str) -> Channel: pytest.param('rest_setup', id='REST'), ], ) -async def test_http_transport_delete_task_callback( +async def test_http_transport_delete_task_push_notification_config( transport_setup_fixture: str, request ) -> None: transport_setup: TransportSetup = request.getfixturevalue( @@ -807,7 +811,7 @@ async def test_http_transport_delete_task_callback( task_id=f'{CALLBACK_CONFIG.task_id}', id=CALLBACK_CONFIG.push_notification_config.id, ) - await transport.delete_task_callback(request=params) + await transport.delete_task_push_notification_config(request=params) handler.on_delete_task_push_notification_config.assert_awaited_once() @@ -816,7 +820,7 @@ async def test_http_transport_delete_task_callback( @pytest.mark.asyncio -async def test_grpc_transport_delete_task_callback( +async def test_grpc_transport_delete_task_push_notification_config( grpc_server_and_handler: tuple[str, AsyncMock], agent_card: AgentCard, ) -> None: @@ -832,7 +836,7 @@ def channel_factory(address: str) -> Channel: task_id=f'{CALLBACK_CONFIG.task_id}', id=CALLBACK_CONFIG.push_notification_config.id, ) - await transport.delete_task_callback(request=params) + await transport.delete_task_push_notification_config(request=params) handler.on_delete_task_push_notification_config.assert_awaited_once()