Skip to content

Mastra A2A subagents#16348

Open
TheIsrael1 wants to merge 15 commits into
mainfrom
feat/a2a-agent-class
Open

Mastra A2A subagents#16348
TheIsrael1 wants to merge 15 commits into
mainfrom
feat/a2a-agent-class

Conversation

@TheIsrael1
Copy link
Copy Markdown
Contributor

@TheIsrael1 TheIsrael1 commented May 8, 2026

This adds an experimental A2AAgent to @mastra/core/a2a so a Mastra agent can use a remote A2A agent as a subagent.

The main story here is registering a remote agent card URL on a parent agent and letting Mastra delegate to it through the normal subagent path.

import { Agent } from '@mastra/core/agent';
import { A2AAgent } from '@mastra/core/a2a';

const supportAgent = new Agent({
  name: 'Support Agent',
  model,
  agents: {
    remoteWeather: new A2AAgent({
      url: 'https://example.com/.well-known/agent-card.json',
    }),
  },
});

A2AAgent handles agent card discovery/bootstrap, remote generate / resumeGenerate, remote stream / resumeStream, suspend-resume payloads, optional agent card verification, and the browser-safe shared A2A imports used by client-js via @mastra/core/a2a/client.

I also tightened the stream path a bit while building this out: malformed SSE frames are skipped instead of aborting the run, non-transient 4xx responses are not retried, and the focused tests now cover the subagent path plus those stream edge cases.

ELI5

This PR lets one AI agent use another AI agent as a helper. Instead of doing all the work itself, an agent can send tasks to a remote AI agent and get back the results—kind of like asking a friend for help instead of doing something alone.


Changes Summary

This PR introduces an experimental A2AAgent implementation that enables Mastra agents to delegate work to remote A2A agents via a subagent pattern. The implementation includes comprehensive testing, stream robustness improvements, and a browser-safe client surface for shared types.

Core Implementation

  • A2AAgent class added at @mastra/core/a2a implementing the SubAgent interface
    • Supports generate(), resumeGenerate(), stream(), and resumeStream() methods for remote A2A execution over JSON-RPC
    • Auto-discovers and caches remote Agent Cards in memory
    • Supports optional agent card verification before execution
    • Handles request retries with exponential backoff, timeouts, and credentials
    • Implements suspend–resume payload handling for multi-turn interactions

Stream Handling & Robustness

  • Malformed SSE frames are now skipped instead of aborting stream processing
  • Non-transient HTTP 4xx responses are no longer retried
  • Stream consumption supports both SSE-based and buffered fallback modes
  • Proper cleanup of stream locks and cancellation tokens

Browser-Safe Client Surface

  • New public export subpath @mastra/core/a2a/client provides browser-compatible types and error classes
  • Client-JS can now reuse A2A protocol types and errors without Node-only runtime dependencies
  • Reorganized type exports to separate client-safe interfaces from internal implementation

Testing & Validation

  • 823-line comprehensive test suite for A2AAgent covering:
    • Agent card caching and verification behavior
    • Non-streaming and streaming execution paths
    • Resume/continuation scenarios
    • SSE stream edge cases and error handling
    • Subagent integration with parent agent memory
  • 6-line regression test ensuring AgentBadge renders correctly for subagent content

Build & Configuration

  • Updated package.json exports map with new ./a2a/client subpath (ESM and CJS targets with shared type definitions)
  • Added src/a2a/client.ts to tsup build configuration
  • Reorganized module exports: moved bulk type/error re-exports from main index to client barrel

Type System Additions

New public types in @mastra/core/a2a/types:

  • A2AAgentOptions – configuration for agent card URL, verification, fetch, timeout, retry, and credential handling
  • A2AAgentVerificationOptions & A2AAgentCardVerificationContext – optional card verification hooks
  • A2AAgentRunState – tracks run/task/context identifiers and card URLs
  • A2AAgentResumePayload – suspend–resume state for multi-turn execution
  • A2AAgentGenerateResult & A2AAgentStreamResult – typed results for generation and streaming

Client-JS Updates

  • Updated imports across test files, resources, and utilities to use @mastra/core/a2a/client instead of @mastra/core/a2a
  • Improved agent card signature tampering in tests to use base64url byte-flipping instead of character substitution

