Skip to content

Conversation

@jmesnil
Copy link
Collaborator

@jmesnil jmesnil commented Nov 27, 2025

Expand PushNotificationSender to support all StreamingEventKind payload types
as defined in the A2A specification, not just Task objects.

Fixes: #490

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests pass
  • Appropriate READMEs were updated (if necessary)

Fixes #490 🦕

Signed-off-by: Jeff Mesnil <[email protected]>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jmesnil, 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 generalizes the push notification mechanism to support a wider array of event types. By transitioning the PushNotificationSender from handling only Task objects to accommodating any StreamingEventKind as defined in the A2A specification, the system gains significant flexibility. This enhancement allows for more diverse event-driven notifications, such as messages, status updates, and artifact updates, ensuring better alignment with the broader A2A event model.

Highlights

  • Expanded Payload Support: The PushNotificationSender interface and its implementations (BasePushNotificationSender, MockPushNotificationSender) have been updated to accept StreamingEventKind as a generic payload type, moving beyond the previous Task-only restriction.
  • Dynamic Task ID Extraction: The BasePushNotificationSender now includes logic to dynamically extract the relevant taskId from different StreamingEventKind types (e.g., Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent) using a switch expression.
  • Comprehensive Testing: The mock PushNotificationSender and integration tests have been refactored to align with the new StreamingEventKind type, and a new test case has been added to specifically verify the sending of Message payloads.
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.

@jmesnil
Copy link
Collaborator Author

jmesnil commented Nov 27, 2025

This PR is built on top of #492 and should be merged after.

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 successfully expands the PushNotificationSender to support various StreamingEventKind payloads, which is a great feature enhancement. The core logic changes are well-implemented, although there's a minor opportunity to use more modern Java features for improved readability. However, the accompanying tests have several critical issues. Some existing tests haven't been correctly updated to handle the new generic event types, which will lead to compilation errors. More importantly, the mock HTTP client and the new test case for sending Message payloads are flawed, causing the test to fail at runtime. There is also some leftover debugging code that should be removed.

Comment on lines 85 to 86
Task task = Utils.OBJECT_MAPPER.readValue(body, Task.TYPE_REFERENCE);
tasks.add(task);
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The mock HTTP client is hardcoded to deserialize the request body into a Task object. With the changes in this PR, the payload can be any StreamingEventKind, such as a Message. This will cause a JsonProcessingException when testSendNotificationWithMessage is run. The mock client needs to be updated to handle different event types. I suggest deserializing to StreamingEventKind and then conditionally adding to the tasks list if it's a Task. You will also need to update the new test testSendNotificationWithMessage to assert against the correct event type (a Message), which may require adding a new list to TestHttpClient to store all captured events.

Suggested change
Task task = Utils.OBJECT_MAPPER.readValue(body, Task.TYPE_REFERENCE);
tasks.add(task);
StreamingEventKind event = Utils.OBJECT_MAPPER.readValue(body, StreamingEventKind.class);
if (event instanceof Task task) {
tasks.add(task);
}

Comment on lines +350 to +352
assertEquals(1, testHttpClient.tasks.size());
Task sentTask = testHttpClient.tasks.get(0);
assertEquals(taskData.getId(), sentTask.getId());
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

These assertions are incorrect. You are sending a Message object, but asserting that a Task was captured. The PushNotificationSender sends the Message object itself. This test will fail because TestHttpClient is not equipped to handle Message payloads and will throw an exception during deserialization, as noted in another comment. The TestHttpClient needs to be updated to capture StreamingEventKind objects, and this test should assert that a Message was received.

Comment on lines +91 to 93
Queue<Task> captured = mockPushNotificationSender.getCapturedEvents();
assertEquals(1, captured.size());
assertEquals("direct-test-task", captured.peek().getId());
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The type of the captured variable is incorrect. mockPushNotificationSender.getCapturedEvents() returns a Queue<StreamingEventKind>, not a Queue<Task>. This will cause a compilation error. You need to update the variable type and add a cast to access Task-specific methods. It's also safer to check the type before casting.

        Queue<StreamingEventKind> captured = mockPushNotificationSender.getCapturedEvents();
        assertEquals(1, captured.size());
        assertTrue(captured.peek() instanceof Task, "Captured event should be a Task");
        assertEquals("direct-test-task", ((Task) captured.peek()).getId());

Comment on lines +55 to +61
String taskId = switch (kind.getKind()) {
case TASK -> ((Task) kind).getId();
case MESSAGE -> ((Message)kind).getTaskId();
case STATUS_UPDATE -> ((TaskStatusUpdateEvent)kind).getTaskId();
case ARTIFACT_UPDATE -> ((TaskArtifactUpdateEvent)kind).getTaskId();
default -> null;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Since this project uses a modern Java version (as indicated by the use of sealed interfaces), you can leverage pattern matching for switch. This will make the code more concise, readable, and type-safe by avoiding explicit string comparisons and casts.

        String taskId = switch (kind) {
            case Task t -> t.getId();
            case Message m -> m.getTaskId();
            case TaskStatusUpdateEvent e -> e.getTaskId();
            case TaskArtifactUpdateEvent e -> e.getTaskId();
        };

@Override
public PostBuilder body(String body) {
this.body = body;
System.out.println("body = " + body);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This System.out.println appears to be leftover debugging code and should be removed before merging.

Task task = Utils.OBJECT_MAPPER.readValue(body, Task.TYPE_REFERENCE);
tasks.add(task);
urls.add(url);
System.out.println(requestHeaders);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This System.out.println appears to be leftover debugging code and should be removed before merging.

@jmesnil jmesnil closed this Nov 27, 2025
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.

[Feat]: Push Notification Payload can also be message, statusUpdate or artifactUpdate

1 participant