Skip to content

fix: handle REST query params as per 1.0 spec#804

Merged
ishymko merged 1 commit into1.0-devfrom
ishymko/improve-tests
Mar 11, 2026
Merged

fix: handle REST query params as per 1.0 spec#804
ishymko merged 1 commit into1.0-devfrom
ishymko/improve-tests

Conversation

@ishymko
Copy link
Member

@ishymko ishymko commented Mar 11, 2026

Source: 11.5. Query Parameter Naming for Request Parameters:

Field Type Handling:

  • Strings: Passed directly as query parameter values
  • Booleans: Represented as lowercase strings (true, false)
  • Numbers: Represented as decimal strings
  • Enums: Represented using their string values (e.g., status=working)
  • Repeated Fields: Multiple values MAY be passed by repeating the parameter name (e.g., ?tag=value1&tag=value2) or as comma-separated values (e.g., ?tag=value1,value2)
  • Nested Objects: Not supported in query parameters; operations requiring nested objects MUST use POST with a request body
  • Datetimes/Timestamps: Represented as ISO 8601 strings (e.g., 2025-11-09T10:30:00Z)
  1. Using MessageToDict in combination with httpx client produces correct output (test is added).
  2. Parsing has an extra addition on top of ParseDict to support repeated fields in both formats (?tag=value1&tag=value2 and ?tag=value1,value2).
  3. test_client_server_integration.py is updated to dedupe gRPC and HTTP based tests and it also asserts params now.

@ishymko ishymko force-pushed the ishymko/improve-tests branch from 5ad30e8 to e685af9 Compare March 11, 2026 08:54
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, 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

  • Standardized REST Query Parameter Handling: Introduced a new utility function, proto_utils.parse_params, to consistently convert REST query parameters into Protobuf messages. This function handles A2A-specific requirements such as camelCase field names, boolean string conversion ('true'/'false'), and robust parsing of repeated fields (supporting both multiple keys and comma-separated values).
  • Client-Side Query Parameter Refinement: Modified the REST client to correctly exclude fields like id, taskId, and tenant from query parameters when they are part of the URL path or handled by the context, ensuring adherence to the 1.0 specification for various task-related API calls.
  • Server-Side Query Parameter Integration: Updated the REST request handler to utilize the new proto_utils.parse_params for processing incoming query parameters, replacing previous ad-hoc parsing logic. This ensures that the server correctly interprets REST requests according to the specification.
  • Enhanced Integration Test Coverage: Refactored integration tests to use a single parametrized fixture that runs tests across all supported transports (JSON-RPC, REST, gRPC). This significantly improves test efficiency and ensures consistent behavior across different communication protocols, with new tests specifically validating REST URL serialization.
Changelog
  • src/a2a/client/transports/rest.py
    • Removed 'tenant' from query parameters in get_task, list_tasks, get_task_push_notification_config, list_task_push_notification_configs, and delete_task_push_notification_config.
    • Changed task_id to taskId in query parameter deletion logic for push notification configurations.
    • Updated list_tasks to use a pre-processed params dictionary instead of direct MessageToDict(request).
  • src/a2a/server/request_handlers/rest_handler.py
    • Removed unused imports ParseDict and GetTaskRequest.
    • Replaced direct ParseDict calls with proto_utils.parse_params for query parameter processing in on_get_task, list_tasks, and list_push_notifications.
    • Added logic to set tenant from context if not provided in query parameters for list_tasks and list_push_notifications.
  • src/a2a/utils/proto_utils.py
    • Added imports for ParseDict, ProtobufMessage, and QueryParams (with type checking guard).
    • Introduced new function parse_params to convert REST query parameters to Protobuf messages, handling boolean conversion, repeated fields, and camelCase names.
  • tests/client/transports/test_rest_client.py
    • Imported Timestamp and TaskState.
    • Added test_url_serialization to verify correct serialization of query parameters, including camelCase and tenant exclusion.
    • Updated an assertion in test_rest_get_task_prepend_empty_tenant for URL string formatting.
  • tests/integration/test_client_server_integration.py
    • Imported Timestamp and reorganized protobuf imports.
    • Removed unused imports A2ACardResolver and cryptography.hazmat.primitives.asymmetric.
    • Updated agent_card fixture to include extended_agent_card=True capability.
    • Modified TransportSetup to allow handler to be RequestHandler | AsyncMock.
    • Updated rest_setup to pass extended_agent_card to A2ARESTFastAPIApplication.
    • Added grpc_setup fixture and transport_setups parametrized fixture to unify integration tests.
    • Refactored multiple HTTP/gRPC specific integration tests into generic test_transport_* functions.
    • Updated ListTasksRequest in test_transport_list_tasks to include more comprehensive query parameters.
    • Removed f-string formatting for task IDs in various test requests.
    • Adjusted assertions to use assert_awaited_once_with(params, ANY) for handler calls.
  • tests/utils/test_proto_utils.py
    • Added imports for httpx, MessageToDict, Parse, ProtobufMessage, Timestamp, AgentCard, AgentSkill, ListTasksRequest, and QueryParams.
    • Added TestRestParams class with test_rest_params_roundtrip and test_repeated_fields_parsing to validate the new proto_utils.parse_params function.
Activity
  • The pull request was created by ishymko.
  • The changes primarily involve refactoring and adding new utility functions and tests, indicating a focused development effort without external comments or reviews yet.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ishymko ishymko marked this pull request as ready for review March 11, 2026 09:03
@ishymko ishymko requested a review from a team as a code owner March 11, 2026 09:03
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

high

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)

high

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)

medium

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)

medium

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)

medium

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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)

low

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.

@ishymko ishymko force-pushed the ishymko/improve-tests branch from e685af9 to 8ab9691 Compare March 11, 2026 09:11
@ishymko ishymko merged commit 45b3059 into 1.0-dev Mar 11, 2026
9 checks passed
@ishymko ishymko deleted the ishymko/improve-tests branch March 11, 2026 09:15
ishymko added a commit that referenced this pull request Mar 17, 2026
🤖 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants