feat!: Proposal for bidirectional streaming over gRPC#1549
feat!: Proposal for bidirectional streaming over gRPC#1549HungYangChang wants to merge 9 commits intoa2aproject:mainfrom
Conversation
This adds a new `SendLiveMessage` RPC to the gRPC A2A service definition. The purpose of this RPC is to address cases where a client would like to maintain an active request stream with an agent, rather than requiring separate follow-up requests any time an agent needs further input. This bidirectional communication is ONLY supported via gRPC. I have tried to lay out the expected semantics as a comment in the gRPC specification. A2A is generally a turn-based protocol, where clients and servers take turns sending each other messages. This is not specifically encoded in our specification, however our SDK implementations do not directly support the idea of receiving a stream of messages from a client. Instead, each new message is treated as a new invocation of the agent implementation. The assumption here is that a client will only send messages to tasks that are in an interrupted state (i.e. input-required), and that agent executions will exit when they reach an interrupted state. The current behavior of SDKs for when a message is received for a task that is actively being processed could be categorized as "undefined". A bidirectional endpoint opens the possibility of full-duplex communication between client and server, however it doesn't require it: bidirectionality is still useful even in a turn-based protocol. The benefit is that an ongoing connection can be maintained for sending responses to agents that enter interrupted states, which enables several convenient properties: - Agent implementations can more easily "await" responses inline, rather than needing to save all necessary state, exit, then reconstitute state when a response is received. - Clients can perform less state tracking, particularly around specifying task and context IDs. These can be implicit to the connection, as a connection is only valid for a single task. - Distributed agent implementations don't need to implement clever load-balancing/routing to achieve task processing locality. Since an active connection is maintained, all responses are received by the same server. This is another view of the first point in this list, but from the networking layer.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Move bidi_streaming (field 4) after extensions (field 3) to follow the convention of ordering fields by their field number. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add SendLiveMessage RPC and bidi_streaming capability to the current specification/a2a.proto instead of the old deleted file locations. Remove re-created legacy files that no longer exist in upstream. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- specification.md: Add Section 3.1.3 (Send Live Message operation), capability validation bullet, method mapping row, gRPC method subsection (10.4.3), and update streaming section (10.7) - streaming-and-async.md: Add bidirectional streaming section with comparison table and usage guidance - key-concepts.md: Add bidirectional streaming to interaction mechanisms - llms.txt: Add SendLiveMessage to RPC table and bidi_streaming to capabilities list - whats-new-v1.md: Document new bidiStreaming capability and SendLiveMessage RPC - extensions.md: Fix broken snippet include (types/src/types.ts was deleted, replaced with proto reference) Co-Authored-By: Claude Opus 4.6 <[email protected]>
Summary of ChangesHello @HungYangChang, 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 enhances the A2A protocol by introducing bidirectional streaming capabilities through a new 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 is an excellent and well-documented proposal for adding bidirectional streaming to the A2A protocol. The new SendLiveMessage RPC is clearly defined, and the extensive updates to the specification and topic guides provide great clarity on its use cases, particularly for human-in-the-loop scenarios. The changes are consistent and follow the protocol's design principles. I have only a couple of minor suggestions to enhance the documentation around reconnection scenarios to make it even more comprehensive for implementers.
Add NOT_FOUND and FAILED_PRECONDITION error cases to reconnection docs in specification.md and streaming-and-async.md per gemini-code-assist suggestions. Co-Authored-By: Claude Opus 4.6 <[email protected]>
499209e to
ecdea3f
Compare
Inserting section 3.1.3 (Send Live Message) shifted all subsequent sections. This fixes the heading numbers (3.1.4 List Tasks through 3.1.12 Get Extended Agent Card) and updates all internal link fragments to match, resolving markdownlint MD051 errors. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Reframe bidirectional streaming documentation to emphasize persistent connections and simplified state management rather than human-in-the-loop interactions, aligning with the original PR a2aproject#1120 framing. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…_table macro Co-Authored-By: Claude Opus 4.6 <[email protected]>
Follow on PR #1120 - BiDi Streaming Discussion Responses
PR: feat!: Proposal for bidirectional streaming over gRPC
Original Author: mikeas1| Author: hungyangchang| Status: Open,
TSC ReviewSummary
Adds
SendLiveMessagebidirectional streaming RPC to A2A gRPC. Clients maintain an active stream with agents instead of separate follow-up requests. Benefits: inline await, less client state tracking, simpler distributed routing.Upstream File Structure Changes
The original PR modified 3 files that no longer exist in upstream
main:specification/grpc/a2a.protospecification/a2a.protospecification/json/a2a.jsontypes/src/types.tsa2a.protois now the single source of truth. The JSON schema is generated at build time viascripts/proto_to_json_schema.sh, anddocs/specification.mdusesproto_to_table()macros that auto-render from proto definitions.Responses
1. gemini-code-assist (bot) - Oct 1, 2025
Field ordering: Fixed.
bidi_streamingnow followsextensionsby field number. In new schema it's field 5 (field 4 =extended_agent_card).FAILED_PRECONDITIONvsUNIMPLEMENTED: Both are used correctly for distinct cases.FAILED_PRECONDITION= duplicate active stream;UNIMPLEMENTED= method not supported.Omitted
SendMessageConfiguration: Already specified: "If omitted, the agent MUST continue to use the configuration from the initial request."2. ToddSegal - Oct 7, 2025
Resubscribe interaction: Continues as-is.
SendLiveMessageis a separate RPC.Multiple client calls: Three rules (per mikeas1):
FAILED_PRECONDITIONMissing task_id: Empty values are interpreted as the established stream's task_id/context_id.
3. HungYangChang - Dec 11, 2025
Interrupted vs Failed: These are distinct states with different BiDi behavior:
INPUT_REQUIRED,AUTH_REQUIREDCOMPLETED,FAILED,CANCELED,REJECTEDThis is the key difference from
SendStreamingMessage, which closes on both interrupted and terminal states (per spec 11.1: "until the task reaches a terminal or interrupted state, at which point the stream closes").State transitions on BiDi stream: When a Task reaches
INPUT_REQUIRED:The agent can "await" the response inline without saving/reconstituting state. This is the primary advantage over
SendStreamingMessage+ separateSendMessagefollow-up.Timeout: Not specified in the protocol. Left to agent implementation, consistent with A2A's approach of leaving operational policies to implementations. Options:
FAILEDorCANCELEDtimeoutfield inSendMessageConfigurationMultiple interruptions: Fully supported. Each interruption keeps the stream open:
Error codes:
UNIMPLEMENTEDNOT_FOUNDFAILED_PRECONDITIONINVALID_ARGUMENT4. Tehsmash - Feb 25, 2026
Concern: BiDi might encourage multi-turn tied to a single Task instead of context-based reuse.
Response: This concern is partially valid, and we should be clear about scope:
The BiDi stream IS scoped to a single Task. The spec states: "the established stream Task" (singular), and "The agent MUST half-close the connection when the Task reaches a terminal state." Once a task completes, the stream closes. You cannot create Task B on the same stream after Task A completes.
BiDi is NOT for multi-turn conversation. The recommended pattern for multi-turn remains:
This is unchanged. BiDi doesn't replace or conflict with this pattern.
BiDi IS for single-task human-in-the-loop. The specific use case is tasks that need clarification or approval mid-execution:
Without BiDi, this requires:
SendStreamingMessage-> stream closes onINPUT_REQUIRED-> newSendMessage-> newSendStreamingMessageto get updates. BiDi simplifies this to a single persistent connection.The "bad" pattern Tehsmash described isn't really bad for BiDi. The pattern
Task -> input-required -> respond -> input-required -> respond -> completeis exactly the intended use case. It represents a single unit of work (e.g., booking a flight) that requires multiple human confirmations. This is different from multi-turn conversation where each turn is a separate task.Key distinction to document: BiDi streaming is for single-task execution with inline interruptions, not for multi-task conversational flows.
Recommended BiDi Streaming Patterns
When to Use
SendLiveMessage(BiDi)Use BiDi streaming when all of these apply:
capabilities.bidiStreaming: trueINPUT_REQUIREDorAUTH_REQUIREDstatesWhen NOT to Use
SendLiveMessageSendMessageinsteadSendStreamingMessageSendMessagecalls with sharedcontextIdSendMessage+ push notificationsPattern 1: Single-Task with Human Approval (Recommended BiDi Use Case)
A task that requires one or more human confirmations before completing.
Pattern 2: Multi-Turn Conversation (Do NOT Use BiDi)
For multi-turn conversations, use separate RPC calls with shared
contextId:Pattern 3: Reconnecting to an Active Task
A client can reconnect to an ongoing task's BiDi stream (e.g., after network disruption):
Comparison Table
SendMessageSendStreamingMessageSendLiveMessageSendMessage+ push notificationsSendMessagecallsChanges Made
Proto (
specification/a2a.proto)SendLiveMessagebidirectional streaming RPC afterSendStreamingMessageoptional bool bidi_streaming = 5toAgentCapabilitiesspecification/grpc/a2a.proto,specification/json/a2a.json,types/src/types.ts)Specification (
docs/specification.md)bidiStreamingcapability validation bullet in Section 3.3.4SendLiveMessagerow to method mapping table in Section 5.3 (gRPC only, N/A for JSON-RPC and REST)SendLiveMessageSendLiveMessageto operations layer Mermaid diagramTopic Docs
docs/topics/streaming-and-async.md: Added "Bidirectional Streaming with gRPC" section with SSE vs BiDi comparison table, usage guidance, and when to/not to usedocs/topics/key-concepts.md: Added bidirectional streaming as 4th interaction mechanismReference Docs
docs/llms.txt: AddedSendLiveMessageto RPC methods table,bidi_streamingto capabilities listdocs/whats-new-v1.md: AddedbidiStreamingto AgentCapabilities changes, added "NEW: SendLiveMessage" operation sectionBug Fix
docs/topics/extensions.md: Fixed broken snippet include —types/src/types.ts:AgentExtension(deleted file) replaced withspecification/a2a.proto:AgentExtensionAction Items
AgentCapabilitiesspecification/a2a.proto(new file location)