feat(adk): retry A2A requests on transport error - #2827
Open
anthonyhaussman wants to merge 1 commit into
Open
anthonyhaussman wants to merge 1 commit into
anthonyhaussman wants to merge 1 commit into
Conversation
anthonyhaussman
requested review from
a team,
Charlesthebird,
peterj and
supreme-gg-gg
as code owners
September 15, 2026 19:59
anthonyhaussman
marked this pull request as draft
September 15, 2026 19:59
anthonyhaussman
force-pushed
the
tone/fix/a2a-retry-transport
branch
from
September 15, 2026 20:06
2b7a4d1 to
a35d23e
Compare
anthonyhaussman
force-pushed
the
tone/fix/a2a-retry-transport
branch
from
September 15, 2026 20:25
a35d23e to
c7f9e11
Compare
anthonyhaussman
marked this pull request as ready for review
September 15, 2026 20:27
Same-cluster A2A calls skip agentgateway entirely, so pod eviction mid-request surfaces a raw EOF. SendMessage made exactly one attempt with no retry. Wrap the HTTP client with a transport-level retry, three attempts with 250ms doubling backoff, matching agentgateway's existing federation retry policy. Only retries EOF and net.OpError, never response codes, keeping status-code retry as agentgateway's job. Disabled by default, tunable via KAGENT_A2A_RETRY_ENABLED, KAGENT_A2A_RETRY_MAX_ATTEMPTS and KAGENT_A2A_RETRY_BASE_DELAY. Assisted-by: Claude Sonnet 5 Signed-off-by: Anthony Hausman <[email protected]>
anthonyhaussman
force-pushed
the
tone/fix/a2a-retry-transport
branch
from
September 15, 2026 20:28
c7f9e11 to
2b3e54f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Same-cluster agent-to-agent (A2A) calls (pod-to-pod on port 8080) go directly through
remoteA2ATool's HTTP client and never pass through any gateway/proxy layer.When the target agent pod is evicted or replaced mid-request (e.g. node consolidation, rolling update), the in-flight connection is torn down and
SendMessagefails with a raw transport error such as:remoteA2AState'shandleFirstCall/handleResumeeach callclient.SendMessageexactly once.There is no retry anywhere in the A2A client stack (
remote_a2a_tool.go,a2aclient, or the underlyinga2a-gotransport), so any pod churn during a call surfaces directly to the end user as a hard failure, even though a retry a few hundred milliseconds later would very likely succeed once the Service's endpoint list catches up.Fix
Add a small
http.RoundTripper(retry_transport.go) that wraps the A2A tool'shttp.Clientand retries only on transport-level failures:io.EOF,io.ErrUnexpectedEOF, and*net.OpError(dial/read/write failures).It never retries based on a received response status code, and it never retries when the request body cannot be safely replayed (
req.GetBody == nil).Retry policy: up to 3 attempts total, with a 250ms base delay that doubles between attempts, bounded by the request's context deadline.
The transport is wired in as the innermost layer, underneath the existing
otelhttptransport, so a single logical A2A call (including any internal retries) still produces one trace span.This covers both
client.SendMessagecall sites inremote_a2a_tool.goas well as agent-card resolutionagentcard.NewResolver(...).Resolve), since both share the same wrappedhttp.Client.Configuration
The retry is disabled by default and opt-in via env var, tunable through:
KAGENT_A2A_RETRY_ENABLED(bool, defaultfalse)KAGENT_A2A_RETRY_MAX_ATTEMPTS(int, default3)KAGENT_A2A_RETRY_BASE_DELAY(duration, default250ms)