fix: handle REST query params as per 1.0 spec#804
Conversation
5ad30e8 to
e685af9
Compare
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the handling of REST query parameters across both the client and server components to align with the 1.0 specification. By introducing a centralized and robust parsing utility, it ensures consistent interpretation of request parameters, including proper serialization of field names, boolean values, and repeated fields. The changes also streamline the client's request preparation and enhance the server's ability to process incoming REST calls correctly. Furthermore, the refactoring of integration tests provides more comprehensive validation of these changes across all supported transport layers. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a centralized parse_params utility function to improve REST query parameter handling according to the A2A specification, ensuring robust and spec-compliant parsing for boolean conversions, timestamps, and repeated fields. The RESTHandler has been refactored to use this new logic, and the test suite has been significantly improved.
I am having trouble creating individual review comments. Click here to see my feedback.
src/a2a/utils/proto_utils.py (148-191)
The parse_params function is a critical and well-implemented addition. It correctly handles A2A-specific pre-processing for booleans and robustly supports repeated fields, including both multiple parameter keys and comma-separated values. This significantly improves the flexibility and correctness of REST query parameter parsing according to the specification. The inline comments clearly explain the logic.
tests/utils/test_proto_utils.py (185-241)
The TestRestParams class provides excellent unit test coverage for the new proto_utils.parse_params function. The test_rest_params_roundtrip comprehensively validates the parsing of various data types and camelCase conversion, while test_repeated_fields_parsing specifically targets the complex logic for handling repeated fields in different formats. This ensures the robustness and correctness of the core parsing utility.
tests/integration/test_client_server_integration.py (338-359)
The updated test_transport_list_tasks is much more comprehensive. It now includes a Timestamp and a wider range of ListTasksRequest parameters, providing better coverage for the new query parameter parsing logic across all transports. This is a significant improvement in test quality.
tests/integration/test_client_server_integration.py (233-254)
The introduction of the grpc_setup fixture and its inclusion in the transport_setups parametrized fixture is a significant improvement. This allows for comprehensive testing of gRPC transport alongside JSON-RPC and REST, greatly expanding test coverage and reducing test code duplication.
tests/client/transports/test_rest_client.py (179-218)
The test_url_serialization test is an excellent addition. It thoroughly verifies that MessageToDict correctly serializes various protobuf field types (enum, boolean, timestamp) into REST query parameters as per the A2A specification. Crucially, it also confirms that the tenant field is correctly excluded from the query parameters, which is vital for proper URL construction.
tests/integration/test_client_server_integration.py (220-222)
Passing extended_agent_card=agent_card to A2ARESTFastAPIApplication ensures that the REST server is correctly configured to serve the extended agent card during integration tests, which is important for comprehensive testing of this feature.
tests/integration/test_client_server_integration.py (279-282)
Refactoring test_http_transport_sends_message_streaming into a generic test_transport_sends_message_streaming that uses the transport_setups fixture is an excellent example of reducing test duplication and improving maintainability. This single test now covers all supported transports.
src/a2a/server/request_handlers/rest_handler.py (40)
Excluding _parse_params from tracing is a sensible optimization. Internal helper methods that are frequently called and don't represent significant logical units often don't require their own spans, reducing telemetry overhead.
src/a2a/utils/proto_utils.py (20-32)
The conditional import of QueryParams using TYPE_CHECKING and a try-except block is an excellent pattern for handling optional dependencies. It ensures type hints are available during development without forcing a runtime dependency if starlette is not installed, improving flexibility and reducing potential import errors.
src/a2a/utils/proto_utils.py (22-23)
Importing ParseDict and ProtobufMessage directly into proto_utils.py is appropriate, as these are now core components used by the new parse_params function. This centralizes protobuf-related imports where they are most directly used.
src/a2a/server/request_handlers/rest_handler.py (10)
Removing ParseDict from the imports is a good cleanup, as its functionality is now encapsulated within the new proto_utils.parse_params function, centralizing the parsing logic.
tests/client/transports/test_rest_client.py (8)
Adding the Timestamp import is necessary for the new test_url_serialization test, which verifies the correct serialization of timestamp fields in query parameters.
tests/client/transports/test_rest_client.py (29)
Importing TaskState is required for the new test_url_serialization test, which uses TaskState.TASK_STATE_WORKING as a parameter.
src/a2a/client/transports/rest.py (246-249)
Consistent application of camelCase for taskId and removal of tenant from query parameters for delete_task_push_notification_config is a good practice for maintaining a clean and consistent REST interface.
tests/client/transports/test_rest_client.py (661)
Changing the f-string to a regular string for the assertion is a minor stylistic change. While functionally equivalent in this case, it can sometimes improve readability when no variables are actually being interpolated.
tests/integration/test_client_server_integration.py (11)
The import of Timestamp is essential for the expanded test_transport_list_tasks test, allowing it to include timestamp-based filtering in the request parameters.
tests/integration/test_client_server_integration.py (34)
Removing A2ACardResolver is a good cleanup, indicating that the functionality it provided is either no longer needed in this specific test file or has been refactored elsewhere.
tests/integration/test_client_server_integration.py (59)
Removing the asymmetric import is a good cleanup, suggesting that the specific asymmetric cryptography primitives are no longer directly used in this file.
tests/integration/test_client_server_integration.py (163-164)
Enabling extended_agent_card=True in the AgentCapabilities for the agent_card fixture is a necessary change to properly test the extended agent card functionality across all transports.
tests/integration/test_client_server_integration.py (184)
Updating the type hint for handler to RequestHandler | AsyncMock is a good improvement for type accuracy. It correctly reflects that the handler can be either a concrete RequestHandler instance or a mock object in the test setup.
src/a2a/client/transports/rest.py (112-113)
The addition of del params['tenant'] is a good change. It ensures that the tenant ID, which is already part of the URL path, is not inadvertently included as a query parameter, maintaining clean and correct REST API calls.
src/a2a/client/transports/rest.py (219-222)
Similar to get_task_push_notification_config, updating the parameter name from task_id to taskId and removing tenant ensures adherence to REST API conventions and prevents redundant query parameters.
src/a2a/server/request_handlers/rest_handler.py (29)
Removing GetTaskRequest from the imports is appropriate since the on_get_task method now instantiates it directly from a2a_pb2, which is already imported.
tests/integration/test_client_server_integration.py (295-297)
Simplifying the assertions and using assert_called_once_with(params, ANY) makes the test more robust to minor changes in the context object while still verifying that the correct parameters are passed to the handler. This is a good practice for integration tests.
tests/integration/test_client_server_integration.py (303-306)
Consolidating test_http_transport_sends_message_blocking into a generic test_transport_sends_message_blocking using the parametrized transport_setups fixture is a great improvement for test efficiency and readability.
tests/integration/test_client_server_integration.py (317-318)
Similar to the streaming test, using assert_awaited_once_with(params, ANY) for blocking calls improves the test's resilience to minor context variations while ensuring the core parameters are correct.
tests/integration/test_client_server_integration.py (324-333)
This refactoring of test_transport_get_task to use the transport_setups fixture is a good example of reducing test boilerplate and making the test suite more concise and maintainable.
src/a2a/client/transports/rest.py (194-197)
Changing task_id to taskId in the del params logic is important for consistency with REST API conventions, which typically use camelCase for query parameters. The addition of del params['tenant'] is also correct for the same reasons.
tests/integration/test_client_server_integration.py (364-373)
Refactoring test_transport_cancel_task to use the transport_setups fixture streamlines the test and ensures consistent coverage across all transports.
tests/integration/test_client_server_integration.py (378-394)
Consolidating the create_task_push_notification_config tests into a single parametrized function improves test efficiency and readability.
tests/integration/test_client_server_integration.py (398-415)
The refactored test_transport_get_task_push_notification_config test is more concise and effectively tests the functionality across all transports using the transport_setups fixture.
tests/integration/test_client_server_integration.py (419-435)
This refactoring of test_transport_list_task_push_notification_configs significantly reduces test code duplication while maintaining full coverage across all transports.
tests/integration/test_client_server_integration.py (439-455)
Consolidating the delete_task_push_notification_config tests into a single parametrized function improves test efficiency and readability.
tests/integration/test_client_server_integration.py (459-470)
The refactored test_transport_subscribe test is more concise and effectively tests the functionality across all transports using the transport_setups fixture.
tests/integration/test_client_server_integration.py (474-479)
This refactoring of test_transport_get_card significantly reduces test code duplication while maintaining full coverage across all transports.
tests/integration/test_client_server_integration.py (483-496)
The refactored test_transport_get_extended_agent_card test is more concise and effectively tests the functionality across all transports using the transport_setups fixture. The updated assertion result.name in [agent_card.name, 'Extended Agent Card'] is also more flexible for different mock setups.
tests/utils/test_proto_utils.py (6-10)
Adding imports for httpx, MessageToDict, Parse, ProtobufMessage, and Timestamp is necessary to support the new TestRestParams class and its comprehensive unit tests for query parameter parsing.
tests/utils/test_proto_utils.py (13-15)
Importing AgentCard, AgentSkill, and ListTasksRequest is crucial for setting up the protobuf messages used in the new TestRestParams unit tests, ensuring that the parse_params function is tested with relevant message types.
tests/utils/test_proto_utils.py (26)
The import of QueryParams is essential for constructing the input to the proto_utils.parse_params function in the unit tests, allowing for direct testing of the new parsing logic.
src/a2a/client/transports/rest.py (132-134)
This refactoring correctly applies the logic of removing the tenant parameter from the query parameters for list_tasks, aligning it with the get_task method. This ensures consistency in how path parameters are handled across different REST endpoints.
e685af9 to
8ab9691
Compare
🤖 I have created a release *beep* *boop* --- ### ⚠ BREAKING CHANGES * **spec**: upgrade SDK to A2A 1.0 spec and use proto-based types ([#572](#572), [#665](#665), [#804](#804), [#765](#765)) * **client:** introduce ServiceParameters for extensions and include it in ClientCallContext ([#784](#784)) * **client:** rename "callback" -> "push_notification_config" ([#749](#749)) * **client:** transport agnostic interceptors ([#796](#796)) ([a910cbc](a910cbc)) * add `protocol_version` column to Task and PushNotificationConfig models and create a migration ([#789](#789)) ([2e2d431](2e2d431)) * **server:** implement `Resource Scoping` for tasks and push notifications ([#709](#709)) ([f0d4669](f0d4669)) ### Features * add GetExtendedAgentCardRequest as input parameter to GetExtendedAgentCard method ([#767](#767)) ([13a092f](13a092f)) * add validation for the JSON-RPC version ([#808](#808)) ([6eb7e41](6eb7e41)) * **client:** expose close() and async context manager support on abstract Client ([#719](#719)) ([e25ba7b](e25ba7b)) * **compat:** AgentCard backward compatibility helpers and tests ([#760](#760)) ([81f3494](81f3494)) * **compat:** GRPC client compatible with 0.3 server ([#779](#779)) ([0ebca93](0ebca93)) * **compat:** GRPC server compatible with 0.3 client ([#772](#772)) ([80d827a](80d827a)) * **compat:** legacy v0.3 protocol models, conversion logic and utilities ([#754](#754)) ([26835ad](26835ad)) * **compat:** REST and JSONRPC clients compatible with 0.3 servers ([#798](#798)) ([08794f7](08794f7)) * **compat:** REST and JSONRPC servers compatible with 0.3 clients ([#795](#795)) ([9856054](9856054)) * **compat:** set a2a-version header to 1.0.0 ([#764](#764)) ([4cb68aa](4cb68aa)) * **compat:** unify v0.3 REST url prefix and expand cross-version tests ([#820](#820)) ([0925f0a](0925f0a)) * database forward compatibility: make `owner` field optional ([#812](#812)) ([cc29d1f](cc29d1f)) * handle tenant in Client ([#758](#758)) ([5b354e4](5b354e4)) * implement missing push notifications related methods ([#711](#711)) ([041f0f5](041f0f5)) * implement rich gRPC error details per A2A v1.0 spec ([#790](#790)) ([245eca3](245eca3)) * **rest:** add tenant support to rest ([#773](#773)) ([4771b5a](4771b5a)) * send task as a first subscribe event ([#716](#716)) ([e71ac62](e71ac62)) * **server, grpc:** Implement tenant context propagation for gRPC requests. ([#781](#781)) ([164f919](164f919)) * **server, json-rpc:** Implement tenant context propagation for JSON-RPC requests. ([#778](#778)) ([72a330d](72a330d)) * **server:** add v0.3 legacy compatibility for database models ([#783](#783)) ([08c491e](08c491e)) * **spec:** add `tasks/list` method with filtering and pagination to the specification ([#511](#511)) ([d5818e5](d5818e5)) * use StreamResponse as push notifications payload ([#724](#724)) ([a149a09](a149a09)) * **rest:** update REST error handling to use `google.rpc.Status` ([#838](#838)) ([ea7d3ad](ea7d3ad)) ### Bug Fixes * add history length and page size validations ([#726](#726)) ([e67934b](e67934b)) * allign error codes with the latest spec ([#826](#826)) ([709b1ff](709b1ff)) * **client:** align send_message signature with BaseClient ([#740](#740)) ([57cb529](57cb529)) * get_agent_card trailing slash when agent_card_path="" ([#799](#799)) ([#800](#800)) ([a55c97e](a55c97e)) * handle parsing error in REST ([#806](#806)) ([bbd09f2](bbd09f2)) * Improve error handling for Timeout exceptions on REST and JSON-RPC clients ([#690](#690)) ([2acd838](2acd838)) * Improve streaming errors handling ([#576](#576)) ([7ea7475](7ea7475)) * properly handle unset and zero history length ([#717](#717)) ([72a1007](72a1007)) * return entire history when history_length=0 ([#537](#537)) ([acdc0de](acdc0de)) * return mandatory fields from list_tasks ([#710](#710)) ([6132053](6132053)) * taskslist error on invalid page token and response serialization ([#814](#814)) ([a102d31](a102d31)) * use correct REST path for Get Extended Agent Card operation ([#769](#769)) ([ced3f99](ced3f99)) * Use POST method for REST endpoint /tasks/{id}:subscribe ([#843](#843)) ([a0827d0](a0827d0)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: Ivan Shymko <ishymko@google.com>
Source: 11.5. Query Parameter Naming for Request Parameters:
MessageToDictin combination withhttpxclient produces correct output (test is added).ParseDictto support repeated fields in both formats (?tag=value1&tag=value2and?tag=value1,value2).test_client_server_integration.pyis updated to dedupe gRPC and HTTP based tests and it also asserts params now.