UI Refinement

  • AgentBadge no longer defaults badge to collapsed state; now consistently renders open for both live and hydrated subagent content

Review Change Stack

Add an experimental A2AAgent to @mastra/core/a2a with generate, resumeGenerate, stream, and resumeStream methods for remote A2A agents.

Split the browser-safe shared A2A surface into @mastra/core/a2a/client so client-js can keep using shared protocol types and errors without pulling in the Node-only agent runtime.

Also adds focused tests around card discovery, live streaming behavior, and resumable task flows.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mastra-docs-1.x Ready Ready Preview, Comment May 12, 2026 5:06pm
mastra-playground-ui Ready Ready Preview, Comment May 12, 2026 5:06pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This pull request introduces A2AAgent, a new SubAgent implementation enabling remote A2A agent execution from @mastra/core. It adds complete type contracts, streaming/non-streaming orchestration, agent-card caching and verification, and comprehensive test coverage. The export surface is refactored to use a dedicated @mastra/core/a2a/client subpath for browser-safe type sharing with the client SDK.

Changes

A2AAgent Remote Execution with Client Export

Layer / File(s) Summary
Type Contracts
packages/core/src/a2a/types.ts
Adds A2A-specific types: A2AAgentOptions, A2AAgentCardVerificationContext, A2AAgentVerificationOptions, A2AAgentRunState, A2AAgentResumePayload, A2AAgentGenerateResult, and A2AAgentStreamResult for configuration, state tracking, verification, and typed results.
Stream Parsing Utilities
packages/core/src/a2a/a2a-agent.ts (lines 1–142)
Low-level helpers for splitting/parsing SSE-like event blocks, parsing [DONE], and extracting concatenated text from message/task/artifact parts.
Text Extraction Helpers
packages/core/src/a2a/a2a-agent.ts (lines 143–178)
Implements text extraction from Task artifacts/status and Message parts.
Prompt / Resume Helpers
packages/core/src/a2a/a2a-agent.ts (lines 179–291)
Serializes MessageListInput into a remote prompt, creates resume prompts and JSON schema, and resolves memory thread/resource ids.
Result Construction & Validation
packages/core/src/a2a/a2a-agent.ts (lines 292–370)
Constructs A2AAgentGenerateResult from terminal Message or Task outcomes, unwraps JSON-RPC shapes, and requires streaming response bodies when expected.
A2AAgent Class & Bootstrap
packages/core/src/a2a/a2a-agent.ts (lines 403–620)
A2AAgent constructor, identity, bootstrap with agent-card fetching and in-memory caching, optional verification hook, memory wiring, and public non-streaming entrypoints.
Bootstrap RPC & Task Polling
packages/core/src/a2a/a2a-agent.ts (lines 622–881)
Implements card URL resolution, message/send RPC path, non-stream send-and-resolve flow, and task polling (tasks/get) until completion or suspension with suspend payload/schema construction.
Streaming Orchestration & Fallback
packages/core/src/a2a/a2a-agent.ts (lines 883–1403)
stream/resumeStream route to message/stream or tasks/resubscribe when supported; uses ReadableStream.tee() to emit incremental text-start/text-delta/text-end events and collect final text; provides buffered fallback when remote streaming unsupported.
Request, Retry & Abort Utilities
packages/core/src/a2a/a2a-agent.ts (lines 1448–1558), packages/core/tsup.config.ts
#request helper with retries/backoff, Accept header switching, JSON serialization, non-OK error handling, delay helper, combined abort-signal resolution; tsup updated to include src/a2a/client.ts.
Client Barrel Export & Packaging
packages/core/src/a2a/client.ts, packages/core/src/a2a/index.ts, packages/core/package.json
Adds @mastra/core/a2a/client barrel re-exporting ./error, @a2a-js/sdk, and named A2A types; index.ts now exports through client and explicitly exports A2AAgent; package.json adds ./a2a/client export subpath.
Test Scaffolding & Fixtures
packages/core/src/a2a/a2a-agent.test.ts (lines 1–153)
Vitest scaffolding: agent-card fixtures, JSON-RPC builders, SSE/delayed SSE generators, mocked fetch queue, and cleanup hooks.
SubAgent Interface & Memory Tests
packages/core/src/a2a/a2a-agent.test.ts (lines 155–206)
Tests verify SubAgent compatibility, memory injection, in-memory agent-card caching, explicit card URL handling, and optional verification invocation during bootstrap.
Parent Agent Tool Integration
packages/core/src/a2a/a2a-agent.test.ts (lines 227–270)
Tests registering A2AAgent on a parent Agent and executing through generated subagent tools; verifies message/send/message/stream RPC usage and returned text propagation.
Generate, Resume & Memory Behavior
packages/core/src/a2a/a2a-agent.test.ts (lines 336–466)
Tests generate() polling for non-stream remotes, generate() using message/send even if streaming advertised, preservation of memory identifiers, and resumeGenerate() behavior using cached run state and follow-up message/send.
Streaming Mode Tests & Edge Cases
packages/core/src/a2a/a2a-agent.test.ts (lines 468–816)
Tests fallback buffering when streaming unsupported, SSE consumption producing correct event sequences and final text, live stream result emission before SSE completion, artifact chunk concatenation without newlines, excluding progress status text, malformed-frame skipping, resubscribe/resume via tasks/resubscribe, and 4xx non-retry behavior.
Client SDK Import & Test Adjustments
client-sdks/client-js/src/resources/a2a.test.ts, client-sdks/client-js/src/resources/a2a.ts, client-sdks/client-js/src/utils/process-a2a-stream.ts
Client-js imports A2A types/errors from @mastra/core/a2a/client; test invalid-signature tampering now mutates decoded signature bytes via base64url.
Playground Badge Change & Regression Test
packages/playground/src/lib/ai-ui/tools/badges/agent-badge.tsx, packages/playground/src/lib/ai-ui/tools/__tests__/agent-badge-falsy-output-regression.test.ts
AgentBadge now starts uncollapsed (initialCollapsed={false}) and a regression test verifies the updated rendering.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Mastra A2A subagents' is concise (20 characters) and directly describes the main feature being added—an A2AAgent implementation enabling Mastra agents to use remote A2A agents as subagents, which aligns with the substantial changes across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/a2a-agent-class

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 8, 2026

