Highlights
ACP Coding Agents as Tools or Subagents (New @mastra/acp)
New @mastra/acp@0.1.0 lets you run ACP-compatible coding agents as Mastra tools (createACPTool) or lightweight subagents (AcpAgent) with incremental streaming, usable anywhere Mastra accepts SubAgent (supervisors, workflows, and the Inngest adapter).
Realtime xAI Voice Provider (New @mastra/voice-xai-realtime)
New @mastra/voice-xai-realtime@0.1.0 adds a realtime voice integration for the xAI Grok Voice Agent API, enabling Agents to connect, stream audio, and run voice turns via XAIRealtimeVoice.
Agent Metadata for Filtering, Cloning, and Dynamic Resolution
Agents can now include optional metadata (static or DynamicArgument) retrievable via agent.getMetadata(), surfaced in /agents responses for client-side filtering, and preserved when cloning agents via the editor (unless overridden).
Enterprise Foundations for Admin Policies + Role-Aware Capabilities
Two new entry points (@mastra/core/agent-builder/ee and @mastra/core/auth/ee) provide building blocks for model allowlists/admin model policies and RBAC enhancements (optional IRBACProvider.getAvailableRoles() / getPermissionsForRole()), with @mastra/auth-workos implementing these methods.
Better File Handling in workspace.read_file (Native Media Parts + Safer Binaries)
read_file now returns supported media (images/PDF) as native model file/image parts (with configurable mediaTypes and maxMediaBytes), keeps text files as text, and avoids dumping unsupported/oversized binaries as base64 by returning metadata unless an explicit encoding is requested.
Observability: Lightweight Trace Listing API + Improved Retry Visibility
New GET /observability/traces/light (plus ClickHouse/DuckDB/server/client support) enables paginated trace lists without span payloads, and background-task retries now appear as separate workflow steps in run history/event traces for easier debugging.
Breaking Changes
- None noted in this changelog.
Changelog
@mastra/core@1.34.0
Minor Changes
-
You can now run ACP-compatible coding agents as Mastra tools or lightweight subagents. ACP agents support incremental response streaming and can be used anywhere Mastra accepts a
SubAgent, including supervisor delegation and workflow steps. (#16423)import { createACPTool, AcpAgent } from '@mastra/acp'; export const codingTool = createACPTool({ id: 'coding-agent', command: 'my-acp-agent', }); export const codingAgent = new AcpAgent({ id: 'coding-agent', command: 'my-acp-agent', });
You can also wire an
AcpAgentinto a supervisor or workflow as aSubAgent-compatible implementation:import { Agent } from '@mastra/core/agent'; export const supervisor = new Agent({ name: 'supervisor', instructions: 'Delegate coding tasks to the ACP agent.', model, agents: { codingAgent, }, });
Workflows and the Inngest workflow adapter now recognize
SubAgent-compatible implementations when creating agent-backed workflow steps. -
Added optional
metadatato code-defined agents. Pass ametadatarecord tonew Agent({...}), read it back withagent.getMetadata(), and clients can filter on it from the existing/agentsand/agents/:agentIdresponses without encoding the data into IDs or names. (#16603)Metadata supports the same
DynamicArgumentform as other agent config fields, so it can also be resolved per request from the request context.Stored agents loaded via the editor also expose their metadata through
agent.getMetadata(), so clients can filter these agents as well. Cloning a runtime agent viaeditor.agent.clone()now carries the source agent's metadata over to the stored clone when the caller does not provide one explicitly.// Static const supportAgent = new Agent({ id: 'support-agent', name: 'Support Agent', instructions: 'You help customers with support requests.', model: 'openai/gpt-5', metadata: { type: 'support' }, }); supportAgent.getMetadata(); // { type: 'support' } // Dynamic const tenantAgent = new Agent({ id: 'tenant-agent', name: 'Tenant Agent', instructions: 'You help customers with tenant-specific tasks.', model: 'openai/gpt-5', metadata: ({ requestContext }) => ({ type: 'support', tenant: requestContext.get('tenant'), }), }); await tenantAgent.getMetadata({ requestContext }); // { type: 'support', tenant: 'acme' }
-
Added an opt-in foundation for building agent-builder admin policies and role-aware capabilities, available under two new entry points. (#16578)
@mastra/core/agent-builder/eeExposes types, validators, and picker utilities for working with model allowlists and admin model policies on stored agents — for example normalizing model candidates, choosing a default from a configured allowlist, and producing typed errors when a request violates policy.
@mastra/core/auth/eeAdds optional methods on
IRBACProviderfor listing available roles and resolving the permissions for a given role:interface IRBACProvider { // existing methods... getAvailableRoles?(): Promise<RoleDescriptor[]>; getPermissionsForRole?(role: string): Promise<PermissionDescriptor[]>; }
Static defaults, an expanded permissions catalog, and a capabilities helper that surfaces
availableRolesto clients when the provider supports it are also included. Providers that do not implement the new methods continue to work unchanged.Also adds a
StorageBrowserRefshape to@mastra/core/storagefor referencing a configured headless browser on stored agents. -
Improved how the workspace
read_filetool returns files to the model. Reads now branch on file type: (#16570)- Media files (default:
image/png,image/jpeg,image/webp,application/pdf) are surfaced as native file/image parts the model can directly view, instead of being dumped as base64 text. Capped at 10 MiB by default so large media don't get base64-encoded into context and persisted in storage — configurable viamaxMediaBytes. - Text-readable files (anything
text/*, common code/config mime types, or unknown extensions) are returned as text content as before. - Unsupported binaries (e.g.
image/pngwhenmediaTypesis disabled,application/zip, oversized media, etc.) now return a short metadata description (path, size, mime type) instead of dumping useless base64 into the conversation. Pass an explicitencodingto opt back into the raw base64/hex dump.
The set of mime types treated as native media parts and the inline size cap are configurable per workspace:
import { Workspace, WORKSPACE_TOOLS } from '@mastra/core/workspace'; const workspace = new Workspace({ filesystem, tools: { [WORKSPACE_TOOLS.FILESYSTEM.READ_FILE]: { // Broaden to any image (e.g. SVG, BMP, HEIC) — may fail on some providers mediaTypes: ['image/*', 'application/pdf'], // Raise the inline-media cap to 25 MiB maxMediaBytes: 25 * 1024 * 1024, // Or a custom predicate // mediaTypes: (mime) => mime.startsWith('image/'), // Or disable media parts entirely // mediaTypes: false, }, }, });
The default
mediaTypesis intentionally the cross-provider-safe intersection — formats universally supported across Anthropic, OpenAI, and Gemini. - Media files (default:
-
Changed background process output retention. (#16574)
Before: Spawned process handles retained all stdout and stderr, which could grow without bound for long-running background processes.
After: Spawned process handles now retain the latest 1 MiB of stdout and stderr per stream by default. Pass
maxRetainedBytestoprocesses.spawn()to customize the limit, use0to disable retained polling output, or useInfinityto keep the previous retain-all behavior.const handle = await sandbox.processes.spawn('npm run dev', { maxRetainedBytes: 512 * 1024, });
Streaming callbacks and reader streams still receive every chunk in full. Handles also expose truncation and dropped-byte counters so callers can detect when
stdout,stderr, orwait()results only include retained output.The built-in
executeCommand()implementation still retains full output by default; passmaxRetainedBytesthere only when you want bounded command results.
Patch Changes
-
Update provider registry and model documentation with latest models and providers (
784ad98) -
Improved background-task observability. (#16590)
Retry attempts now appear as separate workflow steps in run history and event traces, making retry progression easier to debug. No public API changes.
-
Fixed approval resume for tools loaded by processor workflows. (#16365)
-
Fixed durable agents that could drop object-form system instructions when provider options like
cacheControlwere used. These instructions are now preserved so provider-specific options are respected. (#16599) -
Fixed approval resume for tools loaded with ToolSearchProcessor. (#16365)
-
Fixed listMessages perPage=0 behavior in the in-memory store to match other adapters. (#16602)
-
Fixed non-deterministic ordering of cross-thread semantic recall messages. (#16600)
When messages recalled from other threads shared the same timestamp, they were rendered into the system prompt in whatever order the vector query returned them — driven by similarity scores that can vary between equivalent runs. This made any test or evaluation that snapshots prompt output (or hashes the outbound LLM request) flaky.
Recalled cross-thread messages are now sorted by createdAt, then threadId, then role (user → assistant → tool → system), then id before formatting, so the same set of recalled messages always produces the same prompt.
-
Expose
GET /observability/traces/lightand storage support for fetching paginated trace-list rows without span payload data. (#16608) -
GET /api/observability/discovery/metric-namesandGET /api/observability/discovery/metric-label-valuesnow acceptlimitas a URL query parameter without pre-parsing. Previously, passing?limit=10was rejected as a validation error; callers can now use these endpoints directly from HTTP clients, consistent with other query endpoints (e.g. pagination). (#16489) -
Fixed agent signals so standalone agents coordinate thread streams through a shared runtime. (#16581)
@mastra/acp@0.1.0
Minor Changes
-
You can now run ACP-compatible coding agents as Mastra tools or lightweight subagents. ACP agents support incremental response streaming and can be used anywhere Mastra accepts a
SubAgent, including supervisor delegation and workflow steps. (#16423)import { createACPTool, AcpAgent } from '@mastra/acp'; export const codingTool = createACPTool({ id: 'coding-agent', command: 'my-acp-agent', }); export const codingAgent = new AcpAgent({ id: 'coding-agent', command: 'my-acp-agent', });
You can also wire an
AcpAgentinto a supervisor or workflow as aSubAgent-compatible implementation:import { Agent } from '@mastra/core/agent'; export const supervisor = new Agent({ name: 'supervisor', instructions: 'Delegate coding tasks to the ACP agent.', model, agents: { codingAgent, }, });
Workflows and the Inngest workflow adapter now recognize
SubAgent-compatible implementations when creating agent-backed workflow steps.
Patch Changes
@mastra/auth-workos@1.3.0
Minor Changes
-
Added optional
getAvailableRolesandgetPermissionsForRolemethods to the WorkOS RBAC provider, so consumers can list configured roles and inspect their permissions through@mastra/auth-workos. (#16578)import { MastraRBACWorkos } from '@mastra/auth-workos'; const rbac = new MastraRBACWorkos({ /* config */ }); // List all available roles const roles = await rbac.getAvailableRoles(); // [{ id: 'admin', name: 'Admin' }, { id: 'member', name: 'Member' }] // Get permissions for a specific role const permissions = await rbac.getPermissionsForRole('member'); // ['agents:read', 'workflows:read']
Patch Changes
@mastra/clickhouse@1.7.2
Patch Changes
- Expose
GET /observability/traces/lightand storage support for fetching paginated trace-list rows without span payload data. (#16608)
@mastra/client-js@1.19.0
Minor Changes
-
Added optional
metadatato code-defined agents. Pass ametadatarecord tonew Agent({...}), read it back withagent.getMetadata(), and clients can filter on it from the existing/agentsand/agents/:agentIdresponses without encoding the data into IDs or names. (#16603)Metadata supports the same
DynamicArgumentform as other agent config fields, so it can also be resolved per request from the request context.Stored agents loaded via the editor also expose their metadata through
agent.getMetadata(), so clients can filter these agents as well. Cloning a runtime agent viaeditor.agent.clone()now carries the source agent's metadata over to the stored clone when the caller does not provide one explicitly.// Static const supportAgent = new Agent({ id: 'support-agent', name: 'Support Agent', instructions: 'You help customers with support requests.', model: 'openai/gpt-5', metadata: { type: 'support' }, }); supportAgent.getMetadata(); // { type: 'support' } // Dynamic const tenantAgent = new Agent({ id: 'tenant-agent', name: 'Tenant Agent', instructions: 'You help customers with tenant-specific tasks.', model: 'openai/gpt-5', metadata: ({ requestContext }) => ({ type: 'support', tenant: requestContext.get('tenant'), }), }); await tenantAgent.getMetadata({ requestContext }); // { type: 'support', tenant: 'acme' }
Patch Changes
- Expose
GET /observability/traces/lightand storage support for fetching paginated trace-list rows without span payload data. (#16608)
@mastra/docker@0.2.0
Minor Changes
-
Docker sandbox containers now support resource limits and security hardening through Docker HostConfig options. Configure memory, CPU quota, process IDs, capabilities, security options, read-only root filesystems, and tmpfs mounts. (#16577)
const sandbox = new DockerSandbox({ memory: 512 * 1024 * 1024, memorySwap: 512 * 1024 * 1024, cpuQuota: 100_000, pidsLimit: 256, readonlyRootfs: true, capDrop: ['ALL'], securityOpt: ['no-new-privileges:true'], });
Patch Changes
@mastra/duckdb@1.3.2
Patch Changes
- Expose
GET /observability/traces/lightand storage support for fetching paginated trace-list rows without span payload data. (#16608)
@mastra/editor@0.8.0
Minor Changes
-
Added optional
metadatato code-defined agents. Pass ametadatarecord tonew Agent({...}), read it back withagent.getMetadata(), and clients can filter on it from the existing/agentsand/agents/:agentIdresponses without encoding the data into IDs or names. (#16603)Metadata supports the same
DynamicArgumentform as other agent config fields, so it can also be resolved per request from the request context.Stored agents loaded via the editor also expose their metadata through
agent.getMetadata(), so clients can filter these agents as well. Cloning a runtime agent viaeditor.agent.clone()now carries the source agent's metadata over to the stored clone when the caller does not provide one explicitly.// Static const supportAgent = new Agent({ id: 'support-agent', name: 'Support Agent', instructions: 'You help customers with support requests.', model: 'openai/gpt-5', metadata: { type: 'support' }, }); supportAgent.getMetadata(); // { type: 'support' } // Dynamic const tenantAgent = new Agent({ id: 'tenant-agent', name: 'Tenant Agent', instructions: 'You help customers with tenant-specific tasks.', model: 'openai/gpt-5', metadata: ({ requestContext }) => ({ type: 'support', tenant: requestContext.get('tenant'), }), }); await tenantAgent.getMetadata({ requestContext }); // { type: 'support', tenant: 'acme' }
Patch Changes
- Fixed stored agent tool overrides so conditional tool configuration no longer recursively calls the forked agent when merging code-defined tools. (#16544)
@mastra/inngest@1.4.1
Patch Changes
-
You can now run ACP-compatible coding agents as Mastra tools or lightweight subagents. ACP agents support incremental response streaming and can be used anywhere Mastra accepts a
SubAgent, including supervisor delegation and workflow steps. (#16423)import { createACPTool, AcpAgent } from '@mastra/acp'; export const codingTool = createACPTool({ id: 'coding-agent', command: 'my-acp-agent', }); export const codingAgent = new AcpAgent({ id: 'coding-agent', command: 'my-acp-agent', });
You can also wire an
AcpAgentinto a supervisor or workflow as aSubAgent-compatible implementation:import { Agent } from '@mastra/core/agent'; export const supervisor = new Agent({ name: 'supervisor', instructions: 'Delegate coding tasks to the ACP agent.', model, agents: { codingAgent, }, });
Workflows and the Inngest workflow adapter now recognize
SubAgent-compatible implementations when creating agent-backed workflow steps.
@mastra/memory@1.18.1
Patch Changes
-
Added a public escape hatch so callers can supply an authoritative token estimate for file parts whose binary payload has been stripped before persistence (for example, files uploaded to cloud storage with a hidden reference token left in
dataand re-hydrated by LLM middleware before inference). (#16565)For those pipelines TokenCounter has no on-device file size to measure, so Observational Memory thresholds and context budgets undercount large attachments. Callers can now stamp an estimate directly on the part:
part.providerMetadata = { mastra: { tokenEstimate: { v: 0, source: 'client', key: 'client', tokens: 25_000 }, }, };
When present, TokenCounter returns those tokens from both the sync and async paths and skips provider fetches. Invalid entries (NaN, negative, non-numeric) fall through to the default estimator. Parts without a client estimate are unaffected.
Related to #16522
@mastra/nestjs@0.1.5
Patch Changes
-
Fixed
@mastra/nestjscoercing query parameter values to booleans,null, numbers, and parsed JSON objects/arrays before route schema validation. A route declaringqueryParamSchema: z.object({ filter: z.string() })could reject a valid request like?filter={"a":1}because the adapter had already turned the string into an object. NestJS now forwards query values as the raw strings (or string arrays) the HTTP layer delivered — matching@mastra/hono,@mastra/express,@mastra/fastify, and@mastra/koa. (#16268)Routes that want type coercion should opt in via the schema, e.g.
z.coerce.boolean(),z.coerce.number(), or a JSON preprocessor on the field.Fixes #16114.
@mastra/playground-ui@28.0.0
Minor Changes
- Added a List mode filter to the Observability traces page for switching between Traces and Branches mode, and changed the default to Traces mode. Previously, the page opened in Branches mode; now it opens in Traces mode, and users can switch modes via the new "List mode" property in the Add filter menu. For example: open Observability → Traces (now defaults to Traces) → Add filter → List mode → pick Branches or Traces. (#16587)
Patch Changes
-
Removed the inset top gloss from the
shadow-dialogtoken. The gloss read as a faint highlight band along the top edge of dropdown menus, popovers, selects, comboboxes, dialogs, tooltips, side dialogs and the main app container in dark mode. The token now applies a drop-shadow only and is consistent across light and dark themes. (#16544) -
Restyled
MainSidebarand swapped sidebar icons to the new Figma design system set. (#16544)- Section titles are larger and medium-weight (
text-ui-sm,font-medium), lowercase, muted — replacing the previous uppercase + wide-tracking treatment. Underline divider beneath the title removed in both expanded and collapsed states. Active indicator bar on the left edge removed. - Nav items render flush: icons align horizontally with the section title, hover/active state now uses theme-aware sidebar surface tokens without item borders or shadows. The legacy
indentoption is still accepted but no longer changes layout. - New sidebar icons:
WorkspacesIcon,RequestContextIcon,ScorersIcon,DatasetsIcon,ExperimentsIcon,MetricsIcon. Existing iconsAgentIcon,PromptIcon,WorkflowIcon,ProcessorIcon,McpServerIcon,ToolsIcon,LogsIcon,TraceIconupdated to match the Figma artwork. All icons acceptReact.SVGProps<SVGSVGElement>and inherit color viacurrentColor.
- Section titles are larger and medium-weight (
-
Improved Studio main content framing, persistent page breadcrumbs, accessible page headings, panel layering, and theme-aware navigation/card contrast. (#16544)
-
Fixed a React/React DOM version mismatch that prevented Storybook from rendering in
@mastra/playground-ui. (#16529)
@mastra/server@1.34.0
Minor Changes
-
Added optional
metadatato code-defined agents. Pass ametadatarecord tonew Agent({...}), read it back withagent.getMetadata(), and clients can filter on it from the existing/agentsand/agents/:agentIdresponses without encoding the data into IDs or names. (#16603)Metadata supports the same
DynamicArgumentform as other agent config fields, so it can also be resolved per request from the request context.Stored agents loaded via the editor also expose their metadata through
agent.getMetadata(), so clients can filter these agents as well. Cloning a runtime agent viaeditor.agent.clone()now carries the source agent's metadata over to the stored clone when the caller does not provide one explicitly.// Static const supportAgent = new Agent({ id: 'support-agent', name: 'Support Agent', instructions: 'You help customers with support requests.', model: 'openai/gpt-5', metadata: { type: 'support' }, }); supportAgent.getMetadata(); // { type: 'support' } // Dynamic const tenantAgent = new Agent({ id: 'tenant-agent', name: 'Tenant Agent', instructions: 'You help customers with tenant-specific tasks.', model: 'openai/gpt-5', metadata: ({ requestContext }) => ({ type: 'support', tenant: requestContext.get('tenant'), }), }); await tenantAgent.getMetadata({ requestContext }); // { type: 'support', tenant: 'acme' }
Patch Changes
-
Expose
GET /observability/traces/lightand storage support for fetching paginated trace-list rows without span payload data. (#16608) -
GET /api/observability/discovery/metric-namesandGET /api/observability/discovery/metric-label-valuesnow acceptlimitas a URL query parameter without pre-parsing. Previously, passing?limit=10was rejected as a validation error; callers can now use these endpoints directly from HTTP clients, consistent with other query endpoints (e.g. pagination). (#16489) -
Fixed agent signal wakeups so idle runs receive request context values while preserving server-owned resource identifiers. (#16557)
@mastra/voice-xai-realtime@0.1.0
Minor Changes
-
Added
@mastra/voice-xai-realtime, a realtime voice provider for the xAI Grok Voice Agent API. (#16507)Use
XAIRealtimeVoicewith Mastra'sAgentvoice primitive to connect, stream audio, and run xAI voice turns:import { Agent } from '@mastra/core/agent'; import { XAIRealtimeVoice } from '@mastra/voice-xai-realtime'; const voice = new XAIRealtimeVoice({ apiKey: process.env.XAI_API_KEY, model: 'grok-voice-think-fast-1.0', speaker: 'eve', turnDetection: { type: 'server_vad' }, }); const agent = new Agent({ id: 'voice-agent', name: 'Voice Agent', instructions: 'You are a helpful voice assistant.', model: 'xai/grok-4.3', voice, }); await agent.voice.connect(); agent.voice.on('speaker', audioStream => playAudio(audioStream)); await agent.voice.speak('How can I help you today?'); await agent.voice.send(microphoneStream);
Patch Changes
Other updated packages
The following packages were updated with dependency changes only:
- @mastra/agent-builder@1.0.35
- @mastra/deployer@1.34.0
- @mastra/deployer-cloud@1.34.0
- @mastra/deployer-cloudflare@1.1.35
- @mastra/deployer-netlify@1.1.11
- @mastra/deployer-vercel@1.1.29
- @mastra/express@1.3.21
- @mastra/fastify@1.3.21
- @mastra/hono@1.4.16
- @mastra/koa@1.5.4
- @mastra/longmemeval@1.0.40
- @mastra/mcp-docs-server@1.1.37
- @mastra/opencode@0.0.37
- @mastra/react@0.3.2
- @mastra/temporal@0.1.4