Replies: 1 comment
-
|
@seanzhou1023 can you please look into this. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I have been experimenting with the to_a2a utility and some of the behavior doesn't seem quite right with respect to the A2A protocol so I wanted to discuss it here:
The core behavior of this wrapper seems to produce the following sequences of A2A events when the wrapped agent is invoked for a streaming response (user submits a Message object containing their query):
A TaskStatusUpdateEvent is generated setting the status to
Submittedand containing a Message for which the text is the user's original query. ExampleA TaskStatusUpdateEvent is generated setting the status to
Workingwith no Message content ExampleAnother TaskStatusUpdateEvent is generated with the status still
Workingbut containing a Message with the text response from the agent/llm ExampleA TaskArtifactUpdateEvent is generated containing an Artifact which contains the text response from the agent/llm Example
A final TaskStatusUpdateEvent is generated with the status
Completedand no Message content. ExampleMy questions are as follows:
A) Why is the original query used as the "reason" (Message text) for the status update in (1)? This seems like it should be a reason for the status change (e.g. "the user query has been received"), not literally the user's query (though yes, technically the query is the reason for the status change)
B) Why is the response text included in (3) ? Again I'd expect the message content here to be an explanation of why the Status has changed, e.g. "agent is generating a response". (Also not entirely clear why there should be two Status update events when the status isn't actually changing, but i could see an argument for doing it if the reason/Message was changing....which in this case it sort of is, it goes from nothing to an actual value)
C) Ultimately the response text is also sent as a TaskArtifactUpdate, which is what I'd expect, but it's a single Artifact update, the code in question has no way to send multiple TaskArtifactUpdates such as you might expect if it were streaming chunks of response text back as the agent/llm generated them. Instead the implementation seems to rely on using multiple TaskStatusUpdateEvents(each containing a Message with a chunk of the response) to stream back chunks of response text, if it's going to do so at all, which doesn't seem like the right use of the protocol objects.
D) Somewhat related, the TaskResultAggregrator, from which the message content for the Artifact is retrieved, is not actually aggregating text, it only retains the last chunk of text it saw. This seems like it won't work if the response text was returned as chunks in a series of TaskStatusUpdateEvents because in that case the resulting Artifact will only contain that last chunk. Of course this code is also predicated on the underlying agent sending TaskStatusUpdateEvents to return the actual response text and not TaskArtifactUpdate events, which seems incorrect to me.
As evidence that at least some of this behavior is incorrect, I explored how this behaves in the non-streaming case and among other things I can clearly see that this behavior results in duplicated History text in the Task object that is returned to the client because of the response text being included in the TaskStatusUpdateEvent. The A2A library itself, when producing a non-streaming response, aggregates the various events that are being generated, which in this case means it includes in the history:
in addition to the actual Artifact content which is derived from the TaskArtifactUpdate event.
This means that both the original query, and the final response, are duplicated in the resulting Task response. (The query is duplicated in the History, the final response appears in both History and the actual Artifact)
What I would expect the behavior to be:
In the non-streaming case, this would result in A2A emitting a single Task containing:
TLDR: I think that response content generated by the agent/llm should be emitted in one or more TaskArtifactUpdateEvents, not included as Message text on TaskStatusUpdateEvents and the behavior of the A2A server library in the non-streaming case(which still consumes A2A streaming events from the agent before turning them into a single A2A Task event) seems to confirm this expectation. You can follow the A2A request handler logic and how it aggregates events into a Single task for the non-streaming case here: https://github.com/a2aproject/a2a-python/blob/3bfbea9ec8d7982fa73eb12d8352a581307355dc/src/a2a/server/request_handlers/default_request_handler.py#L289-L400
My example includes no tool or sub-agent calls, but it would make sense to me that if those were present, they would result in additional TaskStatusUpdateEvents where the message content included the tool call request/responses, which I believe does already happen with the current implementation.
Beta Was this translation helpful? Give feedback.
All reactions