🦋 Changeset detected

Latest commit: 2c268d4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@mastra/core Minor
mastracode Patch
@mastra/mcp-docs-server Patch
@internal/playground Patch
@mastra/client-js Patch
@mastra/opencode Patch
@mastra/longmemeval Patch
mastra Patch
@mastra/deployer-cloud Minor
@mastra/deployer-vercel Patch
@mastra/playground-ui Patch
@mastra/react Patch
@mastra/server Minor
@mastra/deployer Minor
create-mastra Patch
@mastra/express Patch
@mastra/fastify Patch
@mastra/hono Patch
@mastra/koa Patch
@mastra/nestjs Patch
@mastra/deployer-cloudflare Patch
@mastra/deployer-netlify Patch
@mastra/temporal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@TheIsrael1 TheIsrael1 changed the title Mastra A2A subagents Mastra A2A subAgents May 8, 2026
@TheIsrael1 TheIsrael1 changed the title Mastra A2A subAgents Mastra A2A subagents May 8, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
.changeset/whole-papers-throw.md (1)

7-12: ⚡ Quick win

Refocus "What changed" on developer outcomes rather than implementation details.

Lines 10-12 describe internal architecture ("in-memory caching", "typed result objects for wrappers", "dedicated subpath for browser-safe shared types") rather than what developers gain. Changeset descriptions should highlight capabilities and impact, not how features are implemented internally.

Consider rephrasing to emphasize outcomes:

  • Line 10: What can developers do with card verification? (e.g., "Verify Agent Card signatures using custom key providers")
  • Line 11: What do the result types enable? (Skip if this is purely internal)
  • Line 12: What does the client subpath unlock? (e.g., "Import A2A types in browser environments via @mastra/core/a2a/client")

Also consider varying the sentence structure beyond "Added..." to improve scannability.

As per coding guidelines: "Highlight outcomes! What does change for the end user? Do not focus on internal implementation details."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/whole-papers-throw.md around lines 7 - 12, Update the "What
changed" section to emphasize developer-facing outcomes instead of
implementation details: for the A2AAgent entry mention the new developer
capabilities (e.g., "Remote A2A execution via generate, resumeGenerate, stream,
and resumeStream" so devs know what they can do), rephrase the Agent Card line
to describe the outcome (e.g., "Verify Agent Card signatures with pluggable key
providers" rather than "in-memory caching"), and rewrite the client subpath line
to state the benefit (e.g., "Import A2A types in browser environments via
`@mastra/core/a2a/client`"); vary sentence starts away from repeated "Added..."
and prefer short outcome-focused bullets.
packages/core/src/a2a/a2a-agent.ts (3)

1005-1013: 🏗️ Heavy lift

as unknown as A2AAgentStreamResult and AsyncIterable<any> defeat the public type contract.

The two as unknown as A2AAgentStreamResult casts (lines 1002 and 1338) plus AsyncIterable<any> on line 1013 indicate the assembled object doesn't structurally match A2AAgentStreamResult. Strict TypeScript will silently let you drift from the contract here — e.g., renaming a property on A2AAgentStreamResult won't error in this file. Prefer defining a discriminated event union for stream chunks (text-start | text-delta | text-end | tool-call-suspended | finish) and constructing a value that satisfies A2AAgentStreamResult without unknown casts. As per coding guidelines, "Packages must use strict TypeScript".

Also applies to: 1002-1002, 1338-1338

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/a2a/a2a-agent.ts` around lines 1005 - 1013, The stream
helper `#streamEvents` is currently typed as AsyncIterable<any> and uses two "as
unknown as A2AAgentStreamResult" casts which bypass the A2AAgentStreamResult
contract; replace the casts and the loose AsyncIterable<any> by defining a
discriminated union type for stream events (e.g., "text-start" | "text-delta" |
"text-end" | "tool-call-suspended" | "finish") and update `#streamEvents` to yield
that union so each yielded object structurally matches A2AAgentStreamResult;
remove the two casts (the ones wrapping assembled chunk objects) and construct
objects that satisfy A2AAgentStreamResult directly, updating any helper/emit
code in the same file to use the new discriminant and precise types.

917-1003: ⚖️ Poor tradeoff

Duplicated SSE parsing across #streamEvents and #collectStreamEvents.

Both functions independently parse the same tee()-d byte stream and reconstruct task/artifact/suspended state, with slightly different semantics (e.g., #streamEvents always emits createResumeSchema() for tool-call-suspended on line 1132, while #collectStreamEvents carries the captured resumeSchema from line 1198/1243; messages overwrite textBuffer in the accumulator but append text-delta chunks on the consumer side). Consider parsing once into a shared internal event stream and deriving both the emitted chunks and the final aggregate from it. Not blocking, but it will drift if either path is touched.

Also applies to: 1149-1276

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/a2a/a2a-agent.ts` around lines 917 - 1003, Both
`#streamEvents` and `#collectStreamEvents` duplicate SSE parsing and reconstruct
state differently, causing drift; extract the shared parsing logic into a single
internal parser (e.g., new private method `#parseA2AStreamEvents`) that consumes
the tee'd byte stream and yields canonical event objects (message-delta, task,
artifact, suspended with resumeSchema). Have `#streamEvents` and
`#collectStreamEvents` consume that canonical event async-iterator (or shared
EventEmitter/Readable) to implement their distinct behaviors (streamed deltas
vs. aggregated final state), remove duplicated parsing and the ad-hoc
createResumeSchema() call so resumeSchema from the parsed suspended event is
preserved, and update `#consumeA2AStream` to wire the parser output into both the
consumerStream path and the accumulator path.

1354-1389: ⚡ Quick win

Retry loop treats every error as transient, including non-retryable 4xx.

When retries > 0, the catch block retries on any thrown error, including the MastraA2AError.invalidAgentResponse(...) raised at line 1369 for HTTP 4xx responses (400, 401, 403, 404, 422, ...). Those statuses won't succeed on retry, so this just amplifies bad requests and authn/authz failures while also delaying the failure surfaced to the caller. Consider classifying errors so only network failures, 408, 429, and 5xx are retried.

♻️ Sketch
       } catch (error) {
         lastError = error;
 
+        const status =
+          error && typeof error === 'object' && 'status' in error && typeof (error as { status?: unknown }).status === 'number'
+            ? (error as { status: number }).status
+            : undefined;
+        const retryable =
+          status === undefined || status === 408 || status === 429 || status >= 500;
+
+        if (!retryable) {
+          throw error;
+        }
+
         if (attempts === this.#retries) {
           break;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/a2a/a2a-agent.ts` around lines 1354 - 1389, The retry loop
in the A2A request method retries on every error (including
MastraA2AError.invalidAgentResponse for 4xx), so change the catch in the method
that calls this.#fetch (the retry loop around `#fetch` in a2a-agent.ts) to only
retry transient errors: network/fetch failures (e.g., TypeError/AbortError),
HTTP 408, 429, or any 5xx status. Specifically, detect when the caught error is
a MastraA2AError (or an error object carrying a status) and if it has a numeric
status that is not 408, 429, or >=500 rethrow immediately (do not increment
attempts or delay); otherwise treat it as transient and continue with the
existing attempts increment and `#delay` logic. Ensure you still assign lastError
before rethrowing so the final throw at the end behaves the same for
non-retriable failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/a2a/a2a-agent.test.ts`:
- Around line 572-576: The wall-clock assertion using startedAt/elapsedMs is
flaky; instead make the test assert that agent.stream(...) resolves before the
SSE completion signal by racing the stream call against a watchdog/deferred that
you resolve only after the mock SSE enqueues the final chunk. Replace the
elapsedMs expect with a Promise.race pattern: start the agent.stream('Live
stream please', { runId: 'stream-run-live' }) and race it against a deferred (or
Promise) that is resolved by the SSE mock at the moment the last chunk is
enqueued; then assert that the stream promise wins the race. Reference the
existing agent.stream call and the mock SSE completion event to implement the
deferred/watchdog.

In `@packages/core/src/a2a/a2a-agent.ts`:
- Around line 112-134: The parseEventBlock function currently calls
JSON.parse(payload) without protection, so a malformed SSE chunk will throw and
abort streaming; wrap the JSON.parse(payload) call in a try/catch inside
parseEventBlock (and keep the existing payload/to-result logic) so parsing
errors are caught, log or swallow the error, and return an empty result (e.g.,
{}) to signal "skip this frame" instead of throwing; this ensures callers like
collectStreamEvents/streamEvents continue processing subsequent valid events
while preserving handling for the '[DONE]' case and JSONRPCResponse result
extraction.

---

Nitpick comments:
In @.changeset/whole-papers-throw.md:
- Around line 7-12: Update the "What changed" section to emphasize
developer-facing outcomes instead of implementation details: for the A2AAgent
entry mention the new developer capabilities (e.g., "Remote A2A execution via
generate, resumeGenerate, stream, and resumeStream" so devs know what they can
do), rephrase the Agent Card line to describe the outcome (e.g., "Verify Agent
Card signatures with pluggable key providers" rather than "in-memory caching"),
and rewrite the client subpath line to state the benefit (e.g., "Import A2A
types in browser environments via `@mastra/core/a2a/client`"); vary sentence
starts away from repeated "Added..." and prefer short outcome-focused bullets.

In `@packages/core/src/a2a/a2a-agent.ts`:
- Around line 1005-1013: The stream helper `#streamEvents` is currently typed as
AsyncIterable<any> and uses two "as unknown as A2AAgentStreamResult" casts which
bypass the A2AAgentStreamResult contract; replace the casts and the loose
AsyncIterable<any> by defining a discriminated union type for stream events
(e.g., "text-start" | "text-delta" | "text-end" | "tool-call-suspended" |
"finish") and update `#streamEvents` to yield that union so each yielded object
structurally matches A2AAgentStreamResult; remove the two casts (the ones
wrapping assembled chunk objects) and construct objects that satisfy
A2AAgentStreamResult directly, updating any helper/emit code in the same file to
use the new discriminant and precise types.
- Around line 917-1003: Both `#streamEvents` and `#collectStreamEvents` duplicate
SSE parsing and reconstruct state differently, causing drift; extract the shared
parsing logic into a single internal parser (e.g., new private method
`#parseA2AStreamEvents`) that consumes the tee'd byte stream and yields canonical
event objects (message-delta, task, artifact, suspended with resumeSchema). Have
`#streamEvents` and `#collectStreamEvents` consume that canonical event
async-iterator (or shared EventEmitter/Readable) to implement their distinct
behaviors (streamed deltas vs. aggregated final state), remove duplicated
parsing and the ad-hoc createResumeSchema() call so resumeSchema from the parsed
suspended event is preserved, and update `#consumeA2AStream` to wire the parser
output into both the consumerStream path and the accumulator path.
- Around line 1354-1389: The retry loop in the A2A request method retries on
every error (including MastraA2AError.invalidAgentResponse for 4xx), so change
the catch in the method that calls this.#fetch (the retry loop around `#fetch` in
a2a-agent.ts) to only retry transient errors: network/fetch failures (e.g.,
TypeError/AbortError), HTTP 408, 429, or any 5xx status. Specifically, detect
when the caught error is a MastraA2AError (or an error object carrying a status)
and if it has a numeric status that is not 408, 429, or >=500 rethrow
immediately (do not increment attempts or delay); otherwise treat it as
transient and continue with the existing attempts increment and `#delay` logic.
Ensure you still assign lastError before rethrowing so the final throw at the
end behaves the same for non-retriable failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 007957f3-1748-4cf9-a828-dac99cfa6e7a

📥 Commits

Reviewing files that changed from the base of the PR and between 9268531 and 9ac19fa.

📒 Files selected for processing (11)
  • .changeset/whole-papers-throw.md
  • client-sdks/client-js/src/resources/a2a.test.ts
  • client-sdks/client-js/src/resources/a2a.ts
  • client-sdks/client-js/src/utils/process-a2a-stream.ts
  • packages/core/package.json
  • packages/core/src/a2a/a2a-agent.test.ts
  • packages/core/src/a2a/a2a-agent.ts
  • packages/core/src/a2a/client.ts
  • packages/core/src/a2a/index.ts
  • packages/core/src/a2a/types.ts
  • packages/core/tsup.config.ts

Comment thread packages/core/src/a2a/a2a-agent.test.ts Outdated
Comment thread packages/core/src/a2a/a2a-agent.ts
Keep subagent badge content expanded while live and hydrated subagent output is rendered. This avoids hiding nested tool and text streams before the parent response completes.
Wrap A2AAgent stream chunks with the same runId and from=AGENT envelope used by normal subagents. This lets parent agent streams and playground rendering treat remote A2A text deltas as live nested subagent output.
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 12, 2026

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/playground/src/lib/ai-ui/tools/badges/agent-badge.tsx (1)

34-34: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused isComplete prop from interface.

The isComplete prop is defined in AgentBadgeProps but is never destructured or referenced in the component implementation. Since line 92 now hardcodes initialCollapsed={false}, this prop serves no purpose and should be removed to avoid confusion.

🧹 Proposed fix
   toolCalled?: boolean;
-  isComplete?: boolean;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/playground/src/lib/ai-ui/tools/badges/agent-badge.tsx` at line 34,
AgentBadgeProps currently defines an unused isComplete property; remove
isComplete from the AgentBadgeProps interface and any related type references so
the prop is no longer declared, and ensure the AgentBadge component continues to
use the explicit initialCollapsed={false} (no other changes needed to AgentBadge
or its JSX); update any callers only if they were passing isComplete to avoid
unused prop warnings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/playground/src/lib/ai-ui/tools/badges/agent-badge.tsx`:
- Line 34: AgentBadgeProps currently defines an unused isComplete property;
remove isComplete from the AgentBadgeProps interface and any related type
references so the prop is no longer declared, and ensure the AgentBadge
component continues to use the explicit initialCollapsed={false} (no other
changes needed to AgentBadge or its JSX); update any callers only if they were
passing isComplete to avoid unused prop warnings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3204ef06-1135-4579-80f5-19978bc3e47d

📥 Commits

Reviewing files that changed from the base of the PR and between 934d8ea and a94d6a0.

📒 Files selected for processing (4)
  • packages/core/src/a2a/a2a-agent.test.ts
  • packages/core/src/a2a/a2a-agent.ts
  • packages/playground/src/lib/ai-ui/tools/__tests__/agent-badge-falsy-output-regression.test.ts
  • packages/playground/src/lib/ai-ui/tools/badges/agent-badge.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/playground/src/lib/ai-ui/tools/tests/agent-badge-falsy-output-regression.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/a2a/a2a-agent.ts
  • packages/core/src/a2a/a2a-agent.test.ts

Update the A2AAgent changeset to describe remote A2A agents as Mastra subagents and show registration on a parent Agent.
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