Mastra now supports relationship-based, resource-level authorization with centralized enforcement before agent runs (generate()/stream()), tool/workflow execution, and memory thread access via new IFGAProvider/IFGAManager + checkFGA()/FGADeniedError. FGA is also enforced consistently in @mastra/server handlers, all built-in server adapters (Express/Fastify/Hono/Koa), and MCP tool execution.
@mastra/auth-workos)New MastraFGAWorkos implements IFGAManager on top of the WorkOS Authorization API, including check/require/filterAccessible, resource CRUD, role assignments, org scoping, JWT/bearer-token context handling, and permission/resource mappings for multi-tenant setups.
Workflows can now declare schedule in createWorkflow() to run on cron with automatic promotion to the evented engine, type-checked inputData/initialState/requestContext, and safe multi-instance claiming (CAS) via WorkflowScheduler. End-to-end support includes new schedules storage domains/adapters (PG/LibSQL/MongoDB + in-memory for tests), new @mastra/server routes + @mastra/client-js schedule methods, and new Studio UI for listing schedules, viewing trigger history, and durable pause/resume.
MCP servers can now publish ui:// HTML app resources via appResources, with new listResources()/readResource() on MCPServerBase and client/server endpoints (MastraClient.getMcpServerResources() / readMcpServerResource(), plus @mastra/server routes). @mastra/mcp adds proxy helpers (MCPClientServerProxy, toMCPServerProxies()) and stamps serverId into tool metadata to support multi-server UI resolution.
New listBranches/getBranch (plus getSpans and getStructure) let you find and fetch runs even when an entity only appears as a nested span (not root traces), with corresponding HTTP endpoints and store implementations (ClickHouse/DuckDB). Metrics now support count_distinct plus server-side TopK (limit, ordering) for fast dashboards on high-cardinality fields; ClickHouse also adds skip indexes to speed drilldowns, and a new DatadogBridge keeps auto-instrumented spans correctly nested under Mastra spans.
mastra_schedules, mastra_schedule_triggers): adds ownerType/ownerId, renames ScheduleTrigger.status → outcome, adds trigger id PK plus triggerKind/parentTriggerId/metadata; GET /api/schedules/:id/triggers now returns outcome instead of status (no compat shim; scheduled workflows are alpha).@mastra/client-js Vector return types changed to match runtime:
vector.getIndexes() → string[] (was { indexes: string[] })vector.upsert() → { ids: string[] } (was string[])vector.query() → QueryResult[] (was { results: QueryResult[] })Added Fine-Grained Authorization (FGA) support for relationship-based, resource-level access control. FGA answers "can this user perform this action on this specific resource?" — enabling multi-tenant isolation and per-resource permissions. (#15410)
New interfaces: IFGAProvider (read-only checks) and IFGAManager (read + write operations) with types for access checks, resources, and role assignments.
Enforcement at all execution points: FGA checks are automatically enforced before agent execution (generate(), stream()), tool execution, workflow execution, and memory thread access. When no FGA provider is configured, all checks are skipped (backward compatible).
New utility: checkFGA() provides centralized FGA enforcement with FGADeniedError for denied checks. MastraMemory.checkThreadFGA() adds thread-level access control.
Request-aware authorization: Resource ID resolvers receive request context so route-level FGA checks can derive tenant- or request-scoped resource IDs.
Typed permission constants: Strongly-typed permission identifiers (e.g. 'agents:execute', 'workflows:execute', 'memory:threads:read') for use in authorization config and permissionMapping.
const mastra = new Mastra({
server: {
fga: new MastraFGAWorkos({ apiKey, clientId }),
},
});
Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added listResources() and readResource() abstract methods to MCPServerBase, enabling MCP servers to expose app resources. These resources power interactive UI rendering (MCP Apps) in Studio and other consumers. (#16004)
Added count_distinct aggregation and server-side TopK to the metrics storage API so dashboards built on high-cardinality fields (like threadId or resourceId) stay fast and bounded. (#16137)
New aggregation
getMetricAggregate, getMetricBreakdown, and getMetricTimeSeries accept aggregation: 'count_distinct' with a distinctColumn. Backends pick the most efficient native implementation — uniq on ClickHouse, approx_count_distinct on DuckDB.
distinctColumn is restricted to a low/medium-cardinality categorical allowlist (entityType, entityName, parentEntityType, parentEntityName, rootEntityType, rootEntityName, name, provider, model, environment, executionSource, serviceName). ID columns are not allowed — distinct counts over near-unique values converge to the row count and are rarely useful.
await store.getMetricAggregate({
name: ['mastra_llm_tokens_total'],
aggregation: 'count_distinct',
distinctColumn: 'model',
filters: { timestamp: { start, end } },
});
Server-side TopK
getMetricBreakdown accepts limit and orderDirection, so breakdowns never return the full cardinality of a column from the database. Ordering is always by the aggregated value; orderDirection flips between top-N (DESC, default) and bottom-N (ASC).
await store.getMetricBreakdown({
name: ['mastra_agent_duration_ms'],
aggregation: 'sum',
groupBy: ['threadId'],
limit: 20,
orderDirection: 'DESC',
});
Added RegexFilterProcessor — a zero-cost regex-based content filter for blocking, redacting, or warning on pattern matches in agent messages. Includes built-in presets for PII, secrets, URLs, and prompt injection patterns. Supports input, output, and streaming phases. (#16058)
Added scheduled workflows. Declare a schedule on createWorkflow and Mastra fires the workflow on cron with no extra wiring. (#15830)
import { createWorkflow } from '@mastra/core/workflows';
const dailyReport = createWorkflow({
id: 'daily-report',
inputSchema: z.object({ date: z.string() }),
outputSchema: z.object({ summary: z.string() }),
schedule: {
cron: '0 9 * * *',
timezone: 'America/Los_Angeles',
inputData: { date: 'today' },
},
})
.then(/* steps */)
.commit();
A workflow with a schedule is auto-promoted to the evented engine, so scheduled fires share the same execution path as manual start() calls. inputData, initialState, and requestContext on the schedule are type-checked against the workflow's schemas at definition time. Pass an array of schedules with stable ids to fire one workflow on multiple crons.
Mastra auto-instantiates a WorkflowScheduler when any registered workflow declares a schedule. The scheduler claims due schedules via compare-and-swap, so multiple instances polling the same storage cannot double-fire. Projects with no scheduled workflows pay zero cost. Configure with new Mastra({ scheduler: { tickIntervalMs, batchSize, enabled, onError } }).
Requires a storage adapter that implements the new schedules domain (@mastra/libsql and @mastra/pg ship adapters; InMemorySchedulesStorage is included for tests). Adds a croner dependency.
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Added CostGuardProcessor, a built-in processor for enforcing monetary cost limits across agent runs. Supports run, resource, and thread scopes with configurable time windows (default 7 days), blocking or warning when limits are reached. Also added onViolation callback to the base Processor interface for generalized violation handling across all processors. (#16057)
import { Agent } from '@mastra/core/agent';
import { CostGuardProcessor } from '@mastra/core/processors';
const costGuard = new CostGuardProcessor({
maxCost: 5.0,
scope: 'resource',
window: '24h',
strategy: 'block',
});
costGuard.onViolation = ({ processorId, message, detail }) => {
console.log(`[${processorId}] ${message}`, detail);
};
const agent = new Agent({
name: 'my-agent',
model: 'openai/gpt-5-nano',
inputProcessors: [costGuard],
});
Added listBranches and getBranch for querying named-entity invocations across traces, including nested ones. listTraces only returns root-rooted traces, so an entity that always runs as a child (e.g., an Observer agent inside a workflow) wasn't queryable before. (#16154)
// Before: nested-only entities returned nothing
await store.listTraces({ filters: { entityName: 'Observer' } }); // []
// After: one row per AGENT_RUN, WORKFLOW_RUN, PROCESSOR_RUN, SCORER_RUN,
// RAG_INGESTION, TOOL_CALL, or MCP_TOOL_CALL span
await store.listBranches({ filters: { entityName: 'Observer' } });
// Plus: fetch the subtree at any span, with optional depth
const branch = await store.getBranch({ traceId, spanId, depth: 1 });
Added getStructure({ traceId }) (canonical name for the lightweight trace skeleton; getTraceLight retained as a deprecated alias) and getSpans({ traceId, spanIds }) (batch-fetch spans by id, used internally by getBranch to avoid pulling whole traces).
Update provider registry and model documentation with latest models and providers (6dcd65f)
Fixed Harness token usage so provider-reported totals, reasoning tokens, and cache token fields are preserved. Fixes https://github.com/mastra-ai/mastra/issues/16055 (#16072)
Fixed supervisor output processors so they can filter streamed chunks from delegated sub-agents. (#16071)
Fixed Observational Memory model resolution for user-defined gateways. Models such as cloudflare/google/gemini-2.5-flash-lite now resolve through registered gateways instead of failing with provider-config errors. Closes #13841. (#16083)
Fixed model step traces to show the final prompt sent to the model, including memory-injected system messages. (#16029)
Fixed tool results dropping provider metadata from the original tool call. (#16078)
Fixed workflow request context serialization to skip values that cannot be safely stored as JSON. Fixes #16043. (#16061)
Fix buildResumedBlockResult returning suspended instead of failed when a step throws after resume in a parallel or conditional block (#14410)
Fixed serializeRequestContext to handle plain Map instances passed as requestContext, restoring backward compatibility broken in #16061 (#16081)
Added direct score lookup support to observability storage so score records can be fetched by scoreId without scanning paginated score lists, including DuckDB and ClickHouse vNext observability stores. (#16162)
fix(harness): use type 'image' and mimeType for image parts in convertToHarnessMessage to fix Gemini image recognition (#13917)
Fixed TokenLimiterProcessor failing silently when no input messages fit the token budget. (#16063)
Added MastraFGAWorkos provider for Fine-Grained Authorization using the WorkOS Authorization API. Implements IFGAManager interface with support for: (#15410)
check(), require(), filterAccessible())createResource(), getResource(), listResources(), updateResource(), deleteResource())assignRole(), removeRole(), listRoleAssignments())resourceMapping and permissionMapping for translating Mastra resource types and permissions to WorkOS resource type slugs and permission slugspermissionMappingimport { MastraFGAWorkos } from '@mastra/auth-workos';
const fga = new MastraFGAWorkos({
organizationId: 'org_abc123',
resourceMapping: {
agent: { fgaResourceType: 'team', deriveId: ctx => ctx.user.teamId },
},
permissionMapping: {
'agents:execute': 'manage-workflows',
},
});
// Check whether a user can execute an agent
const allowed = await fga.check(user, {
resource: { type: 'agent', id: 'my-agent' },
permission: 'agents:execute',
});
Improved metric drilldown performance with skip indexes on the high-cardinality ID columns of metric_events. Dashboard queries that filter metrics by traceId, threadId, resourceId, userId, organizationId, experimentId, runId, sessionId, or requestId skip data chunks that don't contain the filtered value instead of scanning the full time range. (#16138)
Equality (=) and IN filters benefit automatically. Aggregations and GROUP BY queries without a filter on these columns are unaffected.
Migration
Existing deployments pick up the indexes on next start. The migration is metadata-only and instant — no table lock, no rewrite, no downtime. Insert overhead is negligible and index storage is well under 1% of table size. Existing data is indexed lazily as parts merge under normal retention; no operator action is required.
Added count_distinct aggregation and server-side TopK to the metrics storage API so dashboards built on high-cardinality fields (like threadId or resourceId) stay fast and bounded. (#16137)
New aggregation
getMetricAggregate, getMetricBreakdown, and getMetricTimeSeries accept aggregation: 'count_distinct' with a distinctColumn. Backends pick the most efficient native implementation — uniq on ClickHouse, approx_count_distinct on DuckDB.
distinctColumn is restricted to a low/medium-cardinality categorical allowlist (entityType, entityName, parentEntityType, parentEntityName, rootEntityType, rootEntityName, name, provider, model, environment, executionSource, serviceName). ID columns are not allowed — distinct counts over near-unique values converge to the row count and are rarely useful.
await store.getMetricAggregate({
name: ['mastra_llm_tokens_total'],
aggregation: 'count_distinct',
distinctColumn: 'model',
filters: { timestamp: { start, end } },
});
Server-side TopK
getMetricBreakdown accepts limit and orderDirection, so breakdowns never return the full cardinality of a column from the database. Ordering is always by the aggregated value; orderDirection flips between top-N (DESC, default) and bottom-N (ASC).
await store.getMetricBreakdown({
name: ['mastra_agent_duration_ms'],
aggregation: 'sum',
groupBy: ['threadId'],
limit: 20,
orderDirection: 'DESC',
});
listBranches and getSpans implementations. (#16154)listBranches; historical traces remain accessible through the existing listTraces / getTrace APIs.scoreId without scanning paginated score lists, including DuckDB and ClickHouse vNext observability stores. (#16162)Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added getMcpServerResources() and readMcpServerResource() methods to MastraClient for listing and reading MCP server resources from the client SDK. These methods enable frontend applications to fetch app resource HTML for interactive MCP Apps rendering. (#16004)
const client = new MastraClient();
// List resources on an MCP server
const resources = await client.getMcpServerResources('my-server');
// Read a specific app resource
const resource = await client.readMcpServerResource('my-server', 'ui://calculator/app');
Added schedule methods to the client for the new scheduled workflows feature. (#15830)
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:4111' });
const schedules = await client.listSchedules({ workflowId: 'daily-report' });
const schedule = await client.getSchedule('wf_daily-report');
const triggers = await client.listScheduleTriggers('wf_daily-report', { limit: 50 });
await client.pauseSchedule('wf_daily-report');
await client.resumeSchedule('wf_daily-report');
Pause is durable across redeploys. Resume recomputes the next fire time from now so a long-paused schedule does not fire a backlog.
Added listBranches and getBranch endpoints. Use these to find specific runs of an agent, workflow, tool, or processor — even when they are nested inside another trace — and to fetch the subtree of spans rooted at any single span. (#16177)
GET /observability/branches?spanType=agent_run&entityName=Observer
GET /observability/traces/:traceId/branches/:spanId?depth=1
Each row in listBranches is a single anchor span (one of AGENT_RUN, WORKFLOW_RUN, PROCESSOR_RUN, SCORER_RUN, RAG_INGESTION, TOOL_CALL, MCP_TOOL_CALL), so entities that always run as a child (e.g., an Observer agent inside a workflow) — previously not listable through listTraces — are now queryable via the HTTP API. getBranch accepts an optional depth (0 = anchor only; omitted = full subtree).
Follow-up to https://github.com/mastra-ai/mastra/pull/16154 which added the underlying @mastra/core storage APIs.
Fixed Vector resource return types so they match what the server actually returns. Previously the types declared shapes that did not exist at runtime, leading to runtime failures with no TypeScript errors. (#16036)
What changed
vector.getIndexes() now returns string[] (was { indexes: string[] })vector.upsert() now returns { ids: string[] } (was string[])vector.query() now returns QueryResult[] (was { results: QueryResult[] })Before
const response = await client.getVector('docs').getIndexes();
console.log(response.indexes); // undefined at runtime
After
const indexes = await client.getVector('docs').getIndexes();
console.log(indexes[0]); // 'docs-index'
Closes #15089.
Fixed client stream handling for step completion and finish chunks that omit step result details. (#9146)
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Added server-generated route contract types for the JavaScript client SDK and updated the SDK to use those generated request and response types. (#15519)
Fixed @mastra/convex workflow snapshot persistence when snapshots contain $-prefixed JSON Schema keys (for example $schema and $ref). (#16169)
Snapshots are now stored safely, preventing Convex validation failures during workflow runs. Fixes #16110.
Improved Convex bulk insert and delete throughput. (#16149)
Added a new DatadogBridge integration for Mastra tracing so Datadog can keep auto-instrumented HTTP, database, and framework spans nested under the agent, workflow, model, and tool spans that triggered them. (#15716)
import tracer from 'dd-trace';
tracer.init({
service: process.env.DD_SERVICE || 'my-mastra-app',
env: process.env.DD_ENV || 'production',
});
import { Mastra } from '@mastra/core';
import { Observability } from '@mastra/observability';
import { DatadogBridge } from '@mastra/datadog';
const mastra = new Mastra({
observability: new Observability({
configs: {
default: {
serviceName: 'my-mastra-app',
bridge: new DatadogBridge({
mlApp: process.env.DD_LLMOBS_ML_APP!,
}),
},
},
}),
});
listBranches and getSpans implementations. (#16154)Added count_distinct aggregation and server-side TopK to the metrics storage API so dashboards built on high-cardinality fields (like threadId or resourceId) stay fast and bounded. (#16137)
New aggregation
getMetricAggregate, getMetricBreakdown, and getMetricTimeSeries accept aggregation: 'count_distinct' with a distinctColumn. Backends pick the most efficient native implementation — uniq on ClickHouse, approx_count_distinct on DuckDB.
distinctColumn is restricted to a low/medium-cardinality categorical allowlist (entityType, entityName, parentEntityType, parentEntityName, rootEntityType, rootEntityName, name, provider, model, environment, executionSource, serviceName). ID columns are not allowed — distinct counts over near-unique values converge to the row count and are rarely useful.
await store.getMetricAggregate({
name: ['mastra_llm_tokens_total'],
aggregation: 'count_distinct',
distinctColumn: 'model',
filters: { timestamp: { start, end } },
});
Server-side TopK
getMetricBreakdown accepts limit and orderDirection, so breakdowns never return the full cardinality of a column from the database. Ordering is always by the aggregated value; orderDirection flips between top-N (DESC, default) and bottom-N (ASC).
await store.getMetricBreakdown({
name: ['mastra_agent_duration_ms'],
aggregation: 'sum',
groupBy: ['threadId'],
limit: 20,
orderDirection: 'DESC',
});
Improved performance of listTraces and listBranches on DuckDB. The Traces and Branches lists in the observability UI now load noticeably faster, especially on large span tables, because filtering and pagination happen up front and the store only assembles full span data for the rows on the page being viewed. (#16165)
No API or behavior changes — return shapes and filter semantics are unchanged, and no migration is required.
Added direct score lookup support to observability storage so score records can be fetched by scoreId without scanning paginated score lists, including DuckDB and ClickHouse vNext observability stores. (#16162)
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Improved the Koa adapter to make request routing more efficient as route counts grow. (#16050)
Requests now move through a leaner routing path with lower middleware overhead, which helps Koa-based Mastra servers stay faster and produce cleaner request traces without changing the public API.
Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added the schedules storage domain so LibSQL-backed Mastra apps can use scheduled workflows. Creates mastra_schedules and mastra_schedule_triggers tables on init. (#15830)
Added MCP Apps support for interactive UI rendering over MCP. (#16004)
MCPClientServerProxy — a lightweight proxy that delegates resource and tool operations to remote MCP servers via MCPClient, enabling Studio to fetch app resources from any connected server.
toMCPServerProxies() — new convenience method on MCPClient that creates proxy objects for all configured servers, ready for Mastra-level registration.
Automatic serverId stamping — tools returned by listTools() now carry _meta.ui.serverId, allowing consumers to resolve ui:// app resources from the correct MCP server in multi-server environments.
const mcp = new MCPClient({
servers: {
myApps: { url: new URL('https://my-mcp-server.example.com/mcp') },
},
});
const mastra = new Mastra({
agents: { myAgent },
mcpServers: { ...mcp.toMCPServerProxies() },
});
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Added Fine-Grained Authorization (FGA) enforcement to MCP tool execution. Both transport-driven calls and direct executeTool() calls now run the same authorization checks when a request user is present, and typed FGA permission constants are accepted in MCP server authorization config. (#15410)
Fixed trace parenting for long-lived MCP Stream connections. (#15716)
Fixed Observational Memory model resolution for user-defined gateways. Models such as cloudflare/google/gemini-2.5-flash-lite now resolve through registered gateways instead of failing with provider-config errors. Closes #13841. (#16083)
Fixed async reflection buffering incorrectly triggering during idle timeout and provider-change activations when observation tokens are below the reflection activation threshold (#16076)
Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added the schedules storage domain so MongoDB-backed Mastra apps can use scheduled workflows. Creates mastra_schedules and mastra_schedule_triggers collections on init, with default indexes on (status, next_fire_at) for due-schedule polling and (schedule_id, actual_fire_at) for trigger-history queries. (#15830)
Fixed model step traces to show the final prompt sent to the model, including memory-injected system messages. (#16029)
Added a new DatadogBridge integration for Mastra tracing so Datadog can keep auto-instrumented HTTP, database, and framework spans nested under the agent, workflow, model, and tool spans that triggered them. (#15716)
import tracer from 'dd-trace';
tracer.init({
service: process.env.DD_SERVICE || 'my-mastra-app',
env: process.env.DD_ENV || 'production',
});
import { Mastra } from '@mastra/core';
import { Observability } from '@mastra/observability';
import { DatadogBridge } from '@mastra/datadog';
const mastra = new Mastra({
observability: new Observability({
configs: {
default: {
serviceName: 'my-mastra-app',
bridge: new DatadogBridge({
mlApp: process.env.DD_LLMOBS_ML_APP!,
}),
},
},
}),
});
Reduced startup noise: CloudExporter missing-token message is now logged at debug level instead of warn, since being disabled is the expected state for local development (#16070)
Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added the schedules storage domain so Postgres-backed Mastra apps can use scheduled workflows. Creates mastra_schedules and mastra_schedule_triggers tables on init, with default indexes on (status, next_fire_at) for due-schedule polling and (schedule_id, actual_fire_at) for trigger-history queries. (#15830)
Improved the NoLogsInfo empty state. It now accepts optional datePreset, dateFrom, and dateTo props to show why no logs match the active range, suggests lowering the logging level, and links to the docs. Calling <NoLogsInfo /> without props keeps the original copy. (#16139)
Removed the deprecated Notification component. Use Notice for inline persistent context (errors, empty states) and toast (from @mastra/playground-ui's sonner wrapper) for transient feedback (success messages, confirmations). (#16033)
// Before
<Notification isVisible={true} type="error">Failed to load.</Notification>
// After — inline persistent context
<Notice variant="destructive">Failed to load.</Notice>
// Before
<Notification isVisible={true}>Saved successfully!</Notification>
// After — transient feedback
toast.info('Saved successfully');
Added Studio UI for scheduled workflows. (#15830)
/workflows/schedules lists every schedule across the project with the most recent run's status. Append ?workflowId=<id> to filter to a single workflow./workflows/schedules/:scheduleId shows the schedule's metadata, Pause/Resume controls, and paginated trigger history. Each trigger is deep-linked to its workflow run graph. The view polls every five seconds while any fired run is still active.Added SectionCard component to design system. Provides card primitive with tinted header strip (title, description, optional action slot), transparent body, and default/danger variants. Composes CardHeading for typography. Suitable for settings pages, dashboard sections, and grouped form layouts. (#16168)
import { SectionCard } from '@mastra/playground-ui';
<SectionCard title="Theme" description="Customize the appearance.">
<ThemeSelector />
</SectionCard>;
Redesigned the span token usage panel to show input vs output split with proportional bar and per-side detail breakdowns. DataKeysAndValues gained an optional density='dense' prop. (#16143)
Removed the CombinedButtons component. Use ButtonsGroup with spacing="close" for the same segmented-style cluster of toggle buttons. (#16035)
// Before
<CombinedButtons>
<Button>Agent</Button>
<Button>Model</Button>
</CombinedButtons>
// After
<ButtonsGroup spacing="close">
<Button>Agent</Button>
<Button>Model</Button>
</ButtonsGroup>
Added support for icon-and-description layout in Notice by making title optional. When omitted, the notice renders as a single row with icon and description, useful for inline contextual messages. (#16033)
// Before — title required
<Notice variant="info" title="Heads up">Some message.</Notice>
// After — title optional, single-row layout
<Notice variant="info">Some message.</Notice>
Improved trace timeline span controls. Added tooltips with row counts to the expand-children, expand-all-descendants, and expand-at-this-level buttons. The expand-children button now collapses only the direct children rather than the entire subtree, and the descendants column gained a matching collapse-all-descendants action. Root spans show a single Expand all / Collapse all button using outward/inward double-chevrons. (#16173)
Refreshed toast styling so it aligns with the Notice component and lets sonner own the layout. (#16144)
What changed for users:
<Notice> component, including bg, border and text color in both light and dark mode.toast.promise, the close button position, the icon placement and the mobile width all work as documented instead of fighting custom overrides.dismissible: false and closeButton: false.toast.success / error / warning / info now return sonner's toast id (or an array of ids when called with an array of messages) so callers can keep dismissing or updating the toast they created.Added a Scorer span type style on the trace timeline and a colored type dot before each span name so spans are visually flagged in both the name and timing columns. (#16160)
Migrated Files/Skills tabs and agent page tabs (Chat/Editor/Evaluate/Review/Traces) to the design-system Tabs component for consistent styling and accessibility (Radix tablist, arrow-key navigation). Also added a cursor-pointer on the Tab trigger and a disabled prop on the DS Tab. (#16148)
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Added an informational notice on the trace data panel pointing users to Mastra Studio (local or deployed) when "Evaluate Trace" and "Save as Dataset Item" actions are not available in the current view. (#16157)
Fixed pointer cursor on interactive form controls (Button, SelectTrigger, SelectItem) for better affordance. (#16140)
Extend the schedules storage schema to support owned schedules and richer trigger audit. This is a breaking schema change to mastra_schedules and mastra_schedule_triggers; scheduled workflows are still in alpha so no compat shim is provided. (#16166)
Schedule gains optional ownerType / ownerId so a schedule row can be attributed to an owning subsystem (e.g. an agent that owns a heartbeat schedule). Workflow schedules leave both fields unset.ScheduleTrigger.status is renamed to outcome and the type is widened to ScheduleTriggerOutcome so future outcome values can be added without another rename.ScheduleTrigger gains a stable id primary key and new triggerKind, parentTriggerId, and metadata fields. triggerKind distinguishes schedule-fire rows from later queue-drain rows (used by upcoming heartbeat work); parentTriggerId links related rows; metadata carries outcome-specific context.@mastra/core peer dependency is tightened to >=1.32.0-0 <2.0.0-0 so installing a new storage adapter against an older core (or vice-versa) surfaces a peer-dependency warning at install time instead of silently writing/reading the wrong field.triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.outcome so the schedule detail page keeps polling and rendering publish-failure rows correctly.Added API endpoints for MCP server resources, enabling clients to list and read app resources for interactive UI rendering. (#16004)
GET /api/mcp/:serverId/resources — lists available resources on an MCP serverPOST /api/mcp/:serverId/resources/read — reads a specific resource by URI (e.g. ui://calculator/app)Added HTTP routes for scheduled workflows. (#15830)
GET /api/schedules — list schedules across the project, optionally filtered by workflowId.GET /api/schedules/:scheduleId — fetch a schedule with its most recent run summary.GET /api/schedules/:scheduleId/triggers — paginated trigger history joined to the corresponding workflow run.POST /api/schedules/:scheduleId/pause and POST /api/schedules/:scheduleId/resume — durable pause/resume. Both require schedules:write and are idempotent. Resume recomputes nextFireAt from now so a long-paused schedule does not fire a backlog.Added listBranches and getBranch endpoints. Use these to find specific runs of an agent, workflow, tool, or processor — even when they are nested inside another trace — and to fetch the subtree of spans rooted at any single span. (#16177)
GET /observability/branches?spanType=agent_run&entityName=Observer
GET /observability/traces/:traceId/branches/:spanId?depth=1
Each row in listBranches is a single anchor span (one of AGENT_RUN, WORKFLOW_RUN, PROCESSOR_RUN, SCORER_RUN, RAG_INGESTION, TOOL_CALL, MCP_TOOL_CALL), so entities that always run as a child (e.g., an Observer agent inside a workflow) — previously not listable through listTraces — are now queryable via the HTTP API. getBranch accepts an optional depth (0 = anchor only; omitted = full subtree).
Follow-up to https://github.com/mastra-ai/mastra/pull/16154 which added the underlying @mastra/core storage APIs.
Added Fine-Grained Authorization (FGA) enforcement across server handlers and memory APIs: (#15410)
resourceId forwarded into the FGA context so providers can derive composite tenant-scoped resource IDsFixed A2A task resubscribe to return the current task snapshot and continue streaming live artifact and status updates for in-progress tasks. (#15987)
Added an observability score lookup endpoint at GET /observability/scores/:scoreId backed by observability storage. (#16162)
Added MCP Apps extension support (SEP-1865). MCPServer now accepts an appResources config to register interactive ui:// HTML resources. MCPClient preserves full tool _meta (including ui.resourceUri) when converting MCP tools to Mastra tools. Both advertise the io.modelcontextprotocol/ui extension capability. (#16004)
Example — MCPServer with app resources:
const server = new MCPServer({
name: 'my-server',
tools: { myTool },
appResources: {
dashboard: {
name: 'Dashboard',
description: 'Interactive dashboard UI',
html: '<html>...</html>',
},
},
});
Added server-generated route contract types for the JavaScript client SDK and updated the SDK to use those generated request and response types. (#15519)
Added the new @mastra/temporal package for running Mastra workflows on Temporal. (#15789)
What changed
init() to create Temporal-backed Mastra workflows and steps.MastraPlugin to bundle workflow code for Temporal workers and load generated activities.debug: true support to write transformed workflow modules and emitted bundles to .mastra/temporal.Example
import { init } from '@mastra/temporal';
import { MastraPlugin } from '@mastra/temporal/worker';
import { Client, Connection } from '@temporalio/client';
import { Worker } from '@temporalio/worker';
const connection = await Connection.connect();
const client = new Client({ connection });
const { createWorkflow, createStep } = init({ client, taskQueue: 'mastra' });
const step = createStep({ id: 'hello', execute: async () => 'world' });
export const helloWorkflow = createWorkflow({ id: 'hello-workflow' }).then(step);
await Worker.create({
connection,
taskQueue: 'mastra',
plugins: [new MastraPlugin({ src: import.meta.resolve('./mastra/index.ts') })],
});
The following packages were updated with dependency changes only:
A new channels architecture adds ChannelProvider, a dedicated ChannelsStorage domain, and ChannelConnectResult connection flows (OAuth, deep link, immediate), with Mastra-level connect/disconnect/list APIs and matching MastraClient.channels methods.
@mastra/slack)New Slack provider connects agents to Slack workspaces with OAuth-based app provisioning, manifest drift detection, encrypted credential storage, slash commands, and threaded conversation support.
@mastra/nestjs)New @mastra/nestjs adapter runs Mastra inside NestJS (Express) apps with native module registration, DI-friendly service injection, rate limiting, graceful shutdown, streaming, and MCP transport support; MastraServerBase is now exported to support adapters that manage routing.
@mastra/google-drive)New Google Drive WorkspaceFilesystem mounts a single Drive folder as an agent workspace, supporting OAuth tokens (with refresh callbacks) and service accounts, and implementing the full read/write/list/move/stat interface with optimistic concurrency via expectedMtime.
@mastra/voice-aws-nova-sonic)Adds a bidirectional streaming voice provider for Bedrock Nova 2 Sonic with live mic streaming and playback, streaming transcription (speculative/final), barge-in detection, multi-voice selection, and tool calling with per-session RequestContext.
@mastra/playground-ui: IconButton export removed (use Button with size="icon-*") and <Alert> removed in favor of <Notice>; variant="light"/"inputLike" replaced by variant="default".Enhanced load_tool to accept an array of tool names, enabling bulk tool loading in a single call. Returns 'loaded', 'notFound', and 'alreadyLoaded' arrays for clearer response shape. (#15472)
Added Microsoft Entra ID authentication support for Azure OpenAI gateways, so Azure deployments can call models without API keys when using Azure SDK credentials. (#15983)
Added platform channels framework with ChannelProvider interface, ChannelsStorage domain, and ChannelConnectResult discriminated union supporting OAuth, deep link, and immediate connection flows. Channels can be registered on the Mastra instance and expose connect/disconnect/list APIs for platform integrations. (#15876)
Added top-level environment config on Mastra to tag observability signals with the deployment environment. (#15956)
Set it once on the Mastra instance and it will be attached to all observability signals automatically. Falls back to process.env.NODE_ENV when unset; per-call tracingOptions.metadata.environment still takes precedence.
Before
await agent.generate('hello', {
tracingOptions: { metadata: { environment: process.env.NODE_ENV } },
});
After
new Mastra({
environment: 'production',
observability: new Observability({ ... }),
})
mastra.getEnvironment() returns the resolved value.
Fixed trajectory scorers in dataset.startExperiment receiving raw agent messages instead of a Trajectory object, which caused a crash when accessing run.output.steps. Trajectory scorers now receive the same pre-extracted Trajectory that runEvals provides. (#15693)
The scorers option now also accepts the same categorised shape as runEvals (AgentScorerConfig / WorkflowScorerConfig), so you no longer need to rewrite your scorer config when moving from runEvals to dataset.startExperiment.
Before (trajectory scorer crashed at runtime):
await dataset.startExperiment({ scorers: [orderScorer] }) // run.output.steps was undefined
After (works correctly, both flat and categorised forms accepted):
await dataset.startExperiment({ scorers: [orderScorer] }) await dataset.startExperiment({ scorers: { agent: [accuracyScorer], trajectory: [orderScorer] } })
Per-step scorers are now also supported for workflow targets, matching runEvals. Pass scorers: { workflow: [...], steps: { stepId: [...] }, trajectory: [...] } to score individual workflow steps with their own scorers; results carry the originating stepId and keep targetScope: 'span' (with targetEntityType: WORKFLOW_STEP on the underlying scorer run), matching how runEvals encodes step identity.
Workspace search now supports batch-capable embedders. Pass an embedder branded with batch: true (and an optional maxBatchSize) to embed all pending chunks for a flush in a single provider call instead of one call per chunk. This dramatically reduces index-rebuild time on large workspaces when using providers that support batch embedding (e.g. OpenAI's embedMany). Existing single-text embedders continue to work unchanged. (#14735)
import { embedMany } from 'ai';
import { openai } from '@ai-sdk/openai';
const model = openai.embedding('text-embedding-3-small');
const workspace = new Workspace({
// ...
embedder: Object.assign(
async (texts: string[]) => {
const { embeddings } = await embedMany({ model, values: texts });
return embeddings;
},
{ batch: true as const, maxBatchSize: 2048 },
),
});
Update provider registry and model documentation with latest models and providers (1723e09)
Fixed workflow runs not being cancellable when steps or conditions ignored the abort signal. Cancelling a run now correctly stops dountil, dowhile, and foreach loops at every cancellation boundary — between iterations, after a step returns, after the loop condition is evaluated, and (for foreach) between concurrency chunks and after the final chunk. Previously, long-running loops (e.g. a dountil with a setTimeout inside the step) would keep running and eventually emit success even after the run was cancelled. Closes #15990. (#15994)
Fixed type inference on workflow loop helpers (foreach, dowhile, dountil) so a step's requestContextSchema correctly aligns with the workflow's requestContextSchema. Previously these methods dropped the workflow's TRequestContext from the step parameter, causing TypeScript to reject typed-context steps even when the workflow declared a matching schema. Steps without a requestContextSchema are still accepted; steps whose schema does not match the workflow's now produce a type error. Fixes #15989. (#15995)
Fixed sub-agent delegation so nested tool results stay out of the parent model context by default while remaining available to application code. Set delegation.includeSubAgentToolResultsInModelContext to include the full subagent result in the parent model context. (#15832)
Added a coalesced display state subscription API for Harness. (#15974)
This helps UI clients render fewer updates while still receiving the latest state. The example below renders the initial state, then subscribes to coalesced updates with the default windowMs and maxWaitMs timing options.
render(harness.getDisplayState());
const unsubscribe = harness.subscribeDisplayState(render, {
windowMs: 250,
maxWaitMs: 500,
});
Fixed BatchPartsProcessor using a hardcoded id in batched text-delta chunks. The real message id and runId are now preserved from the original chunks, preventing AI SDK UIMessage stream from dropping batched deltas. (#14974)
Add filterAfterToolSteps to ToolCallFilter so tool calls can be filtered during agentic loops after they are no longer recent. By default, ToolCallFilter keeps its previous behavior and only filters the initial input. (#15795)
Workspace search no longer throws when requesting hybrid or vector mode if the configuration does not support it. The search tool now gracefully falls back to the best available mode instead of throwing an error. (#14533)
Workspace file tools no longer use misleading absolute-path examples (e.g. /data/output.txt) that caused weaker LLMs to attempt writes at the actual filesystem root. The example paths in read_file and write_file are now relative. (#14544)
Additionally, when a contained workspace rejects an absolute path that escapes its boundary, the resulting PermissionError now guides the agent toward a relative path so it can self-correct on the next turn. When the path's first segment names a real directory in the workspace (e.g. /src/app.ts with an existing src/), the error suggests the exact relative form. Otherwise it falls back to a generic hint instead of inventing a misleading suggestion for genuinely out-of-workspace paths like /etc/passwd.
Fixes #14542
Fixed SkillSearchProcessor so agents use it as the on-demand skill discovery path without also adding eager skill context. (#15916)
When SkillSearchProcessor is configured, agents no longer auto-add the eager SkillsProcessor, and they hide the overlapping skill and skill_search tools while keeping skill_read available for supporting skill files. Workspace file tools can still read SKILL.md files during explicit file inspection or editing workflows.
Fixed tool calls to run in parallel when active tools exclude approval or suspending tools. (#15978)
indexMany uses p-map with a default concurrency of 8 when vector embedding runs, with optional concurrency and stopOnError (same semantics as p-map). Lazy vector indexing flushes pending documents at the same concurrency, drains the queue before awaiting so concurrent index calls are not dropped, loops until the queue is empty before search, dedupes by document id (last wins), and re-queues the batch if a flush throws. (#14735)Fix semantic recall indexing to honor read-only memory mode. (#15949)
Fixed Linux bubblewrap failing when Workspace mounts use symlinks under LocalSandbox by resolving mount paths to real directories for isolation allowlists. (#15498)
Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)
gen_ai.usage.cached_input_tokens → gen_ai.usage.cache_read.input_tokensgen_ai.usage.cache_write_tokens → gen_ai.usage.cache_creation.input_tokensgen_ai.usage.input_tokens is unchanged and remains the total prompt-token count. Cache attributes are emitted separately as subsets of that total.
Updated Arize, Arthur, and Sentry mappings so cache values continue to flow through those exporters.
Direct consumers should update any dashboards, alerts, or queries that reference the old attribute names.
Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)
gen_ai.usage.cached_input_tokens → gen_ai.usage.cache_read.input_tokensgen_ai.usage.cache_write_tokens → gen_ai.usage.cache_creation.input_tokensgen_ai.usage.input_tokens is unchanged and remains the total prompt-token count. Cache attributes are emitted separately as subsets of that total.
Updated Arize, Arthur, and Sentry mappings so cache values continue to flow through those exporters.
Direct consumers should update any dashboards, alerts, or queries that reference the old attribute names.
Added ClickhouseStoreVNext, a ClickHouse storage adapter that uses the vNext observability domain by default. Equivalent to constructing a ClickhouseStore and overriding the observability domain manually, but exposed as a single class for new projects. (#15984)
import { Mastra } from '@mastra/core';
import { ClickhouseStoreVNext } from '@mastra/clickhouse';
export const mastra = new Mastra({
storage: new ClickhouseStoreVNext({
id: 'clickhouse-storage',
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
}),
});
ClickhouseStoreVNext accepts the same configuration as ClickhouseStore and reuses the same ClickHouse client across every domain. ClickhouseStore continues to work for projects on the legacy observability schema.
Thread <id> placeholder on save, which prevented the title-generation step (gated on an empty title) from running. Empty titles now round-trip correctly so generated titles work the same as with other storage adapters. Resolves #15998. (#16003)Fix multipart file handling in Fastify adapter by aligning return type with other adapters and preventing stream hang on file size limit. (#15796)
Fix multipart upload tests to register the multipart content-type parser. The tests were manually adding the preHandler hook but skipping registerContextMiddleware(), which meant Fastify rejected multipart/form-data requests with 415 Unsupported Media Type. (#16002)
Add @mastra/google-drive, a new Google Drive WorkspaceFilesystem provider that mounts a single Drive folder as an agent workspace. Supports OAuth access tokens, async refresh callbacks, and service account (JWT) authentication. Implements the full WorkspaceFilesystem interface — read, write, list, copy, move, mkdir, rmdir, stat, exists — plus expectedMtime optimistic concurrency. (#15756)
import { Agent } from '@mastra/core/agent';
import { Workspace } from '@mastra/core/workspace';
import { GoogleDriveFilesystem } from '@mastra/google-drive';
const workspace = new Workspace({
filesystem: new GoogleDriveFilesystem({
folderId: process.env.GOOGLE_DRIVE_FOLDER_ID!,
accessToken: process.env.GOOGLE_DRIVE_ACCESS_TOKEN!,
}),
});
const agent = new Agent({
id: 'drive-agent',
name: 'Drive Agent',
model: 'openai/gpt-4o-mini',
workspace,
});
A matching googleDriveFilesystemProvider descriptor is also exported for MastraEditor.
Removed unsupported minScore query option from MongoDB vector store docs and README. Exported MongoDBQueryVectorParams so callers can type documentFilter for MongoDBVector.query(). (#15936)
Fixes #15715
Add NestJS server adapter (@mastra/nestjs) for running Mastra with NestJS Express applications. Provides native module registration, DI-based service injection, rate limiting, graceful shutdown, streaming, and MCP transport support. (#12751)
import { Module } from '@nestjs/common';
import { MastraModule } from '@mastra/nestjs';
import { mastra } from './mastra';
@Module({
imports: [MastraModule.register({ mastra })],
})
export class AppModule {}
environment to all observability signals. (#15956)Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)
gen_ai.usage.cached_input_tokens → gen_ai.usage.cache_read.input_tokensgen_ai.usage.cache_write_tokens → gen_ai.usage.cache_creation.input_tokensgen_ai.usage.input_tokens is unchanged and remains the total prompt-token count. Cache attributes are emitted separately as subsets of that total.
Updated Arize, Arthur, and Sentry mappings so cache values continue to flow through those exporters.
Direct consumers should update any dashboards, alerts, or queries that reference the old attribute names.
Added new @mastra/perplexity integration with the Perplexity Search tool for agents. (#15939)
import { createPerplexityTools } from '@mastra/perplexity';
const { perplexitySearch } = createPerplexityTools({ apiKey: process.env.PERPLEXITY_API_KEY });
Fixed workflow snapshot sanitization in @mastra/pg for strings containing escaped surrogate patterns like [^\ud800-\udfff]. This prevents invalid JSON escape sequences that caused PostgreSQL jsonb writes to fail with error 22P02. (#15923)
Fixes #15920
Added platform channels framework with ChannelProvider interface, ChannelsStorage domain, and ChannelConnectResult discriminated union supporting OAuth, deep link, and immediate connection flows. Channels can be registered on the Mastra instance and expose connect/disconnect/list APIs for platform integrations. (#15876)
Refactored Button component to use a single cva (class-variance-authority) variant config instead of nested manual maps. Consolidated IconButton into Button via size="icon-sm|icon-md|icon-lg" and removed the IconButton export. Replaced variant="light" and variant="inputLike" with variant="default" (no behavior change for default styling). Added cta and outline variants and unified active/hover styles between text- and icon-mode buttons. (#15985)
Why: A single source of truth for variants means consistent visuals, fewer drift bugs, simpler maintenance, and a more predictable surface for AI agents — single-variant cva is the dominant shadcn pattern across DS components in this repo (Card, Input, Label, Textarea, StatusBadge).
Migration:
// Before
import { IconButton } from '@mastra/playground-ui';
<IconButton><Settings /></IconButton>
<Button variant="light">…</Button>
<Combobox variant="inputLike" />
// After
import { Button } from '@mastra/playground-ui';
<Button size="icon-md"><Settings /></Button>
<Button variant="default">…</Button>
<Combobox variant="default" />
Removed <Alert> in favor of <Notice>. The two components had significant visual and behavioral overlap; <Notice> is now the single banner primitive and supports every previous <Alert> use case. (#15791)
<Notice> is also redesigned with a flatter API: title and icon are now props, each variant ships a default icon, an optional action prop renders a button aligned to the title, and a new note variant has been added alongside warning, destructive, info, and success. Theme tokens (notice-warning, notice-destructive, notice-info, notice-success, notice-note) replace the previous hardcoded colors.
Migration
// Before
<Alert variant="warning">
<AlertTitle>Provider not connected</AlertTitle>
<AlertDescription as="p">Set the API key environment variable.</AlertDescription>
</Alert>
// After
<Notice variant="warning" title="Provider not connected">
<Notice.Message>Set the API key environment variable.</Notice.Message>
</Notice>
Removed the "Avg Score" KPI card from the Metrics dashboard and the avg-score summary from the Scores card. (#15967)
Fixed row click behavior in the dataset experiments compare view. Clicking a row while selection mode is active now toggles the row's selection instead of navigating to the experiment. Clicking directly on the checkbox no longer also triggers the row click handler. (#15492)
Aligned AlertDialog visual styling with Dialog component for design system consistency. AlertDialog now uses the same surface tokens, border radius, shadow, animation curves, and typography scale as Dialog. The accessibility primitive remains separate (preserves role="alertdialog" and explicit Action/Cancel semantics) — only the visual shell was synced. Also added AlertDialog.Body for parity with Dialog. (#15988)
Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)
gen_ai.usage.cached_input_tokens → gen_ai.usage.cache_read.input_tokensgen_ai.usage.cache_write_tokens → gen_ai.usage.cache_creation.input_tokensgen_ai.usage.input_tokens is unchanged and remains the total prompt-token count. Cache attributes are emitted separately as subsets of that total.
Updated Arize, Arthur, and Sentry mappings so cache values continue to flow through those exporters.
Direct consumers should update any dashboards, alerts, or queries that reference the old attribute names.
Fix GET /tools/:toolId and POST /tools/:toolId/execute to find dynamically-resolved agent tools (provided via toolsResolver / function-based tools) when they are not in the static tool registry. Errors thrown by an individual agent's listTools() during the lookup are now logged as warnings instead of being silently swallowed. (#13989)
Fixed memory query validation when optional JSON query params are omitted with newer Zod versions. (#15969)
Export MastraServerBase from @mastra/core/server so framework adapters that manage routing independently can share the same server base class. (#12751)
Added platform channels framework with ChannelProvider interface, ChannelsStorage domain, and ChannelConnectResult discriminated union supporting OAuth, deep link, and immediate connection flows. Channels can be registered on the Mastra instance and expose connect/disconnect/list APIs for platform integrations. (#15876)
Added @mastra/slack channel integration for connecting AI agents to Slack workspaces. Provides automatic Slack app provisioning via OAuth, manifest management with drift detection, encrypted credential storage, slash command support, and threaded conversation handling. Usage: (#15876)
import { SlackProvider } from '@mastra/slack';
const mastra = new Mastra({
channels: {
slack: new SlackProvider({
refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN!,
}),
},
});
// Connect an agent to Slack
const result = await mastra.channels.slack.connect('my-agent');
// result.type === 'oauth' → redirect user to result.authorizationUrl
Add new @mastra/voice-aws-nova-sonic voice provider for AWS Bedrock Nova 2 Sonic. (#13232)
The provider exposes a real-time bidirectional voice interface backed by the
InvokeModelWithBidirectionalStreamCommand API on AWS Bedrock, including:
send / listen) and assistant audio playback
via speaking eventswriting events with SPECULATIVE / FINAL
generation stagesRequestContextThe following packages were updated with dependency changes only:
New DurableAgent support lets agent streams resume after client disconnects and continue through server crashes/restarts by caching stream events and enabling reconnection via observe(runId, { offset }).
Agents can now run outside the HTTP request using workflow execution (createEventedAgent for built-in evented engine, createInngestAgent for Inngest), enabling reliable long-running tool loops while clients subscribe to progress.
Durable streaming is backed by a PubSub + ServerCache layer (defaults: EventEmitterPubSub + InMemoryServerCache), with recommended production configs using Redis-backed implementations so any instance can serve reconnect/replay.
@mastra/serverA2A streaming now emits incremental artifact updates during the full agent stream while still preserving final structured output artifacts.
Cloud observability uploads now filter model chunk spans by default and raise the default observability log level to warn, reducing data volume and chatter.
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionFixed a regression in 1.29.0 where configuring an agent with channel adapters (e.g. channels.adapters.slack) caused server startup to crash with a "Custom API route ... must not start with /api" error. The custom-route prefix validation now skips framework-generated webhook routes. (#15952)
Update provider registry and model documentation with latest models and providers (d587199)
Fix MCP client support in the agent editor: (#15945)
Remove incorrect deprecation markers from getTask() and cancelTask() in the Mastra A2A client. (#15941)
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionchannels.adapters.slack) caused server startup to crash with a "Custom API route ... must not start with /api" error. The custom-route prefix validation now skips framework-generated webhook routes. (#15952)Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionUpdate peer dependencies to match core package version bump (1.0.5) (#12557)
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionReduced default cloud observability volume by filtering model chunk spans from CloudExporter uploads by default and raising the default observability log level to warn. (#15815)
Updated the look and motion of Dialog. The surface is now lighter and translucent with a subtle backdrop blur, the typography is tighter, and the open/close animation feels snappier. SideDialog and AlertDialog pick up the refined ambient shadow as well, since they share the same shadow style. (#15958)
Polished DataList visuals: removed the trailing "No more data to load" message and dropped the bottom border on the last row for a cleaner end-of-list appearance. (#15959)
Refined the DataPanel loading state with a smaller spinner and tightened layout for a less prominent appearance. (#15965)
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionFixed a regression in 1.29.0 where configuring an agent with channel adapters (e.g. channels.adapters.slack) caused server startup to crash with a "Custom API route ... must not start with /api" error. The custom-route prefix validation now skips framework-generated webhook routes. (#15952)
Fix MCP client support in the agent editor: (#15945)
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionFix A2A streaming to emit incremental artifact updates from the agent full stream while preserving final structured output artifacts. (#15941)
Add durable agents with resumable streams (#12557)
Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
Standard agent streaming has two fragility points:
Resumable streams solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
Durable execution solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
Wrap any existing Agent with durability using factory functions:
import { Agent } from '@mastra/core/agent';
import { createDurableAgent } from '@mastra/core/agent/durable';
const agent = new Agent({
id: 'my-agent',
model: openai('gpt-4'),
instructions: 'You are helpful',
});
const durableAgent = createDurableAgent({ agent });
Factory functions for different execution strategies:
| Factory | Execution | Use Case |
|---|---|---|
createDurableAgent({ agent }) | Local, synchronous | Development, simple deployments |
createEventedAgent({ agent }) | Fire-and-forget via workflow engine | Long-running operations |
createInngestAgent({ agent, inngest }) | Inngest-powered | Production, distributed systems |
// Start streaming
const { runId, output } = await durableAgent.stream('Analyze this data...');
// Client disconnects at event 5...
// Reconnect and resume from where we left off
const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
// Receives events 6, 7, 8... from cache, then continues with live events
Durable agents use two infrastructure components:
| Component | Purpose | Default |
|---|---|---|
| PubSub | Real-time event delivery during streaming | EventEmitterPubSub |
| Cache | Stores events for replay on reconnection | InMemoryServerCache |
When stream() is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When observe() is called, missed events replay from cache before continuing with live events.
Configure via Mastra instance (recommended):
const mastra = new Mastra({
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
agents: {
// Inherits cache and pubsub from Mastra
myAgent: createDurableAgent({ agent }),
},
});
Configure per-agent (overrides Mastra):
const durableAgent = createDurableAgent({
agent,
cache: new RedisServerCache({ url: 'redis://...' }),
pubsub: new RedisPubSub({ url: 'redis://...' }),
});
Disable caching (streams won't be resumable):
const durableAgent = createDurableAgent({ agent, cache: false });
For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
DurableAgent extends Agent - base class with resumable streamsEventedAgent extends DurableAgent - fire-and-forget executionInngestAgent extends DurableAgent - Inngest-powered executionThe following packages were updated with dependency changes only:
Server auth now supports mapUserToResourceId, automatically mapping an authenticated user to a resource ID so memory/threads are isolated per user without custom middleware, and client attempts to inject reserved context keys (mastra__resourceId, mastra__threadId) are stripped.
Experiments correctly execute the specified agentVersion, and observability gains first-class entityVersionId/parentEntityVersionId/rootEntityVersionId across spans/metrics/scores/logs/feedback (with storage migrations in ClickHouse/DuckDB/Postgres/MongoDB/LibSQL), plus new experiment query filters and experimentId propagation into agent spans and scorer context.
chatRoute(), handleChatStream(), networkRoute(), and handleNetworkStream() now accept agentVersion (and runtime ?versionId= / ?status= overrides) to route traffic to draft/published or specific version IDs (requires the Editor).
You can enable per-tool strict: true in createTool() for providers that support strict tool calling, and processors can now intercept LLM failures via processAPIError (including a built-in PrefillErrorHandler that retries Anthropic “assistant message prefill” errors automatically).
Agent Browser/Stagehand add lightweight auth persistence via storageState/exportStorageState(), support persistent sessions via profile and custom Chrome via executablePath, and improve cleanup (stale lock files/orphaned Chrome processes) for more reliable runs.
@mastra/voice-sarvam@1.0.0 drops deprecated Sarvam models (bulbul:v1, saarika:v1/v2/flash), defaults shift to bulbul:v3 + speaker shubh, and the TTS request payload changes from inputs[] to text.feat(server): Add mapUserToResourceId callback to auth config for automatic resource ID scoping (#13954)
Auth configs now accept a mapUserToResourceId callback that maps the authenticated user to a resource ID after successful authentication. This enables per-user memory and thread isolation without requiring custom middleware or adapter subclassing.
const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => verifyToken(token),
mapUserToResourceId: user => user.id,
},
},
});
The callback is called in coreAuthMiddleware after the user is authenticated and set on the request context. The returned value is set as MASTRA_RESOURCE_ID_KEY, which takes precedence over client-provided values for security. Works across all server adapters (Hono, Express, Next.js, etc.).
Added processAPIError hook to the Processor interface for intercepting LLM API call failures before they surface as errors. New built-in PrefillErrorHandler automatically recovers from Anthropic "assistant message prefill" errors by appending a <system-reminder>continue</system-reminder> user message and retrying once. (#14435)
Experiments now run the correct agent version (#15317)
When an experiment specifies agentVersion, the experiment pipeline now resolves and executes against that specific version instead of ignoring it. Previously, the version was stored as metadata but the agent always ran with its current default configuration.
entityVersionId is now a first-class observability dimension
New entityVersionId, parentEntityVersionId, and rootEntityVersionId fields are available on all observability records (spans, metrics, scores, feedback, logs). This enables filtering and grouping OLAP queries by version at any level of the span tree. rootEntityVersionId is particularly useful for aggregating all signals within a versioned agent's trace. This replaces the previous resolvedVersionId attribute which was buried in span attributes and unfilterable.
experimentId propagated to agent spans
Agent spans created during experiment execution now carry the experimentId, enabling trace-to-experiment cross-referencing.
Scorer correlation context
Scorers running in the experiment pipeline now receive full targetCorrelationContext (including experimentId), so scores emitted via observability carry experiment context.
New experiment query filters
listExperiments now supports filtering by targetType, targetId, agentVersion, and status. listExperimentResults now supports filtering by traceId and status.
Added profile and executablePath options to browser config for persistent sessions and custom browser support. Automatically cleans up stale Chrome lock files on browser close. (#15194)
Added (#15313)
Added per-tool strict mode for providers that support strict tool calling. You can now set strict: true on createTool() and Mastra will forward it when preparing tool definitions.
const weatherTool = createTool({
id: 'weather',
description: 'Get weather for a city',
strict: true,
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ city }),
});
Update provider registry and model documentation with latest models and providers (582644c)
Fixed mastra_workspace_list_files silently returning no files when agents passed an empty pattern (e.g. pattern: [] or pattern: ''). Empty and whitespace-only patterns are now treated as "no filter" and return the full listing instead of a dirs-only view or a picomatch error. (#15360)
Fixed harness tool approval, decline, and resume handlers hardcoding requireToolApproval: true. They now follow the harness yolo state like sendMessage already does, so resumed tool calls in yolo mode no longer get unexpectedly re-gated on approval.
Update references to "Mastra Cloud" to "Mastra platform" (#15297)
Fixed symlinked skill paths so workspace skills resolve consistently and allowed path checks work through both symlink and real paths. (#15228)
AgentBrowser with default thread scope now initializes correctly. Previously, calling launch() followed by getPage() would throw "Browser not launched" when no explicit thread ID was provided. (#15285)
fix: ensure listVectorStores always returns a string id (#15239)
Improved structuredOutput.model error messages to surface upstream structuring failures, including plain-object errors, instead of a generic internal agent error. (#15226)
Agent instances can now create lightweight clones that preserve all configuration, so version overrides and tools are isolated without mutating the shared runtime agent. (#15314)
Fixed structuredOutput.model custom gateway resolution by registering the internal structuring agent with the parent Mastra instance. (#15230)
Fixed OpenAI reasoning summary streaming so reasoning summary text is preserved when multiple summaries overlap or finish out of order. (#15225)
Upgraded model router providers to AI SDK v3 spec: OpenAI, Anthropic, Google, xAI, Groq, and Mistral now use the latest v6 SDK packages. Providers built on openai-compatible (Cerebras, DeepInfra, DeepSeek, Perplexity, TogetherAI) remain on v2 spec until their base package is updated. All provider packages (both v5 and v6) bumped to their latest stable patch versions. (#15358)
Fixed 'item missing its reasoning part' error for OpenAI reasoning models (gpt-5-mini, gpt-5.2). The v5 SDK couldn't serialize reasoning items for OpenAI's Responses API, so Mastra stripped them from prompts — but this caused errors in multi-turn conversations with memory enabled. With v3 providers, reasoning items are serialized natively and the stripping workaround has been removed.
Fixed gateway model detection to use duck typing instead of instanceof check, preventing potential failures from cross-package module resolution issues. Propagates gatewayId through the AISDKV5LanguageModel wrapper so duck-type detection works even when models are re-wrapped. (#15168)
Fixed Channels not working on Vercel serverless (and other serverless platforms). Webhook handlers now await initialization on cold starts instead of immediately returning 503, and pass the platform's waitUntil to the Chat SDK so agent processing survives after the HTTP response is sent. See #15300. (#15335)
fix(core): Restore AI SDK v6 provider option typings for vector embeddings (#15306)
The vendored AI SDK v6 declaration build now re-exports ProviderOptions after type bundling renames it to ProviderOptions_2. This fixes TS2724 errors in @mastra/core when vector embeddings import AI SDK v6 provider option types.
storageState option and exportStorageState() method for lightweight auth persistence (cookies and localStorage). Also kills orphaned Chrome child processes on close to prevent zombies. (#15194)Added structured output streaming to the AI SDK UI stream. When an agent produces structured output, the final object is now emitted as a data-structured-output data part in the UI message stream, making it available to frontends via AI SDK UI's custom data handling. (#15237)
Added agent versioning support to chat and network route handlers. You can now pass agentVersion to chatRoute(), handleChatStream(), networkRoute(), and handleNetworkStream() to target a specific agent version by ID or status (draft/published). Route handlers also accept ?versionId=<id> or ?status=draft|published query parameters at request time, which take precedence over static configuration. Requires the Editor to be configured. (#15296)
// Static version on route config
chatRoute({
path: '/chat',
agent: 'weatherAgent',
agentVersion: { status: 'published' },
});
// Programmatic version on handler
const stream = await handleChatStream({
mastra,
agentId: 'weatherAgent',
agentVersion: { versionId: 'ver_abc123' },
params,
});
entityVersionId, parentEntityVersionId, and rootEntityVersionId columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added targetType, targetId, agentVersion, and status filters to listExperiments, and traceId and status filters to listExperimentResults. (#15317)entityVersionId, parentEntityVersionId, and rootEntityVersionId columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added targetType, targetId, agentVersion, and status filters to listExperiments, and traceId and status filters to listExperimentResults. (#15317)Fixed "column does not exist" errors when using experiment review features on databases created before the review pipeline was introduced. Startup now automatically migrates older experiment tables to the latest schema. (#15304)
Added entityVersionId, parentEntityVersionId, and rootEntityVersionId columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added targetType, targetId, agentVersion, and status filters to listExperiments, and traceId and status filters to listExperimentResults. (#15317)
requireToolApproval option to MCP server configuration for requiring human approval before tool execution. Supports both boolean (all tools) and function (dynamic per-tool logic). (#15315)gatewayId through the AISDKV5LanguageModel wrapper so duck-type detection works even when models are re-wrapped. (#15168)entityVersionId, parentEntityVersionId, and rootEntityVersionId columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added targetType, targetId, agentVersion, and status filters to listExperiments, and traceId and status filters to listExperimentResults. (#15317)Fixed double-counting of Anthropic cache tokens in usage metrics (#15316)
Cost estimates now use the latest model pricing rates for more accurate calculations (#15362)
Update references to "Mastra Cloud" to "Mastra platform" (#15297)
Reduced observability overhead for MODEL_STEP spans by storing a lightweight message preview of request bodies. (#15249)
This keeps span previews readable and avoids pulling large payloads into exporter input.
Fixed cost lookup for models with date suffixes. Providers like OpenAI often return model names with date suffixes (e.g., gpt-5.4-mini-2026-03-17) that don't exactly match pricing data entries. The lookup now tries multiple variants including stripping date suffixes and converting dots to dashes. (#15349)
Added entityVersionId, parentEntityVersionId, and rootEntityVersionId to span correlation context, enabling version information to propagate to scores, metrics, logs, and feedback emitted during traced execution. (#15317)
Fixed stack traces for errors reported to Sentry. Exceptions now point to the code that threw the error instead of SentryExporter.handleSpanEnded inside the exporter, so issues in Sentry are actually debuggable. (#15343)
This was caused by two issues, both fixed:
@mastra/sentry passed the error message as a string to Sentry.captureException, which made Sentry synthesize a stack trace from the exporter's call site. It now passes an Error instance with the captured stack attached.@mastra/observability stored the wrapping MastraError's stack on the span, hiding the original error's location. When the MastraError has a cause, the cause's stack is now preserved.Fixes #15337.
Fixed vector similarity queries to leverage HNSW and IVFFlat indexes. When querying without filters on an HNSW or IVFFlat-indexed table, ORDER BY and LIMIT are now placed inside the CTE so PostgreSQL can use the index for faster approximate nearest neighbor searches instead of scanning all rows. (#14574)
Fixed batchInsert and batchUpdate in @mastra/pg to run on a single Postgres transaction connection. (#15312)
This prevents pooled BEGIN/COMMIT/ROLLBACK calls from landing on different connections and leaving idle transactions open during batch writes.
Fixed "column does not exist" errors when using experiment review features on databases created before the review pipeline was introduced. Startup now automatically migrates older experiment tables to the latest schema. (#15304)
Fixed vector operations failing when pgvector extension is installed in a custom schema. The search_path is now set before index creation and vector similarity queries, ensuring operator classes (e.g. vector_cosine_ops) and distance operators (e.g. <=>) resolve correctly regardless of where the extension is installed. Previously, only table creation set the search_path, causing CREATE INDEX and query operations to fail with unresolvable operator errors. (#14526)
Added entityVersionId, parentEntityVersionId, and rootEntityVersionId columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added targetType, targetId, agentVersion, and status filters to listExperiments, and traceId and status filters to listExperimentResults. (#15317)
Added PageLayout and PageHeader compound components for consistent page structure across Mastra Studio, plus a NoDataPageLayout helper for 401/403/empty/error states. (#15243)
List components (AgentsList, WorkflowsList, ToolsList, ProcessorsList, McpServersList, PromptsList, LogsList, ObservabilityTracesList) no longer handle errors or empty states internally — handle those at the page level. If you consume these components directly, move error/empty-state rendering to the parent.
Fix dataset detail tab badges to use total item and experiment counts instead of currently loaded rows. (#14994)
Added EntityList.Pagination sub-component for server-side pagination of EntityList views. Mirrors the existing ItemList.Pagination API. (#15353)
Added ValueLink, ValueWithTooltip, and ValueWithCopyBtn variants to DataKeysAndValues component (#15208)
Refresh Studio Evaluation pages with an updated UI and flattened top-level URLs (/scorers, /datasets, /experiments; /evaluation remains as the overview). @mastra/playground-ui removes EvaluationDashboard and all Evaluation*-prefixed list components, constants, and hooks — use the per-domain replacements (e.g. ScorersList) instead. (#15258)
Fixed DataList to only take as much height as its content needs instead of always stretching to fill available space (#15291)
{messages: [...]} and output objects with text are now properly extracted and formatted. (#15203)--- (#14624)
@mastra/schema-compat: patch
Improved provider schema compatibility for structured outputs and tool calls. Fixed validation for optional, nullable, and defaulted fields, and for ISO date strings returned for date fields.
Fixed stack traces for errors reported to Sentry. Exceptions now point to the code that threw the error instead of SentryExporter.handleSpanEnded inside the exporter, so issues in Sentry are actually debuggable. (#15343)
This was caused by two issues, both fixed:
@mastra/sentry passed the error message as a string to Sentry.captureException, which made Sentry synthesize a stack trace from the exporter's call site. It now passes an Error instance with the captured stack attached.@mastra/observability stored the wrapping MastraError's stack on the span, hiding the original error's location. When the MastraError has a cause, the cause's stack is now preserved.Fixes #15337.
feat(server): Add mapUserToResourceId callback to auth config for automatic resource ID scoping (#13954)
Auth configs now accept a mapUserToResourceId callback that maps the authenticated user to a resource ID after successful authentication. This enables per-user memory and thread isolation without requiring custom middleware or adapter subclassing.
const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => verifyToken(token),
mapUserToResourceId: user => user.id,
},
},
});
The callback is called in coreAuthMiddleware after the user is authenticated and set on the request context. The returned value is set as MASTRA_RESOURCE_ID_KEY, which takes precedence over client-provided values for security. Works across all server adapters (Hono, Express, Next.js, etc.).
fix(server): Strip reserved context keys from client-provided requestContext (#13954)
Clients could inject mastra__resourceId or mastra__threadId via the request body or query params to impersonate other users' memory/thread access. Reserved keys are now filtered out during request context creation in mergeRequestContext, so only server-side code (auth callbacks, middleware) can set them.
exit_type to prevent restore dialogs, kills orphaned Chrome child processes, and uses CDP events for reliable disconnect detection in both shared and thread scope. (#15194)Added support for Sarvam's current TTS and STT models. Previously the package only supported the now-deprecated bulbul:v1 and saarika:v1/v2/flash models, which Sarvam has retired. (#15204)
What's new:
bulbul:v2, bulbul:v3 (default), and bulbul:v3-beta. bulbul:v3 and bulbul:v3-beta support 39 speakers; bulbul:v2 supports 7 speakers.saarika:v2.5 (default) and saaras:v3. saaras:v3 is a multi-mode model that supports transcribe, translate, verbatim, translit, and codemix via a new mode option.temperature, dict_id, output_audio_codec.speech_sample_rate options: 8000, 16000, 22050, 24000, 32000, 44100, 48000.Breaking changes:
bulbul:v1 TTS model and its speakers (meera, pavithra, maitreyi, arvind, amol, amartya, diya, neel, misha, vian, arjun, maya). Sarvam has retired the underlying API.saarika:v1, saarika:v2, and saarika:flash STT models.bulbul:v3 and the default speaker is shubh. Speakers are not interchangeable between bulbul versions — each has its own catalog.text (single string) instead of inputs (array), matching Sarvam's current API.Migration:
Before:
const voice = new SarvamVoice({
speechModel: { model: 'bulbul:v1', language: 'en-IN' },
speaker: 'meera',
listeningModel: { model: 'saarika:v2' },
});
After:
const voice = new SarvamVoice({
speechModel: { model: 'bulbul:v3', language: 'en-IN' },
speaker: 'shubh',
listeningModel: { model: 'saarika:v2.5' },
});
// Or use saaras:v3 for speech translation:
await voice.listen(audio, { model: 'saaras:v3', mode: 'translate' });
Resolves #15188.
The following packages were updated with dependency changes only:
@mastra/azure)New @mastra/azure adds an Azure Blob Storage WorkspaceFilesystem provider (@mastra/azure/blob) and an AzureBlobStore content-addressable store for skill versioning, with support for connection string, account key, SAS token, DefaultAzureCredential, anonymous auth, prefix namespacing, and read-only mode.
agent.streamUntilIdle() (plus POST /api/agents/:agentId/stream-until-idle) keeps SSE streaming open until all background tasks finish, then automatically re-invokes the agent so task results are incorporated without needing a second user message; client-js and React useChat now use this flow.
resume-stream)Mastra Server adds POST /agents/:agentId/resume-stream and @mastra/client-js adds agent.resumeStream() so apps can resume a previously suspended run with custom data (e.g., approvals/choices) via the client SDK.
A new forked flag for HarnessSubagent (and the built-in subagent tool input) runs subagents on a cloned parent thread to preserve prompt-cache prefix while isolating writes; forks inherit parent tools/instructions, flush pending message saves before cloning, and are hidden from Harness.listThreads() by default unless explicitly included.
@mastra/mcp adds a jsonSchemaValidator pass-through for MCPClient and MCPServer, enabling validators like CfWorkerJsonSchemaValidator so tools with outputSchema work in environments where Ajv’s new Function(...) compilation is blocked.
Added prepareRun and filterRun utilities for scorer input preparation, allowing scorers to filter and transform agent messages before scoring. Scorers can now declare a prepareRun hook or use the filterRun builder to select specific message part types and tool names before scoring runs. (#15642)
Added getCurrentTraceId() to Harness, which captures the observability trace ID from agent stream responses. This allows callers to correlate feedback and other annotations to the correct trace.
Added progressThrottleMs to background task configuration so high-frequency progress output can be coalesced before it reaches pubsub and stream consumers. (#15829)
const mastra = new Mastra({
backgroundTasks: {
enabled: true,
progressThrottleMs: 500,
},
});
Added forked subagents: a new forked flag on HarnessSubagent definitions and the built-in subagent tool input. When set, the subagent runs on a clone of the parent thread using the parent agent's instructions and tools, preserving prompt-cache prefix while isolating writes from the main conversation. (#15695)
Stop logging client-disconnect aborts as Error in LLM execution at error level. The catch block in agentic-execution/llm-execution-step.ts now checks for isAbortError(error) first and exits via a debug-level log + the existing onAbort flow before the upstream-error / generic-error branches run. Closes #15844. (#15847)
Fixed Studio observability tabs so runtime-injected observability unlocks them. (#15821)
Update provider registry and model documentation with latest models and providers (b510d36)
Added a stream error retry processor with OpenAI Responses stream error matching. (#15760)
Enable ProviderHistoryCompat error processor by default in mastracode (#15730)
Fixed AgentChannels.consumeAgentStream silently dropping tripwire chunks, which left channel users (Slack, Discord) with no response when a strategy: "block" processor fired. The chunk is now handled: when retry is false/unset the block reason is posted to the channel (prefixed with the processorId when present); when retry is true the chunk is skipped so the agent's retried output can flow through normally. (#15692)
Fixed toModelOutput lookup for dynamically loaded tools via ToolSearchProcessor (#15452)
Replace wildcard ./* export with an explicit allowlist of 48 valid subpath exports. The wildcard combined with tsc emitting individual .d.ts files created phantom subpaths (e.g. @mastra/core/auth/ee/defaults) that compiled in TypeScript but crashed at runtime with MODULE_NOT_FOUND. The allowlist approach only exposes subpaths that have actual runtime JS, preventing phantom imports entirely. (#15794)
fix(tools): preserve args for programmatic tool calls when merging synthetic tool-call (#15227)
Fixes an issue where programmatic tool calls (PTC) received empty {} arguments during streaming.
When a synthetic tool-call was created with empty args, the real tool-call event (containing actual args) was ignored. This change ensures that args from the real tool-call are merged into the synthetic one when missing.
Fixed agents forcing temperature: 0 when the user did not explicitly set it. Previously, every agent.stream() / agent.generate() call silently injected temperature: 0 into model settings, which broke models that restrict acceptable temperature values (for example Moonshot Kimi K2.5, which only accepts temperature=1 and rejects any other value with 400 Bad Request). The model provider's own default is now used when the user does not configure a temperature. Users who explicitly set temperature (including temperature: 0 for deterministic output) are unaffected. Fixes #15240. (#15611)
Fix forked subagent fork threads starting with empty history. The parent stream's message saves are debounced through SaveQueueManager, so a forked subagent that calls memory.cloneThread mid-stream used to clone from an empty store and lose the parent's user + assistant turn. The tool now drains the parent save queue via a new flushMessages callback on AgentToolExecutionContext before cloning, so forks actually carry the prior conversation. (#15695)
The internal <subagent-meta /> tag is no longer appended to subagent tool result content. The tag was previously visible to the parent model in the tool result, which could cause it to be echoed back as literal markup in the parent's assistant text on subsequent turns. Live UIs continue to receive model / duration / tool-call information via the structured subagent_* events; history UIs read the persisted tool_call.args.modelId. parseSubagentMeta is retained so already-persisted threads carrying the legacy tag continue to render cleanly (and the tag is stripped before display in all cases). (#15695)
Forked subagents now inherit the parent agent's toolsets (so harness-injected tools like ask_user, submit_plan, and user-configured harness tools remain available inside a fork). The subagent tool entry is kept in the inherited toolset with its id, description, and schemas unchanged so the LLM request prefix stays byte-identical to the parent's and the prompt cache continues to hit; recursive forking is blocked at the runtime layer by replacing only the tool's execute with a stub that returns a "tool unavailable inside a forked subagent" message. Forked runs allow follow-up steps so the model can recover and answer directly if it accidentally calls that stub. Fork threads are tagged with metadata.forkedSubagent: true and metadata.parentThreadId, and Harness.listThreads() hides them by default so they don't surface in user-facing thread pickers; pass includeForkedSubagents: true to opt back in for admin/debug tooling. (#15695)
Mastra Code now renders forked subagent footers as subagent fork <parent model id>, including persisted history reloaded after the live event metadata is gone.
Added missing A2A vNext error variants for protocol 0.3 handling. (#15720)
Users now get a clear error when using Observational Memory with agent network. (#15808)
Improved skills discovery performance by parallelizing filesystem I/O operations. Discovery of multiple skills, subdirectory scanning, reference file reads, and staleness checks now run concurrently instead of sequentially. Also fixed a bug in CompositeVersionedSkillSource where the root directory stat always returned the current time, causing unnecessary re-discovery on every refresh cycle. (#14360)
Fixed tool strict: true being silently dropped when routing through V2 (AI SDK v5) OpenAI providers. V2 providers use a global strictJsonSchema provider option instead of per-tool strict, so Mastra now propagates the intent automatically — when any tool on a call has strict: true, providerOptions.openai.strictJsonSchema is set to true before the request is sent. Explicit user-supplied strictJsonSchema values are respected and never overridden. (#15450)
Fixed execute_command timeout handling for models that send numeric values as strings. (#15765)
Fixed resourceId not being forwarded to createRun() in the agentic loop, which caused persistWorkflowSnapshot to receive resourceId: undefined. (#15742)
Fixed agent loops so truncated model responses stop instead of retrying pending tool calls until max steps. (#15788)
Fixed dataset.startExperiment for workflow targets to match runEvals. Previously, scorers running inside a persisted experiment could not access per-step input or output, requestContext configured on the experiment was not forwarded into the workflow run, and direct agent calls inside workflow steps could start detached traces instead of nesting under the workflow step span. Step-level data is now exposed to scorers via run.targetMetadata.stepResults and run.targetMetadata.stepExecutionPath, the workflow's root span ID is available as run.targetSpanId, requestContext propagates into every step, and ambient workflow step tracing is used when creating nested spans. Fixes #15613. (#15792)
Fixed requireApproval being silently ignored for tools loaded dynamically via ToolSearchProcessor. The approval gate now fires a tool-call-approval event and pauses execution before running, matching the behaviour of tools registered directly on the agent. (#15782)
Fixed AI SDK v5 message rehydration so suspended and approval tool state data parts are restored from persisted message metadata after reload. (#14246)
Fixed the TypeScript type for requireApproval on tools so it accepts a function in addition to a boolean. The runtime already supported per-call approval functions (added in #15346), but the type still required boolean, forcing an as any cast. You can now pass a sync or async predicate without a cast — the predicate receives the validated tool input and an optional { requestContext, workspace } second argument. Fixes #15647. (#15783)
Added ProviderHistoryCompat error processor that automatically sanitizes tool-call IDs when switching between LLM providers. When a provider rejects tool IDs from another provider's history (e.g. Anthropic enforces ^[a-zA-Z0-9_-]+$), the processor rewrites invalid characters and retries the request. (#15730)
Add agent.streamUntilIdle() and default sub-agents to run as background tasks. (#15686)
streamUntilIdle
A new agent streaming method that keeps the stream open until all background tasks dispatched during the turn complete. When a task finishes, the agent is re-invoked automatically so the result is processed in the same call — no second user turn required.
// Before — stream closes once the LLM returns. Background task
// results are only processed on the next user message.
const result = await agent.stream('Research quantum computing', { memory });
for await (const chunk of result.fullStream) {
/* ... */
}
// After — stream stays open through the background task completion
// and the follow-up agent turn; the final answer arrives in the same call.
const result = await agent.streamUntilIdle('Research quantum computing', { memory });
for await (const chunk of result.fullStream) {
/* ... */
}
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Add @mastra/azure, exporting an Azure Blob Storage WorkspaceFilesystem provider via @mastra/azure/blob with support for connection string, account key, SAS token, DefaultAzureCredential, and anonymous auth, plus prefix namespacing and read-only mode. (#15217)
Added AzureBlobStore, a content-addressable blob store backed by Azure Blob Storage for skill versioning. Available alongside the existing AzureBlobFilesystem from @mastra/azure/blob. (#15853)
import { AzureBlobStore } from '@mastra/azure/blob';
const blobs = new AzureBlobStore({
container: 'my-skill-blobs',
connectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
});
Supports the same authentication methods as AzureBlobFilesystem: connection string, account key, SAS token, DefaultAzureCredential, and anonymous access. A matching azureBlobStoreProvider descriptor is also exported for MastraEditor.
Added support for resuming suspended agent streams over HTTP with custom data. This adds the POST /agents/:agentId/resume-stream server endpoint and the client SDK agent.resumeStream() method, so apps can continue a suspended agent run through the Mastra client. (#14579)
Usage example (client SDK):
const agent = mastraClient.getAgent('my-agent');
// Resume a suspended agent stream with custom data
const response = await agent.resumeStream(
{ approved: true, selectedOption: 'plan-b' },
{ runId: 'previous-run-id', toolCallId: 'tool-123' },
);
await response.processDataStream({
onChunk: chunk => console.log(chunk),
});
Improved the Mastra A2A client to feel closer to the official A2A SDK without introducing a breaking change. (#15720)
getAgentCard(), sendMessageStream(), getExtendedAgentCard(), and getTaskPushNotificationConfig().sendMessageStream() and resubscribeTask().getCard() and sendStreamingMessage().Fixed Studio observability tabs so runtime-injected observability unlocks them. (#15821)
Add streamUntilIdle to the agent client, mirroring the new server route. The client keeps the SSE connection open through background task completion and the agent's follow-up turn, and preserves the /stream-until-idle endpoint across client-tool continuations. (#15686)
const stream = await client.getAgent('my-agent').streamUntilIdle({
messages: 'Research quantum computing',
});
for await (const chunk of stream) {
/* ... */
}
Fixed slow or stuck mastra dev startup in large monorepos when workspace packages share internal dependencies. (#12963)
What changed
Fixes #12843.
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Refactored Hono adapter's registerCustomApiRoutes() to use the shared buildCustomRouteHandler() from the base class instead of duplicating route/handler resolution logic. Added forwardCustomRouteRequest() to the base class for adapters that already have a raw Request object (avoiding unnecessary request reconstruction). (#15793)
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Added jsonSchemaValidator pass-through option on MCPClient server entries and MCPServer. Forward this option from @modelcontextprotocol/sdk to opt into a non-default validator. Pass CfWorkerJsonSchemaValidator from @modelcontextprotocol/sdk/validation/cfworker to make tools with outputSchema work in Cloudflare Workers / V8 isolates, where the default Ajv validator's new Function(...) compile path is blocked. (#15866)
import { MCPClient, MCPServer } from '@mastra/mcp';
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/cfworker';
const mcp = new MCPClient({
servers: {
upstream: {
url: new URL('https://example/mcp'),
jsonSchemaValidator: new CfWorkerJsonSchemaValidator(),
},
},
});
const server = new MCPServer({
name: 'My Server',
version: '1.0.0',
tools: { ... },
jsonSchemaValidator: new CfWorkerJsonSchemaValidator(),
});
Closes #15862.
Added shared ThemeProvider, useTheme, and ThemeToggle to unify theme management. (#15838)
Added
ThemeProvider applies the resolved theme class to <html> and persists the choice under the shared mastra-theme localStorage key, with a one-time migration from previously stored preferences.useTheme() works without a <ThemeProvider> ancestor: it returns a read-only fallback that tracks the OS color scheme and exposes a no-op setTheme, so theme-aware leaf components (e.g. CodeDiff, CodeEditor) keep working when embedded standalone.ThemeToggle renders a system/light/dark pill and supports both controlled and uncontrolled usage.Migrated color tokens to oklch() for perceptually uniform, wide-gamut (P3) ready colors. Light theme neutrals and surfaces no longer have a blue tint (slate → true gray). Dark theme is visually unchanged. (#15713)
Added shared Logs components and hooks under @mastra/playground-ui. Consumers can now reuse the Logs page building blocks together with the data hooks and the URL-state / filter-persistence helpers instead of duplicating them per app. (#15723)
Added shared metrics components and hooks under @mastra/playground-ui. Consumers can now reuse the metrics dashboard building blocks (KPI, Latency, Scores, Token Usage, Trace Volume, Model Usage Cost cards), their data hooks, and the MetricsProvider / DateRangeSelector primitives instead of duplicating them per app. (#15705)
New peer dependency: @tanstack/react-query ^5.90.21. Add it alongside your existing playground-ui install.
Added shared Traces components and hooks under @mastra/playground-ui. Consumers can now reuse the Traces page building blocks together with the data hooks and the URL-state / filter-persistence helpers instead of duplicating them per app. (#15714)
Fixed the logs date filter button height to match other filter controls. (#15801)
posthog-node from v4 to v5 to pick up the latest fixes and LLM analytics improvements. Resolves #15858. (#15867)agent.streamUntilIdle method and the background-task chunks are processed in toUIMessage. (#15686)Added AWS credential provider chain support to S3Filesystem and S3BlobStore. You can now pass a credentials option with a credential provider function (e.g. fromNodeProviderChain()) for auto-refreshing credentials on ECS, Lambda, SSO, or AssumeRole deployments. When all credential options are omitted, the AWS SDK default credential provider chain is used automatically instead of falling back to anonymous access. Static accessKeyId/secretAccessKey credentials continue to work as before. (#15437)
New credentials option
import { S3Filesystem } from '@mastra/s3';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
// Auto-refreshing credentials (ECS task role, SSO, etc.)
const fs = new S3Filesystem({
bucket: 'my-bucket',
region: 'us-east-1',
credentials: fromNodeProviderChain(),
});
SDK default credential chain (no credentials needed)
// Credentials discovered from environment automatically
const fs = new S3Filesystem({
bucket: 'my-bucket',
region: 'us-east-1',
});
Added support for resuming suspended agent streams over HTTP with custom data. This adds the POST /agents/:agentId/resume-stream server endpoint and the client SDK agent.resumeStream() method, so apps can continue a suspended agent run through the Mastra client. (#14579)
Usage example (client SDK):
const agent = mastraClient.getAgent('my-agent');
// Resume a suspended agent stream with custom data
const response = await agent.resumeStream(
{ approved: true, selectedOption: 'plan-b' },
{ runId: 'previous-run-id', toolCallId: 'tool-123' },
);
await response.processDataStream({
onChunk: chunk => console.log(chunk),
});
Fixed Studio observability tabs so runtime-injected observability unlocks them. (#15821)
Authentication now refreshes expired server-side sessions transparently, so recoverable token expiry no longer causes unexpected user sign-outs. Only truly expired sessions (e.g. refresh token dead) return a 401. (#15819)
Server adapters now forward refreshed session cookies consistently, and auth-studio logs session validation and refresh failures to improve diagnostics.
Updated the A2A server to match the v0.3 protocol shapes and methods. (#15720)
Refactored Hono adapter's registerCustomApiRoutes() to use the shared buildCustomRouteHandler() from the base class instead of duplicating route/handler resolution logic. Added forwardCustomRouteRequest() to the base class for adapters that already have a raw Request object (avoiding unnecessary request reconstruction). (#15793)
Custom API routes now validate that their paths don't collide with the built-in route prefix. If a custom route path starts with the server's apiPrefix (default /api), a descriptive error is thrown at startup. This prevents custom routes from shadowing built-in Mastra routes (e.g. /api/agents, /api/tools). (#15743)
Add POST /api/agents/:agentId/stream-until-idle SSE route that mirrors agent.streamUntilIdle(). The route keeps the SSE stream open through background task completion and the agent's follow-up turn, so clients receive the final answer in a single request. (#15686)
The following packages were updated with dependency changes only:
Agents can now dispatch slow tool calls as background tasks while the main conversation keeps streaming, then inject results back into the loop when they finish. This comes with new /api/background-tasks endpoints (list/get/SSE stream), client methods (listBackgroundTasks, getBackgroundTask, streamBackgroundTasks), and new BackgroundTasksStorage domain implementations across major storage adapters.
@mastra/redis)Introduces @mastra/redis, a Redis-backed Mastra storage provider (memory/workflows/scores) using the official node-redis client, with flexible connection options including connection strings or injected preconfigured clients.
NetlifyDeployer adds a target: 'edge' option to deploy as Netlify Edge Functions (Deno at the edge) with CPU-time limits instead of hard wall-clock timeouts—better suited for longer-running AI workflows than 60s serverless limits.
RAG ingestion runs now appear in observability traces alongside agents/workflows, and traces can be filtered by traceId. New lightweight schemas and endpoints (including GET /observability/traces/:traceId/light and storage getTraceLight) reduce timeline payloads dramatically by omitting heavy span fields until details are requested.
Span serialization is hardened to prevent LLM/API credentials and auth headers from leaking into telemetry across routers, gateways, and model wrappers. Additionally, server calls can now set tracingOptions (tags, hideInput, hideOutput) per request to control span labeling and redaction.
RAG ingestion runs now appear in observability traces, next to your agents, workflows, and scorers. (#15512)
You can now filter traces by traceId when listing them.
Added lightweight span and trace schemas (LightSpanRecord, GetTraceLightResponse) that exclude heavy fields like input, output, attributes, and metadata — reducing per-span payload by ~97% for timeline rendering.
Fixed potential credential leakage in observability spans. LLM API keys, authentication headers, and gateway tokens could previously appear in span input or output data sent to telemetry backends. (#15489)
What's fixed
The model router, AI SDK model wrappers (v4 legacy, v5, v6), built-in gateways (Mastra, Netlify, Models.dev, Azure OpenAI), and the voice provider base class now restrict what they expose to spans. Only public identity fields — model ID, provider, gateway ID, voice name — are included. Private configuration such as API keys, Authorization headers, OAuth tokens, and proxy credentials is no longer serialized into spans.
Legacy AI SDK v4 models passed to resolveModelConfig were previously returned unwrapped. They are now wrapped in AISDKV4LegacyLanguageModel, which applies the same serializeForSpan() safety as the v5/v6 wrappers while preserving the LanguageModelV1 interface so existing consumers continue to work.
The SensitiveDataFilter span output processor already redacted values under common field names (apiKey, token, authorization, etc.) when enabled. This fix closes the gap for users who did not have it configured, and for cases where credentials were nested under custom field names that the filter's exact-match list did not cover.
Recommended action
MastraModelGateway and custom voice providers extending MastraVoice are automatically covered — they inherit the new safe default. Override serializeForSpan() only if you want to expose additional non-sensitive fields.input, output, attributes, or metadata) that holds enumerable fields with credentials or other sensitive state, add a serializeForSpan() method. TypeScript-private properties are still walked by span serialization because private is compile-time only.class MyServiceClient {
constructor(private config: { apiKey: string; endpoint: string }) {}
// Without this, spans carrying a MyServiceClient instance would
// serialize `config.apiKey` through every enumerable property.
serializeForSpan() {
return { endpoint: this.config.endpoint };
}
}
Added support for sub-agent version overrides in core execution. Global defaults can be set on the Mastra instance and overridden per generate()/stream() call, with cascading propagation via requestContext. (#15373)
Added per-entry modelSettings, providerOptions, and headers to agent model fallback arrays. Each entry can now specify its own temperature, topP, provider-specific options, and HTTP headers — either statically or as a function of requestContext. Closes #15421. (#15429)
Example
const agent = new Agent({
model: [
{
model: 'google/gemini-2.5-flash',
maxRetries: 2,
modelSettings: { temperature: 0.3 },
providerOptions: { google: { thinkingConfig: { thinkingBudget: 0 } } },
},
{
model: 'openai/gpt-5-mini',
maxRetries: 2,
modelSettings: { temperature: 0.7 },
providerOptions: { openai: { reasoningEffort: 'low' } },
},
],
});
Precedence:
modelSettings and providerOptions: per-fallback entry > call-time stream() / generate() options > agent defaultOptions. modelSettings shallow-merges by key; providerOptions deep-merges recursively, preserving sibling and nested keys.headers: call-time modelSettings.headers > per-fallback headers > model-router-extracted headers. This preserves the existing Mastra contract from #11275, where runtime headers (typically tracing, auth, tenancy) intentionally override model-level headers.Added activateAfterIdle setting for observational memory so buffered observations can activate after idle time before the next prompt. (#15365)
Example
Set activateAfterIdle: 300_000 (or "5m") on the observationalMemory config to activate buffered context after 5 minutes of inactivity.
This helps long-running threads reuse compressed context after prompt cache TTLs expire instead of sending a larger raw message window on the next request.
You can now opt into parent-agent reuse for the separate structured-output pass with structuredOutput: { schema, model, useAgent: true }, which lets the structuring request reuse the parent agent config, including memory. (#15318)
Added unique IDs (logId, metricId, scoreId, feedbackId) to all observability signals, generated automatically at emission time for de-duplication across the framework pipeline and cross-system correlation. User-facing APIs (logger.info(), metrics.emit(), addScore(), addFeedback()) are unchanged. (#15242)
For existing ClickHouse and DuckDB observability signal tables, run npx mastra migrate before initializing the store so the new signal-ID schema is applied.
Processor traces now store hook-specific inputs and only include changed outputs, reducing payload size while keeping traces more replayable. If you consume PROCESSOR_RUN payloads directly, update any dashboards or parsers that depend on the previous shape. (#15493)
Fixed CompositeAuth types so typed auth providers, such as SimpleAuth<MyUser> or MastraAuthClerk, can be combined without casts. (#15556)
Update provider registry and model documentation with latest models and providers (3d83d06)
Fixed browser context reminders breaking prompt cache. Browser reminders are now added as new user messages instead of modifying existing message history. (#15417)
Fixed Harness subagent tracing so delegated runs keep the parent tracing context and show up in the same trace in observability exporters. Fixes #15461. (#15473)
Refactored how assistant messages are constructed during streaming. Messages are now built from the complete chunk sequence after each step instead of being assembled mid-stream. This fixes duplicate OpenAI item IDs (rs_*, msg_*), eliminates empty text parts from streaming artifacts, and ensures provider metadata is correctly attributed. (#15454)
Fixed nested workflows dropping resourceId when executed as a step of a parent workflow. Child workflow snapshots now preserve the parent run's resource association, so tenant-scoped persistence works end-to-end. Closes #15246. (#15447)
const run = await parent.createRun({
runId: 'run-1',
resourceId: 'workspace-1',
});
await run.start({ inputData: { ok: true } });
// Before: child snapshots persisted with resourceId: undefined
// After: child snapshots persisted with resourceId: 'workspace-1'
Fixed a security issue where several parsing and tracing paths could slow down on malformed or attacker-crafted input. Normal behavior is unchanged, and these packages now handle pathological input in linear time. (#15566)
Fixed messages not being persisted when multiple memory processors are used together. Processor state is now correctly passed between chained workflow steps, ensuring all messages are saved. (#14884)
Fix prototype pollution in setNestedValue (@mastra/core/utils) and generateOpenAPIDocument (@mastra/server). (#15565)
setNestedValue now rejects dot-path segments named __proto__, constructor, or prototype, preventing attacker-controlled field paths passed to selectFields from polluting Object.prototype. generateOpenAPIDocument builds its paths map with Object.create(null) so a route path of __proto__ cannot poison the prototype chain.
Fixed assistant model attribution so provider and model information is preserved more reliably in stored assistant messages. (#15462)
Loop runs now keep the resolved model on the first step-start, already-attributed step-start parts are left alone, and post-tool assistant continuations preserve their incoming metadata when they merge into an existing assistant message.
This keeps downstream features working with the correct model identity instead of falling back to incomplete metadata or losing it during merge.
Fixed channel webhook handling in Node.js when no execution context is available. (#15441)
Recalled V4 messages now preserve data-* message parts (e.g. data-tool-call-suspended) after a page refresh, so suspended HITL workflows can resume correctly. (#14211)
Fixed structured output to keep persisted assistant text behavior aligned with existing memory recall paths. (#15318)
Fixed processOutputStep not receiving token usage data. Output processors now receive usage (inputTokens, outputTokens, totalTokens) for the current LLM step, enabling per-step cost tracking and token budget enforcement. (#15068)
Fixed requireApproval on tools to accept a function in addition to a boolean. Previously, passing a function for requireApproval on a tool created with createTool was silently ignored and approval was never required. (#15346)
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
createTool({
id: 'delete-file',
description: 'Delete a file',
inputSchema: z.object({ path: z.string() }),
// Now works: only require approval for paths outside /tmp
requireApproval: input => !input.path.startsWith('/tmp/'),
execute: async ({ context }) => {
// ...
},
});
Fixed resume errors for suspended agent runs: resumeStream() and resumeGenerate() now return a clear message when storage is missing or the runId is invalid. (#15514)
Fixed OpenAI tool strict mode when requests pass through the model router. strict: true on function tools now survives compatibility prep, so OpenAI Responses models receive strict tool definitions instead of silently downgrading them to non-strict. (#15397)
Added multi-select choices to the Harness ask_user tool. (#15485)
Fixed noisy browser reminders being added to non-browser turns. Browser reminders are now added only when browser context exists (for example, current page URL or title). (#15416)
Fixed dataset.startExperiment hanging forever when targetType is 'workflow'. Workflow experiments now complete normally, honour itemTimeout, and surface failures. Fixes #15453. (#15570)
Fixed PrefillErrorHandler to recover from Qwen/llama.cpp prefill rejections with enable_thinking, so agents retry with a continue reminder instead of failing after skill/tool turns. (#15518)
Add background task execution for agents. Agents can dispatch slow tool calls to run asynchronously while the conversation keeps streaming, and results are injected back into the loop when they complete. (#15307)
Fixed fallback model attribution in agent traces. When an agent fell back after the primary model failed, token usage and cost were reported against the primary model instead of the fallback that actually served the response (e.g. in Langfuse). Fixes #13547. (#15503)
Fixed agent stream errors when providers end a stream without an error payload. (#15435)
Fixed provider-defined tools with custom execute callbacks (e.g. openai.tools.applyPatch) being incorrectly skipped during execution. Previously, all provider-defined tools were assumed to be provider-executed, which meant user-supplied execute functions were never called. Now, provider tools with a custom execute are correctly identified as client-executed. (#14819)
Added model metadata to step-start parts so model changes can be detected across steps, including within a single assistant message. (#15420)
Fixed message serialization to preserve millisecond precision in createdAt timestamps. (#15500)
Fixed workflow streaming in @mastra/ai-sdk so intermediate data-workflow parts stop repeating every completed step output. Added data-workflow-step parts with the full payload for the step that just changed, which reduces stream size for long-running workflows while preserving final workflow outputs. (#15218)
If your UI reads live step outputs during workflow execution, it should now consume data-workflow-step parts in addition to data-workflow. Final workflow snapshots still include the full step outputs.
Fix AI SDK v6 approval replay so ordinary user follow-up turns do not resume stale approval responses. (#15480)
Fixed tool call approvals in AI SDK v6: handleChatStream now automatically routes to resumeStream when the AI SDK v6 native approval flow is used on the client (no extra server-side wiring required). The v6 stream now emits native tool-approval-request parts so useChat can surface approval UI and call addToolApprovalResponse(), while also emitting the existing data-tool-call-approval chunk for backwards compatibility. (#15345)
Fixed AI SDK v6 tool approval streams so requireApproval works with handleChatStream and AssistantChatTransport. (#15345)
Added unique IDs (logId, metricId, scoreId, feedbackId) to all observability signals, generated automatically at emission time for de-duplication across the framework pipeline and cross-system correlation. User-facing APIs (logger.info(), metrics.emit(), addScore(), addFeedback()) are unchanged. (#15242)
For existing ClickHouse and DuckDB observability signal tables, run npx mastra migrate before initializing the store so the new signal-ID schema is applied.
Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
Added forEachIndex option to run.resume(), run.resumeAsync(), and run.resumeStream(). Use it to resume a single iteration of a suspended .foreach() step while leaving the other iterations suspended. (#15563)
await client
.getWorkflow('myWorkflow')
.createRun(runId)
.resume({
step: 'approve',
resumeData: { ok: true },
forEachIndex: 1, // only resume the second iteration
});
Add /api/background-tasks routes (SSE stream, list with filters + pagination, get by ID) and matching MastraClient methods (listBackgroundTasks, getBackgroundTask, streamBackgroundTasks). (#15307)
Fixed @mastra/client-js to re-export RequestContext so client SDK users can import it from @mastra/client-js. (#15413)
Added observabilityRuntimeStrategy to GetSystemPackagesResponse so clients can read the active observability tracing strategy (realtime, batch-with-updates, insert-only, or event-sourced) reported by the server. (#15512)
BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)Added target option to NetlifyDeployer for deploying as Netlify Edge Functions. (#13103)
export const mastra = new Mastra({
deployer: new NetlifyDeployer({
target: 'edge',
}),
});
Edge functions run on Deno at the network edge, closer to users, with no hard execution timeout (only a CPU time limit). This makes them a better fit for longer-running AI workflows that may exceed the 60s serverless function timeout.
The default target remains 'serverless', so existing usage is unaffected.
Added @mastra/docker, a Docker container sandbox provider for Mastra workspaces. Executes commands inside local Docker containers using long-lived containers with docker exec. Supports bind mounts, environment variables, container reconnection by label, custom images, and network configuration. Targets local development, CI/CD, air-gapped deployments, and cost-sensitive scenarios where cloud sandboxes are unnecessary. (#14500)
Usage
import { Agent } from '@mastra/core/agent';
import { Workspace } from '@mastra/core/workspace';
import { DockerSandbox } from '@mastra/docker';
const workspace = new Workspace({
sandbox: new DockerSandbox({
image: 'node:22-slim',
timeout: 60_000,
}),
});
const agent = new Agent({
name: 'dev-agent',
model: 'anthropic/claude-opus-4-6',
workspace,
});
Added unique IDs (logId, metricId, scoreId, feedbackId) to all observability signals, generated automatically at emission time for de-duplication across the framework pipeline and cross-system correlation. User-facing APIs (logger.info(), metrics.emit(), addScore(), addFeedback()) are unchanged. (#15242)
For existing ClickHouse and DuckDB observability signal tables, run npx mastra migrate before initializing the store so the new signal-ID schema is applied.
Fixed DuckDB installs by using a resolvable @duckdb/node-api version range. (#15419)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)nack support and deliveryAttempt tracking on the subscriber callback, and enable exactly-once delivery on grouped subscriptions. (#15307)BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)Added new attribute mappings to the Langfuse exporter so more Mastra attributes are filterable in Langfuse's UI. (#15445)
Observation-level metadata — gen_ai.agent.id, gen_ai.agent.name, mastra.span.type, and gen_ai.operation.name are now mapped to langfuse.observation.metadata.*, making them top-level filterable keys on each observation. This lets you scope Langfuse evaluators to specific agents or span types.
Trace-level attributes — mastra.metadata.traceName and mastra.metadata.version are now mapped to langfuse.trace.name and langfuse.trace.version, enabling custom trace names and version-based filtering.
Fixed a security issue where several parsing and tracing paths could slow down on malformed or attacker-crafted input. Normal behavior is unchanged, and these packages now handle pathological input in linear time. (#15566)
Improved Langfuse trace batching for streamed runs by adding flushAt and flushInterval controls. (#15460)
Use DiskANN vector_top_k() index for faster vector queries when available (#14913)
LibSQLVector.query() now automatically uses the existing DiskANN index for approximate nearest neighbor search instead of brute-force full table scans, providing 10-25x query speedups on larger datasets. Falls back to brute-force when no index exists.
Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
Fixed MCP tool strict mode propagation. MCP servers now expose Mastra tool strictness in MCP metadata, and the MCP client restores that flag when rebuilding tools so strict OpenAI tool calling works for MCP-backed tools too. (#15397)
Fixed MCP tools with recursive JSON Schema refs so they stay serializable when loaded. (#15400)
Added activateAfterIdle setting for observational memory so buffered observations can activate after idle time before the next prompt. (#15365)
Example
Set activateAfterIdle: 300_000 (or "5m") on the observationalMemory config to activate buffered context after 5 minutes of inactivity.
This helps long-running threads reuse compressed context after prompt cache TTLs expire instead of sending a larger raw message window on the next request.
Added activateOnProviderChange so observational memory can activate buffered observations and reflections before switching to a different provider or model. (#15420)
const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
activateOnProviderChange: true,
},
},
});
This helps keep prompt-cache savings when the next step cannot reuse the previous provider's cache.
Fixed early observational memory activations so buffered reflections are only activated when they still leave a healthy active observation set. (#15462)
Before this change, idle-timeout (activateAfterIdle) and model/provider-change (activateOnProviderChange) activations could swap in a buffered reflection too early. In bad cases, that replaced a large raw observation tail with a much smaller mostly-compressed result, which hurt reflection quality.
Early activations now stay buffered unless both of these checks pass:
This update also fixes false provider_change activations when older persisted messages only contain a bare model id like gpt-5.4 while newer turns use the fully qualified provider/modelId form.
Fixed a security issue where several parsing and tracing paths could slow down on malformed or attacker-crafted input. Normal behavior is unchanged, and these packages now handle pathological input in linear time. (#15566)
Fixed other-thread context filtering falling back to the observational memory record timestamp when thread metadata is missing. (#15269)
Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
Changed MODEL_CHUNK tool-result span output handling. (#15495)
What changed
MODEL_CHUNK spans for tool-result now omit output for locally executed tools.TOOL_CALL remains the canonical span for locally executed tool result payloads.MODEL_CHUNK spans for provider-executed tool-result chunks still include output.MODEL_CHUNK metadata still includes toolCallId, toolName, and providerExecuted.Why
This reduces duplicate tool result payloads in traces without dropping provider-emitted tool results that may not have a matching TOOL_CALL span.
Added unique IDs (logId, metricId, scoreId, feedbackId) to all observability signals, generated automatically at emission time for de-duplication across the framework pipeline and cross-system correlation. User-facing APIs (logger.info(), metrics.emit(), addScore(), addFeedback()) are unchanged. (#15242)
For existing ClickHouse and DuckDB observability signal tables, run npx mastra migrate before initializing the store so the new signal-ID schema is applied.
Fixed span serialization replacing tool parameter JSON schemas with lossy summaries like "unknown (required)". JSON schemas in span data are now preserved as-is, keeping full type information for debugging in observability tools like Datadog. Also fixed MODEL_STEP span input showing only a keys summary instead of actual messages for AI SDK v5 providers. (#15404)
Fixed CloudExporter to default to observability.mastra.ai for Mastra platform exports. (#15418)
Improved tracing overhead when filtering spans. Spans dropped by excludeSpanTypes or the internal-span filter (includeInternalSpans: false) now skip payload serialization and retention entirely instead of paying the cost and discarding at export time. (#15487)
undefined from OtelBridge.createSpan when no OpenTelemetry SDK is registered, so core generates valid span/trace IDs instead of reusing the OTEL no-op all-zero IDs. This prevents downstream trace exporters from dropping spans and stops the infinite-loop CPU spike in parent-matching. Fixes #15589. (#15591)Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Added getTraceLight method to the observability storage, returning only lightweight span fields needed for timeline rendering. This avoids transferring heavy fields like input, output, attributes, and metadata when they are not needed. (#15574)
Added ErrorBoundary component to catch and display runtime errors in the studio. Wraps routes in the local playground so a crash on one page (e.g. an agent editor referencing an unresolved workspace skill) surfaces a friendly recovery UI with Try again (in-place React reset), Reload page (full browser refresh), and Report issue (opens the Mastra GitHub issues page in a new tab) actions, plus a collapsible stack trace — instead of a blank screen. (#15561)
The fallback is spatially aware: it fills its parent and the icon, heading, and body text scale up on wider containers via Tailwind container queries. Scope the boundary to a single widget to keep the rest of the UI interactive while one panel fails.
Usage
import { ErrorBoundary } from '@mastra/playground-ui';
import { useLocation } from 'react-router';
// Route-level: wrap the router outlet, reset when the path changes
function Layout({ children }) {
const { pathname } = useLocation();
return <ErrorBoundary resetKeys={[pathname]}>{children}</ErrorBoundary>;
}
// Scoped: contain the crash to one panel, leave the rest of the tree alone
<ErrorBoundary variant="inline" title="The editor failed to render">
<AgentEditor />
</ErrorBoundary>;
Props: fallback (node or render prop with { error, errorInfo, reset }), onError for reporting, resetKeys for automatic reset, variant ('section' — fills available space, default; 'inline' — stays compact), and title / description overrides.
Added BrandLoader, a branded pulse-wave loader component for brand moments like app boot or agent thinking. Complements Spinner, which remains the inline utility loader. (#15490)
Added new Logo component to the playground-ui design system. Supports two sizes (sm, md), uses currentColor for theming, and includes an optional outline-on-hover animation that respects prefers-reduced-motion. (#15513)
Added a dedicated trace details page at /traces/:traceId, plus the design-system changes that support it: (#15392)
Button: new link variant (inline, no padding/background/border).DataKeysAndValues: numOfCol now accepts 3.DataPanel.Header: minimum height so heading-only headers match the height of ones with button actions.Fix unhandled TypeError in getFileContentType when the URL is relative (#15433)
or malformed. The catch block now falls back to inferring the MIME type
from the raw string's file extension and strips query/hash fragments so
inputs like /files/report.pdf, https://x.dev/a.pdf?token=1, and
/files/report.pdf#page=2 all resolve to application/pdf instead of
rejecting.
Closes #15432.
Refactored DataKeysAndValues.ValueLink to use the standard as prop for custom link components, replacing the previous LinkComponent prop (#15391)
Added a Foundations/Tokens page to the @mastra/playground-ui Storybook so you can browse all typography, color, spacing, radius, shadow, and animation tokens in one place. (#15475)
New filter UX on the studio's Traces and Logs pages. Click + Add Filter to pick a property and narrow by value; active filters render as editable pills. Filter state lives in the URL so filtered views survive reloads and can be shared by link. Save filters for next time remembers a default; Clear and Remove all filters are one click away. (#15512)
Align BrandLoader geometry with the Mastra logo: match disk positions to the logo path, introduce per-size stroke widths and bubble radii (sm/md/lg), and rebalance the gooey filter for rounder ridge↔disk fillets. Shift the size scale so sm stays, md is now w-8, lg is now w-10, and the old w-16 size is removed. (#15531)
Added ScoresDataList for rendering lists of score evaluation results. (#15339)
Updated PageHeader.Description styling to use text color (neutral2) and simplified top margin (#15389)
Improved visual consistency across Chip, DropdownMenu, Notification, Popover, and toast components — unified radius and border scale. Deduplicated dropdown menu item classes and added max-height scroll handling for long menus. (#15440)
Add Redis storage provider (#11795)
Introduces @mastra/redis, a Redis-backed storage implementation for Mastra built on the official redis (node-redis) client.
Includes support for the core storage domains (memory, workflows, scores) and multiple connection options: connectionString, host/port/db/password, or injecting a pre-configured client for advanced setups (e.g. custom socket/retry settings, Sentinel/Cluster via custom client).
Fixed MCP tool validation failures when tools use JSON Schema draft 2020-12. Tools from providers like Firecrawl that declare $schema: "https://json-schema.org/draft/2020-12/schema" now validate correctly instead of throwing "no schema with key or ref" errors. (#14530)
Fixed MCP tools with recursive JSON Schema refs so they stay serializable when loaded. (#15400)
You can now tag spans and redact sensitive input or output per request by passing tags, hideInput, or hideOutput in tracingOptions when calling an agent or workflow. (#15512)
Added a lightweight trace endpoint (GET /observability/traces/:traceId/light) that returns only timeline-relevant span fields, dramatically reducing payload size when rendering trace timelines. Also added a dedicated span endpoint (GET /observability/traces/:traceId/spans/:spanId) to fetch full span details on demand.
Added forEachIndex to the workflow resume request body schema. The /workflows/:workflowId/resume, /resume-async, and /resume-stream endpoints (including their agent-builder equivalents) now accept an optional zero-based forEachIndex so clients can target a specific iteration of a suspended .foreach() step. (#15563)
// POST /workflows/:workflowId/resume
// body
{
step: 'approve',
resumeData: { ok: true },
forEachIndex: 1, // resume only the second iteration; others stay suspended
}
Add /api/background-tasks routes (SSE stream, list with filters + pagination, get by ID) and matching MastraClient methods (listBackgroundTasks, getBackgroundTask, streamBackgroundTasks). (#15307)
Added support for versions field in agent generate and stream request bodies, enabling per-request sub-agent version overrides that propagate through delegation. (#15373)
Fix prototype pollution in setNestedValue (@mastra/core/utils) and generateOpenAPIDocument (@mastra/server). (#15565)
setNestedValue now rejects dot-path segments named __proto__, constructor, or prototype, preventing attacker-controlled field paths passed to selectFields from polluting Object.prototype. generateOpenAPIDocument builds its paths map with Object.create(null) so a route path of __proto__ cannot poison the prototype chain.
Fixed noisy 'Background task manager not available' error log in studio when background tasks are not enabled. The list endpoint now returns an empty list, the get-by-id endpoint returns 404, and the SSE stream endpoint returns an empty stream that closes on disconnect — instead of throwing an HTTP 400 that gets logged as an error. (#15600)
Added unique IDs (logId, metricId, scoreId, feedbackId) to all observability signals, generated automatically at emission time for de-duplication across the framework pipeline and cross-system correlation. User-facing APIs (logger.info(), metrics.emit(), addScore(), addFeedback()) are unchanged. (#15242)
For existing ClickHouse and DuckDB observability signal tables, run npx mastra migrate before initializing the store so the new signal-ID schema is applied.
@mastra/tavily integration with first-class Mastra tools for Tavily web search, extract, crawl, and map APIs, and migrated mastracode's web search tools to use it. (#15448)Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)
Fixed slow Upstash message saves by using the message index and treating unindexed messages as new, avoiding full database scans. Also adds index-first lookups to updateMessages. Addresses #15386. (#15393)
The following packages were updated with dependency changes only:
@mastra/modal)New @mastra/modal adds a Modal-backed ModalSandbox for running workspace commands in an isolated cloud environment with pause/resume support—expanding Mastra’s deployment/execution options beyond local sandboxes.
Workspace’s filesystem option now supports a resolver function, enabling per-request filesystem selection/routing from a single Workspace instance—useful for multi-tenant setups and scoped permissions without spinning up multiple Workspaces.
LSPConfigYou can now register additional language servers via lsp.servers (and override built-ins by ID), unlocking LSP-based inspection for languages beyond the default set (e.g., PHP, Ruby, Java, Kotlin, Swift, Elixir).
Workspace file indexing now auto-creates vector indices where required (e.g., LibSQL) and splits large files into overlapping chunks instead of skipping them—preventing empty vector stores and making search reliable with autoIndexPaths.
Multiple fixes prevent duplicated/replayed messages and tool outputs when observational memory is enabled (including disabling savePerStep in Harness in this mode), and agent.stream() callbacks now preserve provider-specific usage.raw so you can access cache metrics without wrapping streams.
The Workspace filesystem option now accepts a resolver function in addition to a static instance. (#13150)
Before: filesystem: WorkspaceFilesystem (static, same filesystem for every request)
After: filesystem: WorkspaceFilesystem | (({ requestContext }) => WorkspaceFilesystem) (static or per-request)
This enables per-request filesystem routing from a single Workspace — useful for multi-tenant setups, role-based access (e.g. admin vs user directories), and scoped filesystem permissions without creating separate Workspace instances.
Added support for custom language server registration with the servers field in LSPConfig. Previously, LSP inspection only worked with built-in server definitions for TypeScript, JavaScript, Python, Go, and Rust. You can now register additional language servers, such as PHP, Ruby, Java, Kotlin, Swift, or Elixir, by providing a CustomLSPServer definition. (#14969)
Example:
const workspace = new Workspace({
lsp: {
servers: {
phpactor: {
id: 'phpactor',
name: 'Phpactor Language Server',
languageIds: ['php'],
extensions: ['.php'],
markers: ['composer.json'],
command: 'phpactor language-server',
},
},
},
});
Custom servers are merged with built-in servers and can also override them by using the same ID. Closes #14828.
Update provider registry and model documentation with latest models and providers (733bf53)
Fixed output processors returning undefined from processOutputStream causing an undefined chunk to be enqueued into the consumer stream. A processor that forgets to return part (or explicitly returns undefined) now drops that chunk, matching existing null behavior, instead of emitting a bogus value to downstream readers. (#15674)
// Before: returning undefined emitted { value: undefined, done: false } to consumers
// After: returning undefined drops the chunk, same as returning null
const processor = {
id: 'my-processor',
processOutputStream: async ({ part }) => {
if (shouldDrop(part)) return; // implicit undefined — now safely dropped
return part;
},
};
Fixed streamed tool results being replayed when observational memory runs mid-stream. (#15701) Fixed observational memory markers being saved as separate empty assistant messages.
Fixed false positive provider change detection in observational memory. Message metadata now uses the configured model ID instead of the API response model ID, ensuring consistency with step-start parts and preventing incorrect 'Model changed' activations when the provider returns versioned model names (e.g., gpt-5.4-2026-03-05 vs gpt-5.4). (#15681)
Fixed interaction between savePerStep and observational memory that caused message duplication. The saveStepMessages method redundantly re-added response messages to the message list on every step, duplicating them. Additionally, savePerStep is now force-disabled when observational memory is enabled, since OM handles its own per-step persistence and the two features conflict. (#15684)
Fixed rotated response message ids not propagating to the active output stream after error processor retries, which could split a single response across two ids on the API-error retry path. (#15702)
Fixed processor-supplied options to writer.custom being dropped in the agentic execution step, so future options like transient now reach the underlying output writer.
Fixed agent.stream() callbacks so that onStepFinish and onFinish now preserve the provider-level usage.raw object on LanguageModelUsage. This lets consumers inspect provider-specific cache metrics (e.g., Anthropic and Bedrock prompt caching) directly from the callback payload without having to wrap the stream. (#15546)
Closes #15510.
Add opt-in checkSkillFileMtime option to detect in-place SKILL.md edits during hot reload. (#15676)
Previously, only directory mtime was checked for skill staleness, so editing a skill's name (to fix a validation error) or updating its description wouldn't trigger re-discovery until server restart.
The option is off by default since it doubles stat() calls per skill during staleness checks. Recommended for local development only, not for cloud storage backends where stat() has higher latency.
const myAgent = new Agent({
workspace: {
filesystem: new LocalFilesystem({ basePath: process.cwd() }),
skills: ['./**/skills'],
checkSkillFileMtime: true, // Enable for local dev
},
});
Added filterIncompleteToolCalls option to memory config. When set to false, suspended tool calls remain visible in the agent's prompt context, allowing the agent to see its own pending interactions in thread history. Defaults to true (current behavior). Useful for suspend/resume patterns with providers that support incomplete tool calls (e.g. Anthropic). (#14721)
Fixed workspace file indexing so vector search works out of the box. (#15011)
createIndex call (e.g. LibSQL) would leave the table uncreated, causing no such table errors on search. Workspaces with vectorStore + embedder + autoIndexPaths configured now work without any manual setup.Disable savePerStep in Harness to prevent duplicate messages when observational memory is enabled (#15684)
The savePerStep option in Harness caused message duplication when used alongside observational memory. This change temporarily disables savePerStep in the Harness runtime while we work on a permanent fix.
Standardize headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
Fixed browser_evaluate so expression scripts now return their computed value instead of undefined (for example, document.querySelectorAll('a').length). (#15689)
Remove unused userDataDir config option from BrowserViewerConfig. (#15696)
Standardize headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
Fix toKey() to resolve "." and "./" as the root path (#14824)
Both GCSFilesystem and S3Filesystem produced invalid object keys when called with path: "." (e.g. prefix/. instead of prefix/). Since the built-in mastra_workspace_list_files tool and Mastra Studio both default to path: ".", workspace directory listings returned empty results when backed by GCS or S3.
toKey() now normalises "." and "./" to empty string before prepending the prefix, matching the existing behaviour of "/". Dotfiles like .env or .gitignore are unaffected.
uuid with @lukeed/uuid and node:crypto (#15691)uuid with @lukeed/uuid and node:crypto (#15691)Added @mastra/modal — Modal cloud sandbox provider for Mastra workspaces. (#14486)
Use ModalSandbox to run commands in an isolated Modal environment with pause/resume support:
import { Workspace } from '@mastra/core/workspace';
import { ModalSandbox } from '@mastra/modal';
const workspace = new Workspace({
sandbox: new ModalSandbox({
tokenId: process.env.MODAL_TOKEN_ID!,
tokenSecret: process.env.MODAL_TOKEN_SECRET!,
}),
});
uuid with @lukeed/uuid and node:crypto (#15691)Fix toKey() to resolve "." and "./" as the root path (#14824)
Both GCSFilesystem and S3Filesystem produced invalid object keys when called with path: "." (e.g. prefix/. instead of prefix/). Since the built-in mastra_workspace_list_files tool and Mastra Studio both default to path: ".", workspace directory listings returned empty results when backed by GCS or S3.
toKey() now normalises "." and "./" to empty string before prepending the prefix, matching the existing behaviour of "/". Dotfiles like .env or .gitignore are unaffected.
uuid with @lukeed/uuid and node:crypto (#15691)Fixed non-Zod Standard Schema types (e.g. ArkType) being incorrectly called as lazy getters in resolveLazySchema, which caused Studio UI tool forms to receive validation errors instead of the actual JSON Schema (#15670)
Fix: Public origin resolution for AWS ALB deployments (#15666)
Implement cascading header resolution in getPublicOrigin() to properly handle:
Fixes OAuth callback URLs being resolved to http:// instead of https:// when deployed behind AWS ALB with Preserve Host Header enabled.
headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)The following packages were updated with dependency changes only:
@mastra/core and the new @mastra/browser-viewer package add end-to-end browser automation for CLI-based agent workflows. BrowserViewer launches Chrome via Playwright with remote debugging, and a new BrowserCliHandler automatically detects browser CLIs (agent-browser, browser-use, browse) and injects the CDP URL into commands — no manual wiring needed. Browser sessions are thread-isolated with automatic lifecycle management, and live screencasts stream directly to Studio. External CDP endpoints (e.g. browser-use cloud) are also supported: the system detects them, skips injection, and connects for screencast.
Workspace packages (@mastra/s3, @mastra/daytona, @mastra/e2b, and @mastra/blaxel) now support mounting an S3 subdirectory via a prefix option, so sandboxes can expose only a folder within a bucket instead of the entire bucket.
foreachFixes a workflow snapshot/resume bug where parallel foreach iterations could lose their suspendPayload when a sibling iteration resumed—important for HITL/tool-approval flows that rely on preserved per-iteration stream state.
Adds opt-in temporal-gap markers (observationalMemory.temporalMarkers: true) to inject persisted <system-reminder type="temporal-gap"> when users return after 10+ minutes, and fixes duplication/conflicts by force-disabling savePerStep when observational memory is enabled.
@mastra/tavilyNew integration package wrapping @tavily/core as first-class Mastra tools — createTavilySearchTool, createTavilyExtractTool, createTavilyCrawlTool, and createTavilyMapTool — with full Zod input/output schemas, lazy client initialization, and a convenience createTavilyTools() that returns all four with shared config. API key resolves from config or TAVILY_API_KEY env var.
Added support for CLI-driven browser automation with screencast support in @mastra/core, including automatic CDP injection for browser CLIs. (#15415)
Fixed local process spawning so workspace-relative cwd values no longer get duplicated.
Update provider registry and model documentation with latest models and providers (f112db1)
Fixed foreach parallel iterations losing their suspendPayload when a sibling iteration was resumed. Previously, every result entry written back to the workflow snapshot had its suspendPayload cleared, so iterations that were still suspended (e.g. parallel tool-call approvals each carrying an agent's __streamState) lost the context they needed to resume correctly. Suspended iterations now retain their suspendPayload across resume cycles; completed iterations still have it cleared to keep snapshots small. (#15551)
const approvalWorkflow = createWorkflow({ id: "approve" }).foreach(approveToolStep, { concurrency: 5 }).commit();
// Before: resuming the first approval wiped streamState on the others,
// so subsequent resumes lost conversation context.
// After: each suspended iteration keeps its suspendPayload (including
// streamState) until it is individually resumed.
Fixed interaction between savePerStep and observational memory that caused message duplication. The saveStepMessages method redundantly re-added response messages to the message list on every step, duplicating them. Additionally, savePerStep is now force-disabled when observational memory is enabled, since OM handles its own per-step persistence and the two features conflict. (#15652)
Added opt-in temporal-gap markers for observational memory. When enabled via observationalMemory.temporalMarkers: true, the agent receives a <system-reminder type="temporal-gap"> before any user message that arrives more than 10 minutes after the previous one, so it can anchor responses in real elapsed time. Markers are persisted, surfaced to the observer, and rendered by the MastraCode TUI on reload. (#15605)
mastra dev startup (that was previously already hidden but got exposed again by a recent change) (#15616)Added S3 prefix (subdirectory) mount support. You can now mount a specific folder within an S3 bucket instead of the entire bucket by setting the prefix option on your S3 filesystem. (#15171)
Example:
const fs = new S3Filesystem({
bucket: "my-bucket",
region: "us-east-1",
prefix: "workspace/data",
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
});
When mounted in a sandbox, only the contents under workspace/data/ in the bucket will be visible at the mount path. This uses the s3fs bucket:/path syntax under the hood.
Closes #15147.
Initial release of @mastra/browser-viewer (#15415)
Playwright-based browser viewer for CLI providers that enables screencast visualization in Studio. Supports thread-isolated browser sessions and automatic CDP connection management.
import { BrowserViewer } from "@mastra/browser-viewer";
const workspace = new Workspace({
sandbox: new LocalSandbox({ cwd: "./workspace" }),
browser: new BrowserViewer({
cli: "agent-browser",
headless: false
})
});
Fixed mastra dev repeatedly reporting MIGRATION REQUIRED on ClickHouse Cloud after mastra migrate had already run successfully. The observability migration check now recognizes the engine-name variants that ClickHouse Cloud and replicated clusters use in place of ReplacingMergeTree. (#15623)
Improved ClickHouse v-next observability initialization errors to include the underlying ClickHouse message in the standard error text. This makes init failures actionable in loggers that only print error.message. (#15588)
Added S3 prefix (subdirectory) mount support. You can now mount a specific folder within an S3 bucket instead of the entire bucket by setting the prefix option on your S3 filesystem. (#15171)
Example:
const fs = new S3Filesystem({
bucket: "my-bucket",
region: "us-east-1",
prefix: "workspace/data",
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
});
When mounted in a sandbox, only the contents under workspace/data/ in the bucket will be visible at the mount path. This uses the s3fs bucket:/path syntax under the hood.
Closes #15147.
Added S3 prefix (subdirectory) mount support. You can now mount a specific folder within an S3 bucket instead of the entire bucket by setting the prefix option on your S3 filesystem. (#15171)
Example:
const fs = new S3Filesystem({
bucket: "my-bucket",
region: "us-east-1",
prefix: "workspace/data",
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
});
When mounted in a sandbox, only the contents under workspace/data/ in the bucket will be visible at the mount path. This uses the s3fs bucket:/path syntax under the hood.
Closes #15147.
tools (e.g. POST /stored/agents, POST /stored/workspaces). The adapter now exposes registered tools as registeredTools in handler params, matching the Express and Hono adapters and the @mastra/server handler contract. (#15635)observationalMemory.temporalMarkers: true, the agent receives a <system-reminder type="temporal-gap"> before any user message that arrives more than 10 minutes after the previous one, so it can anchor responses in real elapsed time. Markers are persisted, surfaced to the observer, and rendered by the MastraCode TUI on reload. (#15605)no low surrogate in string, causing observer runs to fail. (#15634)Added S3 prefix (subdirectory) mount support. You can now mount a specific folder within an S3 bucket instead of the entire bucket by setting the prefix option on your S3 filesystem. (#15171)
Example:
const fs = new S3Filesystem({
bucket: "my-bucket",
region: "us-east-1",
prefix: "workspace/data",
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
});
When mounted in a sandbox, only the contents under workspace/data/ in the bucket will be visible at the mount path. This uses the s3fs bucket:/path syntax under the hood.
Closes #15147.
Forward requestContext from the /approve-tool-call, /decline-tool-call, /approve-tool-call-generate and /decline-tool-call-generate REST handlers to agent.approveToolCall(...) / declineToolCall(...) / approveToolCallGenerate(...) / declineToolCallGenerate(...). (#15620)
Previously requestContext was destructured from the handler arguments but never passed through. On resume, dynamicInstructions ran with requestContext: undefined, so any value placed on the per-request RequestContext by upstream middleware (or by body.requestContext auto-merge) was lost for the rest of the turn. Agents whose prompt assembly depends on request-scoped data (e.g. read-only state from the frontend) produced blank or placeholder responses after the user approved a HITL tool call. Other agent entry points (stream, generate) already forwarded requestContext correctly; this brings the approval routes in line.
Fixed screencast panel staying "Live" after browser closes due to an error. The ViewerRegistry now broadcasts browser_closed status when a screencast stream emits an error, not just when it stops cleanly. (#15415)
ERR_MODULE_NOT_FOUND for @tavily/core by making it a direct dependency. Consumers no longer need to install @tavily/core manually. (#15628)The following packages were updated with dependency changes only:
RAG ingestion and query operations are now visible in Mastra tracing with new span types (e.g., RAG_INGESTION, RAG_EMBEDDING, RAG_VECTOR_OPERATION, RAG_ACTION, GRAPH_ACTION) plus helpers like startRagIngestion() / withRagIngestion(). Instrumentation is opt-in via an observabilityContext, and @mastra/rag automatically threads context from agent TOOL_CALL spans into vector and graph tools.
@mastra/observability CloudExporter can now batch and upload logs, metrics, scores, and feedback in addition to tracing spans, enabling a single exporter path to Mastra Cloud for all signals. This also changes the endpoint configuration to use a base collector URL and derive publish paths automatically.
excludeSpanTypes and spanFilter were added to ObservabilityInstanceConfig in both @mastra/core and @mastra/observability, allowing you to drop entire span categories (e.g., MODEL_CHUNK) or apply predicate-based filtering before export—useful for pay-per-span backends.
@mastra/core MessageList can now accept AI SDK v6 UI/model messages and project stored messages via messageList.get.all.aiV6.ui(), supporting v6 approval request/response flows. @mastra/ai-sdk adds toAISdkMessages() to load stored Mastra messages into AI SDK v5 or v6 chat UIs.
Observability log correlation is fixed so logs inside agent runs carry the active span correlation fields (restoring trace↔log linking), and deepClean() now applies to all signals and better preserves Map/Set/Error detail. MCP tool discovery now retries after reconnectable errors and the MCP server returns spec-correct 404s for stale sessions; memory recall gains more precise browsing (partType, toolName, threadId: "current", anchor paging), and message parts now include createdAt timestamps for accurate part-level timing.
endpoint URL (publisher paths are derived automatically) when using CloudExporter for Mastra Cloud uploads.Added excludeSpanTypes and spanFilter options to ObservabilityInstanceConfig for selectively filtering spans before export. Use excludeSpanTypes to drop entire categories of spans by type (e.g., MODEL_CHUNK, MODEL_STEP) or spanFilter for fine-grained predicate-based filtering by attributes, metadata, entity, or any combination. Both options help reduce noise and costs in observability platforms that charge per-span. (#15131)
excludeSpanTypes example:
excludeSpanTypes: [SpanType.MODEL_CHUNK, SpanType.MODEL_STEP, SpanType.WORKFLOW_SLEEP];
spanFilter example:
spanFilter: span => {
if (span.type === SpanType.MODEL_CHUNK) return false;
if (span.type === SpanType.TOOL_CALL && span.attributes?.success) return false;
return true;
};
Add RAG observability (#10898) (#15137)
Surfaces RAG ingestion and query operations in Mastra's AI tracing.
New span types in @mastra/core/observability:
RAG_INGESTION (root) — wraps an ingestion pipeline runRAG_EMBEDDING — embedding call (used by ingestion and query)RAG_VECTOR_OPERATION — vector store I/O (query/upsert/delete/fetch)RAG_ACTION — chunk / extract_metadata / rerankGRAPH_ACTION — non-RAG graph build / traverse / update / pruneNew helpers exported from @mastra/core/observability:
startRagIngestion(opts) — manual: returns { span, observabilityContext }withRagIngestion(opts, fn) — scoped: runs fn(observabilityContext),
attaches the return value as the span's output, routes thrown errors to
span.error(...)Wired in @mastra/rag:
vectorQuerySearch emits RAG_EMBEDDING (mode: query) and
RAG_VECTOR_OPERATION (operation: query)rerank / rerankWithScorer emit RAG_ACTION (action: rerank)MDocument.chunk emits RAG_ACTION (action: chunk) and
RAG_ACTION (action: extract_metadata)createGraphRAGTool emits GRAPH_ACTION (action: build / traverse)createVectorQueryTool and createGraphRAGTool thread
observabilityContext from the agent's TOOL_CALL span automaticallyAll new instrumentation is opt-in: functions accept an optional
observabilityContext and no-op when absent, so existing callers are
unaffected.
Update provider registry and model documentation with latest models and providers (8db7663)
Added AI SDK v6 UI message support to MessageList in @mastra/core. (#14592)
MessageList can now accept AI SDK v6 UI and model messages in add(...), and project stored messages with messageList.get.all.aiV6.ui(). This adds first-class handling for v6 approval request and response message flows.
Fix observability log correlation: logs emitted from inside an agent run were being persisted with entityId, runId, traceId, and the other correlation fields set to null, breaking trace ↔ log linking in Mastra Studio and downstream observability tools. Logs now correctly carry the active span's correlation context end to end. (#15148)
Added createdAt timestamps to message parts in message history. (#15121)
Message parts now keep their own creation timestamps so downstream code can preserve part-level timing instead of relying only on the parent message timestamp.
After:
{ type: 'text', text: 'hello', createdAt: 1712534400000 }
Added toAISdkMessages() for loading stored Mastra messages into AI SDK v5 or v6 chat UIs. (#14592)
Use the default v5 behavior or pass { version: 'v6' } when your app is typed against AI SDK v6 useChat() message types.
llm span in Datadog (previously the per-call spans were reported as task, so Datadog's "Model Calls" count was wrong and per-call inputs/outputs were not rendered as messages).workflow span instead of llm, so it no longer looks like an extra LLM call.llm spans, so Datadog no longer double-counts tokens against the wrapper.llm spans inherit modelName and modelProvider from their parent generation, so the model is still attached in the Datadog UI.Improved MCP tool discovery to retry once after reconnectable connection errors like Connection closed during tools/list. (#15141)
MCPClient.listToolsets(), listToolsetsWithErrors(), and listTools() now attempt a reconnect before treating transient discovery failures as missing tools.
Fixed MCP server to return HTTP 404 (instead of 400) when a client sends a stale or unknown session ID. Per the MCP spec, this tells clients to re-initialize with a new session, which fixes broken tool calls after server redeploys. (#15160)
Updated the recall tool to support more precise message browsing for agents. (#15116)
Agents using recall can now pass partType and toolName to narrow message results to specific parts, such as tool calls or tool results for one tool. This change also adds threadId: "current" support across recall modes and anchor: "start" | "end" for no-cursor message paging, making it easier to inspect recent thread activity and past tool usage.
Fixed reflection threshold not respecting per-record overrides set via the PATCH API. Previously, lowering the reflection threshold for a specific record had no effect on the actual reflection trigger — only the default 40k threshold was used. Now per-record overrides are correctly applied in both sync and async reflection paths. (#15170)
Improved observational memory formatting to use part timestamps when rendering dates and times. (#15121)
Observer history now follows part-level timing more closely, so the rendered memory context is more accurate when messages contain parts created at different times.
Fixed message history doubling when using Observational Memory with the Mastra gateway. The local ObservationalMemoryProcessor now detects when the agent's model is routed through the Mastra gateway and skips its input/output processing, since the gateway handles OM server-side. (#15161)
Added CloudExporter support for Mastra Observability logs, metrics, scores, and feedback. (#15124)
CloudExporter now batches and uploads all Mastra Observability signals to Mastra Cloud, not just tracing spans.
This includes a breaking change to the CloudExporter endpoint format. We now pass a base endpoint URL and let let the exporter derive the standard publish paths automatically.
import { CloudExporter, Observability } from '@mastra/observability';
const observability = new Observability({
configs: {
default: {
serviceName: 'my-app',
exporters: [
new CloudExporter({
endpoint: 'https://collector.example.com',
}),
],
},
},
});
// Traces, logs, metrics, scores, and feedback now all publish through CloudExporter.
After updating the exporter endpoint config, the exporter will continue to work for traces, and the same exporter will now also publish structured logs, auto-extracted metrics, scores, and feedback records.
Added excludeSpanTypes and spanFilter options to ObservabilityInstanceConfig for selectively filtering spans before export. Use excludeSpanTypes to drop entire categories of spans by type (e.g., MODEL_CHUNK, MODEL_STEP) or spanFilter for fine-grained predicate-based filtering by attributes, metadata, entity, or any combination. Both options help reduce noise and costs in observability platforms that charge per-span. (#15131)
excludeSpanTypes example:
excludeSpanTypes: [SpanType.MODEL_CHUNK, SpanType.MODEL_STEP, SpanType.WORKFLOW_SLEEP];
spanFilter example:
spanFilter: span => {
if (span.type === SpanType.MODEL_CHUNK) return false;
if (span.type === SpanType.TOOL_CALL && span.attributes?.success) return false;
return true;
};
ObservabilityBus now honors per-instance serializationOptions (maxStringLength, maxDepth, maxArrayLength, maxObjectKeys) when deep-cleaning log/metric/score/feedback payloads, matching the behavior of tracing spans. Previously these signals always used the built-in defaults regardless of user configuration. (#15138)
Apply deepClean() to all observability signals (logs, metrics, scores, feedback) before fanning out to exporters and bridges. Previously only tracing spans were deep-cleaned at construction time, leaving free-form payload fields on other signals (e.g. log.data, log.metadata, metric.metadata, metric.costContext.costMetadata, score.metadata, feedback.metadata) susceptible to circular references, oversized strings, and other non-serializable values. Sanitization now happens centrally in ObservabilityBus.emit() so every signal leaving the bus is bounded and JSON-safe. (#15135)
deepClean() now preserves data for Map, Set, and richer Error objects. Previously Maps and Sets were serialized as empty {} (entries silently dropped) and Errors only kept name/message. Maps are now converted to plain objects of entries, Sets to arrays (both respecting maxObjectKeys/maxArrayLength and cycle detection), and Errors additionally preserve stack and recursively cleaned cause. (#15136)
Search input can now be collapsed into a compact icon button with tooltip and auto-focuses when expanded (#15130)
Added DataKeysAndValues component — a compound component for displaying key-value pairs in a grid layout with support for single or two-column modes and section headers (#15126)
Added DateTimeRangePicker component — a date range selector with preset options (last 24h, 7d, 30d, etc.) and a custom range mode with dual calendar and time pickers (#15128)
Added DataCodeSection component — a read-only code viewer with JSON syntax highlighting, search, multiline toggle, and an expandable fullscreen dialog (#15125)
Added DataPanel compound component — a container for detail panels with header, navigation, close button, loading, and empty states (#15127)
New inline Traces page replacing the old dialog-based Observability page. Trace, span, and score details now open in stacked side panels instead of full-screen dialogs. URL deep-linking supports traceId, spanId, tab, and scoreId params. Includes new TracesDataList, DataList.Pagination, DataList.Subheader components, and Evaluate Trace / Save as Dataset Item actions. (#15139)
Fixed publishing older agent versions (#15154)
Fixed agent editor to allow publishing older read-only versions. Previously, the Publish button was disabled when viewing a previous version. Now a "Publish This Version" button appears, enabling users to set any older version as the published version.
Fixed Publish button being clickable without a saved draft
The Publish button is now disabled until a draft version is saved. Previously, making edits would enable the Publish button even without a saved draft, which caused an error when clicked.
Eliminated spurious 404 error logs for code-only agents
The agent versions endpoint now checks both code-registered and stored agents before returning 404, and the frontend conditionally fetches stored agent details only when versions exist. This prevents noisy error logs when navigating to the editor for agents that haven't been published yet.
Changed editor sections to be collapsed by default
The System Prompt, Tools, and Variables sections in the agent editor are now collapsed by default when navigating to the editor page.
Add RAG observability (#10898) (#15137)
Surfaces RAG ingestion and query operations in Mastra's AI tracing.
New span types in @mastra/core/observability:
RAG_INGESTION (root) — wraps an ingestion pipeline runRAG_EMBEDDING — embedding call (used by ingestion and query)RAG_VECTOR_OPERATION — vector store I/O (query/upsert/delete/fetch)RAG_ACTION — chunk / extract_metadata / rerankGRAPH_ACTION — non-RAG graph build / traverse / update / pruneNew helpers exported from @mastra/core/observability:
startRagIngestion(opts) — manual: returns { span, observabilityContext }withRagIngestion(opts, fn) — scoped: runs fn(observabilityContext),
attaches the return value as the span's output, routes thrown errors to
span.error(...)Wired in @mastra/rag:
vectorQuerySearch emits RAG_EMBEDDING (mode: query) and
RAG_VECTOR_OPERATION (operation: query)rerank / rerankWithScorer emit RAG_ACTION (action: rerank)MDocument.chunk emits RAG_ACTION (action: chunk) and
RAG_ACTION (action: extract_metadata)createGraphRAGTool emits GRAPH_ACTION (action: build / traverse)createVectorQueryTool and createGraphRAGTool thread
observabilityContext from the agent's TOOL_CALL span automaticallyAll new instrumentation is opt-in: functions accept an optional
observabilityContext and no-op when absent, so existing callers are
unaffected.
Fixed publishing older agent versions (#15154)
Fixed agent editor to allow publishing older read-only versions. Previously, the Publish button was disabled when viewing a previous version. Now a "Publish This Version" button appears, enabling users to set any older version as the published version.
Fixed Publish button being clickable without a saved draft
The Publish button is now disabled until a draft version is saved. Previously, making edits would enable the Publish button even without a saved draft, which caused an error when clicked.
Eliminated spurious 404 error logs for code-only agents
The agent versions endpoint now checks both code-registered and stored agents before returning 404, and the frontend conditionally fetches stored agent details only when versions exist. This prevents noisy error logs when navigating to the editor for agents that haven't been published yet.
Changed editor sections to be collapsed by default
The System Prompt, Tools, and Variables sections in the agent editor are now collapsed by default when navigating to the editor page.
Fixed the Responses API to use the agent default model when create requests omit model. (#15140)
The following packages were updated with dependency changes only:
@mastra/memory now lets you route observer and reflector calls to different models based on input size using ModelByInputTokens. Short inputs can go to a fast, cheap model while longer ones get sent to a more capable one -- all configured declaratively with token thresholds. Tracing shows which model was selected and why.
@mastra/mongodb now stores versioned datasets with full item history and time-travel queries, plus experiment results and CRUD. If you're already using MongoDBStore, this works automatically with no extra setup.
New @mastra/auth-okta package brings SSO authentication and role-based access control via Okta. Map Okta groups to Mastra permissions, verify JWTs against Okta's JWKS endpoint, and manage sessions -- or pair Okta RBAC with a different auth provider like Auth0 or Clerk.
Added dataset-agent association and experiment status tracking for the Evaluate workflow. (#14470)
targetType and targetIds fields to datasets, enabling association with agents, scorers, or workflows. Datasets can now be linked to multiple entities.status field to experiment results ('needs-review', 'reviewed', 'complete') for review queue workflow.Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added tool suspension handling to the Harness. (#14611)
When a tool calls suspend() during execution, the harness now emits a tool_suspended event, reports agent_end with reason 'suspended', and exposes respondToToolSuspension() to resume execution with user-provided data.
harness.subscribe((event) => {
if (event.type === "tool_suspended") {
// event.toolName, event.suspendPayload, event.resumeSchema
}
});
// Resume after collecting user input
await harness.respondToToolSuspension({ resumeData: { confirmed: true } });
Added agentId to the agent tool execution context. Tools executed by an agent can now access context.agent.agentId to identify which agent is calling them. This enables tools to look up agent metadata, share workspace configuration with sub-agents, or customize behavior per agent. (#14502)
Improved observability metrics and logs storage support. (#14607)
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
Update provider registry and model documentation with latest models and providers (68ed4e9)
Fixed Harness.destroy() to properly clean up heartbeats and workspace on teardown. (#14568)
Fixed null detection in tool input validation to check actual values at failing paths instead of relying on error message string matching. This ensures null values from LLMs are correctly handled even when validators produce error messages that don't contain the word "null" (e.g., "must be string"). Fixes #14476. (#14496)
Fixed missing tool lists in agent traces for streaming runs. Exporters like Datadog LLM Observability now receive the tools available to the agent. (#14550)
Fix consecutive tool-only loop iterations being merged into a single assistant message block. When the agentic loop runs multiple iterations that each produce only tool calls, the LLM would misinterpret them as parallel calls from a single turn. A step-start boundary is now inserted between iterations to ensure they are treated as sequential steps. (#14652)
Improved custom OpenAI-compatible model configuration guidance in the models docs. (#14594)
Added client/server body schemas for feedback and scores that omit the timestamp field, allowing it to be set server-side (#14470)
Workspace skills now surface all same-named skills for disambiguation. (#14430)
When multiple skills share the same name (e.g., a local brand-guidelines skill and one from node_modules), list() now returns all of them instead of only the tie-break winner. This lets agents and UIs see every available skill, along with its path and source type.
Tie-breaking behavior:
get(name) still returns a single skill using source-type priority: local > managed > externalget(name) throws an error — rename one or move it to a different source typeget(path) bypasses tie-breaking entirely and returns the exact skillAgents and UIs now receive all same-named skills with their paths, which improves disambiguation in prompts and tool calls.
const skills = await workspace.skills.list();
// Returns both local and external "brand-guidelines" skills
const exact = await workspace.skills.get("node_modules/@myorg/skills/brand-guidelines");
// Fetches the external copy directly by path
Fixed Anthropic 'tool_use ids were found without tool_result blocks immediately after' error. When client tools (e.g. execute_command) and provider tools (e.g. web_search) are called in parallel, the tool ordering in message history could cause Anthropic to reject subsequent requests, making the thread unrecoverable. Tool blocks are now correctly split to satisfy Anthropic's ordering requirements. (#14648)
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
fetchGroupsFromOkta now propagate so the outer .catch evicts the entry and retries on next requestid_token_hint to logout URL (required by Okta)OKTA_CLIENT_SECRET, OKTA_REDIRECT_URI, OKTA_COOKIE_PASSWORD) in README and examplesMastraAuthOktaOptions docs to include all fields (session config, scopes, etc.)getUserId cross-provider lookup pathAdded client SDK methods for dataset experiments and item generation. (#14470)
triggerExperiment() method to dataset resources for running experiments with configurable target type and IDgenerateItems() method for LLM-powered test data generationclusterFailures() method for analyzing experiment failuresAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added storage support for dataset targeting and experiment status fields. (#14470)
targetType (text) and targetIds (jsonb) columns to datasets table for entity associationtags (jsonb) column to datasets table for tag vocabularystatus column to experiment results for review workflow trackingAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
google/gemini-2.5-flash by using stronger compression guidance and starting it at a higher compression level during reflection. google/gemini-2.5-flash is unusually good at generating long, faithful outputs. That made reflection retries more likely to preserve too much detail and miss the compression target, wasting tokens in the process. (#14612)Added datasets and experiments storage support to the MongoDB store. (#14556)
Datasets — Full dataset management with versioned items. Create, update, and delete datasets and their items with automatic version tracking. Supports batch insert/delete operations, time-travel queries to retrieve items at any past version, and item history tracking.
Experiments — Run and track experiments against datasets. Full CRUD for experiments and per-item experiment results, with pagination, filtering, and cascade deletion.
Both domains are automatically available when using MongoDBStore — no additional configuration needed.
const store = new MongoDBStore({ uri: "mongodb://localhost:27017", dbName: "my-app" });
// Datasets
const dataset = await store.getStorage("datasets").createDataset({ name: "my-dataset" });
await store.getStorage("datasets").addItem({ datasetId: dataset.id, input: { prompt: "hello" } });
// Experiments
const experiment = await store.getStorage("experiments").createExperiment({ name: "run-1", datasetId: dataset.id });
Added storage support for dataset targeting and experiment status fields. (#14470)
targetType (text) and targetIds (jsonb) columns to datasets table for entity associationtags (jsonb) column to datasets table for tag vocabularystatus column to experiment results for review workflow trackingAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added Evaluate tab to the agent playground with full dataset management, scorer editing, experiment execution, and review workflow. (#14470)
Evaluate tab — A new sidebar-driven tab for managing datasets, scorers, and experiments within the agent playground. Key features:
Review tab — A dedicated review workflow for experiment results:
Added dataset and agent version selectors to the experiment evaluate tab. You can now choose which dataset version and agent version to use when running an experiment. Version information is displayed in the experiment sidebar, results panel header, and Past Runs list. Added a copy button next to the agent version selector to easily copy version IDs. (#14562)
Added EntityList.NoMatch component that displays a message when search filtering returns no results. Applied to all entity list pages: Agents, Workflows, Tools, Scorers, Processors, Prompts, Datasets, and MCP Servers. (#14621)
Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Removed 'Create an Agent' button from agent list page and table empty state. Removed 'Create Scorer' button from top-level scorers page. Removed stored/code source icons (AgentSourceIcon) from agent headers, combobox, and table. Renamed 'Versions' tab to 'Editor' in agent page tabs. Added GaugeIcon to the 'Create Scorer' button in the review tab. (#14555)
Added metrics dashboard with KPI cards, trace volume, latency, model usage, and scores visualizations. Includes filtering by date range, agents, models, and providers. Added HorizontalBars, MetricsCard, MetricsKpiCard, MetricsLineChart, MetricsFlexGrid, and MetricsDataTable design system components. (#14491)
Internal cleanup and linting fixes (#14497)
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added experimental entity list components with skeleton loading states, error handling, and dedicated empty state components for all list pages. Gated behind MASTRA_EXPERIMENTAL_UI environment variable. (#14547)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
Redesigned the agent instruction blocks editor with a Notion-like document feel. Blocks no longer show line numbers or block numbers, have tighter spacing, and display a subtle hover highlight. Reference blocks now show a sync-block header with a popover for block details, "Open original", "De-reference block", and "Used by" agents. Inline blocks can be converted to saved prompt blocks via a new "Save as prompt block" action in the hover toolbar. The prompt block edit sidebar now shows a "Used by" section listing which agents reference the block. Added a lineNumbers prop to CodeEditor to optionally hide line numbers. (#14563)
<CodeEditor language="markdown" lineNumbers={false} />
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Fixed schema-compat ESM imports for Zod JSON Schema helpers. (#14617)
@mastra/schema-compat no longer uses createRequire in its Zod v4 adapter or runtime eval tests, which avoids createRequire-related ESM issues while preserving support for zod/v3 and zod/v4.
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added dataset-agent association and experiment status tracking for the Evaluate workflow. (#14470)
targetType and targetIds fields to datasets, enabling association with agents, scorers, or workflows. Datasets can now be linked to multiple entities.status field to experiment results ('needs-review', 'reviewed', 'complete') for review queue workflow.Added getAuthenticatedUser() to @mastra/server/auth so server middleware can resolve the configured auth user without changing route auth behavior. (#14458)
Example
import { getAuthenticatedUser } from "@mastra/server/auth";
const user = await getAuthenticatedUser({
mastra,
token,
request: c.req.raw
});
Added new observability API endpoints and client methods for logs, scores, feedback, metrics (aggregate, breakdown, time series, percentiles), and discovery (metric names, label keys/values, entity types/names, service names, environments, tags) (#14470)
Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
The following packages were updated with dependency changes only:
@mastra/core now supports AI Gateway tools (e.g. gateway.tools.perplexitySearch()) as provider-executed tools: it infers providerExecuted, merges streamed provider results back into the originating tool calls, and skips local execution when the provider already returned a result.
Observational memory persistence is more stable via dated message boundary delimiters and chunking, and @mastra/memory adds getObservationsAsOf() to retrieve the exact observation set active at a given message timestamp (useful for replay/debugging and consistent prompting).
@mastra/mcp adds per-server operational tooling—reconnectServer(serverName), listToolsetsWithErrors(), and getServerStderr(serverName)—to improve reliability and debugging of MCP stdio/server integrations.
Update provider registry and model documentation with latest models and providers (51970b3)
Added dated message boundary delimiters when activating buffered observations for improved cache stability. (#14367)
Fixed provider-executed tool calls being saved out of order or without results in memory replay. (Fixes #13762) (#13860)
Fix generateEmptyFromSchema to accept both string and pre-parsed object JSON schema inputs, recursively initialize nested object properties, and respect default values. Updated WorkingMemoryTemplate type to a discriminated union supporting Record<string, unknown> content for JSON format templates. Removed duplicate private schema generator in the working-memory processor in favor of the shared utility. (#14310)
Fixed provider-executed tool calls (e.g. Anthropic web_search) being dropped or incorrectly persisted when deferred by the provider. Tool call parts are now persisted in stream order, and deferred tool results are correctly merged back into the originating message. (#14282)
Fixed replaceString utility to properly escape $ characters in replacement strings. Previously, patterns like $& in the replacement text would be interpreted as regex backreferences instead of literal text. (#14434)
Fixed tool invocation updates to preserve providerExecuted and providerMetadata from the original tool call when updating to result state. (#14431)
@mastra/core: patch (#14327)
Added spanId alongside traceId across user-facing execution results that return tracing identifiers (including agent stream/generate and workflow run results) so integrations can query observability vendors by run root span ID
Add AI Gateway tool support in the agentic loop. (#14016)
Gateway tools (e.g., gateway.tools.perplexitySearch()) are provider-executed but, unlike native provider tools (e.g., openai.tools.webSearch()), the LLM provider does not store their results server-side. The agentic loop now correctly infers providerExecuted for these tools, merges streamed provider results with their corresponding tool calls, and skips local execution when a provider result is already present.
Fixes #13190
Fixed schema-based working memory typing so workingMemory.schema accepts supported schemas such as Zod and JSON Schema. (#14363)
Fixed workspace search being wiped when skills refresh. Previously, calling skills.refresh() or triggering a skills re-discovery via maybeRefresh() would clear the entire BM25 search index, including auto-indexed workspace content. Now only skill entries are removed from the index during refresh, preserving workspace search results. (#14287)
Added client/server body schemas for feedback and scores that omit the timestamp field, allowing it to be set server-side (#14270)
Fixed processor state not persisting between processOutputStream and processOutputResult when processors are wrapped in workflows. State set during stream processing is now correctly accessible in processOutputResult. (#14279)
Fixed type inference for requestContext schemas when using Zod v3 and v4. Agent and tool configurations now correctly infer RequestContext types from Zod schemas and other StandardSchema-compatible schemas. (#14363)
Fixed Studio showing unauthenticated state when using MastraJwtAuth with custom headers. MastraJwtAuth now implements the IUserProvider interface (getCurrentUser/getUser), so the Studio capabilities endpoint can resolve the authenticated user from the JWT Bearer token. (#14411)
Also added an optional mapUser option to customize how JWT claims are mapped to user fields:
new MastraJwtAuth({
secret: process.env.JWT_SECRET,
mapUser: payload => ({
id: payload.userId,
name: payload.displayName,
email: payload.mail,
}),
});
Closes #14350
cookieDomain option to MastraAuthStudioOptions for explicit configurationMASTRA_COOKIE_DOMAIN environment variable as fallback.mastra.ai domain (prevents false positives from malicious URLs).mastra.ai auto-detectionAdded MASTRA_HOST environment variable support for configuring the server bind address. Previously, the host could only be set via server.host in the Mastra config. Now it follows the same pattern as PORT: config value takes precedence, then env var, then defaults to localhost. (#14313)
Added a new MASTRA_TEMPLATES Studio runtime flag to control whether the Templates section appears in the sidebar. (#14309)
MASTRA_TEMPLATES=true now enables Templates navigation in Studio.false or unset), Templates is hidden.Fixed tsconfig path aliases during build when imports use .js-style module specifiers. (#13998)
Fixed apiPrefix server option not being applied to the underlying Hono server instance. Routes, welcome page, Swagger UI, and studio HTML handler now all respect the configured apiPrefix instead of hardcoding /api. (#14325)
.env variables to wrangler.jsonc to prevent secrets from leaking into source control. (#14302)
.env are no longer merged into the vars field of the generated wrangler config.vars from the CloudflareDeployer constructor are still written as before.npx wrangler secret bulk .env.Added support for constructing ElasticSearchVector with a pre-configured Elasticsearch client. You can now pass either a client instance or connection parameters (url and optional auth), giving you full control over client configuration when needed. (#12802)
Using connection parameters:
const vectorDB = new ElasticSearchVector({
id: 'my-store',
url: 'http://localhost:9200',
auth: { apiKey: 'my-key' },
});
Using a pre-configured client:
import { Client } from '@elastic/elasticsearch';
const client = new Client({ node: 'http://localhost:9200' });
const vectorDB = new ElasticSearchVector({ id: 'my-store', client });
Fixed: PinoLogger now supports JSON output for log aggregators (#14306)
Previously, PinoLogger always used pino-pretty which produced multiline colored output, breaking log aggregators like Datadog, Loki, and CloudWatch. A new prettyPrint option allows switching to single-line JSON output.
Added new MCP client APIs for per-server control and diagnostics. (#14377)
reconnectServer(serverName) to reconnect a single MCP server without restarting all servers.listToolsetsWithErrors() to return both toolsets and per-server errors.getServerStderr(serverName) to inspect piped stderr for stdio servers.Example
const { toolsets, errors } = await mcpClient.listToolsetsWithErrors();
await mcpClient.reconnectServer('slack');
const stderr = mcpClient.getServerStderr('slack');
Improved (#14260)
@modelcontextprotocol/sdk from ^1.17.5 to ^1.27.1.Deprecated
version usage in @mastra/mcp.Migration
client.prompts.get({ name: 'explain-code', version: 'v1', args })client.prompts.get({ name: 'explain-code-v1', args })MastraPrompt is available for migration and is also deprecated.Fixed observational memory triggering observation while provider-executed tool calls are still pending, which could split messages and cause errors on follow-up turns. (#14282)
Fixed working memory tool description to accurately reflect merge behavior. The previous description incorrectly stated "Set a field to null to remove it" but null values are stripped by validation before reaching the merge logic. The updated description clarifies: omit fields to preserve existing data, and pass complete arrays or omit them since arrays are replaced entirely. (#14424)
Limit oversized observational-memory tool results before they reach the observer. (#14344)
This strips large encryptedContent blobs and truncates remaining tool result payloads to keep observer prompts and token estimates aligned with what the model actually sees.
Improved observational memory cache stability by splitting persisted observations into separate prompt chunks using dated message boundary delimiters. (#14367)
Added getObservationsAsOf() utility to retrieve the observations that were active at a specific point in time. This enables filtering observation history by message creation date.
import { getObservationsAsOf } from '@mastra/memory';
// Get observations that existed when a specific message was created
const observations = getObservationsAsOf(record.activeObservations, message.createdAt);
Added dedicated session page for agents at /agents/<agentId>/session. This minimal view shows only the chat interface without the sidebar or information pane, making it ideal for quick internal testing or sharing with non-technical team members. If request context presets are configured, a preset dropdown appears in the header. (#13754)
Added hideModelSwitcher prop to AgentChat and Thread components to allow hiding the model picker in the composer.
Fixed crash during template installation by ensuring error values from stream events are converted to strings before being passed to the UI. This prevents the 'e?.includes is not a function' TypeError when the server returns non-string error payloads. (#14267)
Fixed crash when template installation errors are non-string values (e.g. objects). The error is now safely converted to a string before calling .includes(), preventing the 'e?.includes is not a function' TypeError in the studio. (#14267)
The following packages were updated with dependency changes only:
Mastra now ships zod-based storage schemas and in-memory implementations for all observability signals (scores, logs, feedback, metrics, discovery), with full type inference and a base ObservabilityStorage that includes default method implementations.
@mastra/agentfsThe new AgentFSFilesystem workspace provider adds Turso/SQLite-backed, database-persistent file storage for agents across sessions via agentfs-sdk.
EventBuffer batching@mastra/observability exporters/event bus were updated to align with renamed core observability types, and an EventBuffer was added to batch non-tracing signals with configurable flush intervals.
@mastra/server/schemasA new @mastra/server/schemas export provides utility types (RouteMap, InferPathParams, InferBody, InferResponse, etc.) that automatically infer request/response types from SERVER_ROUTES, including routes added via createRoute().
Observational Memory adds observation.previousObserverTokens to truncate the “Previous Observations” context to a token budget (or omit/disable truncation), reducing observer prompt size in long conversations.
MetricType (counter/gauge/histogram) is deprecated — metrics are now raw events with aggregation at query timescorerId instead of scorerNameObservabilityBus constructor now takes a config object (cardinalityFilter, autoExtractMetrics); setCardinalityFilter() and enableAutoExtractedMetrics() were removedAdded observability storage domain schemas and implementations (#14214)
Introduced comprehensive storage schemas and in-memory implementations for all observability signals (scores, logs, feedback, metrics, discovery). All schemas are zod-based with full type inference. The ObservabilityStorage base class includes default implementations for all new methods.
Breaking changes:
MetricType (counter/gauge/histogram) is deprecated — metrics are now raw events with aggregation at query timescorerId instead of scorerName for scorer identificationUpdate provider registry and model documentation with latest models and providers (ea86967)
Fixed provider tools (e.g. openai.tools.webSearch()) being silently dropped when using a custom gateway that returns AI SDK v6 (V3) models. The router now remaps tool types from provider-defined to provider when delegating to V3 models, so provider tools work correctly through gateways. Fixes #13667. (#13895)
Fixed TypeScript type errors in onStepFinish and onFinish callbacks, and resolved compatibility issues with createOpenRouter() across different AI SDK versions. (#14229)
Fixed a bug where thread metadata (e.g. title, custom properties) passed via options.memory.thread was discarded when MASTRA_THREAD_ID_KEY was set in the request context. The thread ID from context still takes precedence, but all other user-provided thread properties are now preserved. (#13146)
Fixed workspace tools such as mastra_workspace_list_files and mastra_workspace_read_file failing with WorkspaceNotAvailableError in some execution paths. (#14228)
Workspace tools now work consistently across execution paths.
Added observer context optimization for Observational Memory. The observation.previousObserverTokens field reduces Observer input token costs for long-running conversations: (#13568)
2000): Truncates the 'Previous Observations' section to a token budget, keeping the most recent observations and automatically replacing already-reflected lines with the buffered reflection summary. Set to 0 to omit previous observations entirely, or false to disable truncation and keep the full observation history.const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
previousObserverTokens: 10_000,
},
},
},
});
Added AgentFSFilesystem workspace provider — a Turso/SQLite-backed filesystem via the agentfs-sdk that gives agents persistent, database-backed file storage across sessions. (#13450)
Basic usage
import { Workspace } from '@mastra/core/workspace';
import { AgentFSFilesystem } from '@mastra/agentfs';
const workspace = new Workspace({
filesystem: new AgentFSFilesystem({
agentId: 'my-agent',
}),
});
Bump esbuild from ^0.25.10 to ^0.27.3 to resolve Go stdlib CVEs (CVE-2025-22871, CVE-2025-61729) flagged by npm audit in consumer projects. (#13124)
Fixed Agent-to-Agent requests to return a clear error message when the agent ID parameter is missing. (#14229)
Add dynamicPackages bundler config for runtime-loaded packages and auto-detect pino (#11779)
Adds a new dynamicPackages bundler config option for packages that are loaded
dynamically at runtime and cannot be detected by static analysis (e.g.,
pino.transport({ target: "pino-opentelemetry-transport" })).
Usage:
import { Mastra } from '@mastra/core';
export const mastra = new Mastra({
bundler: {
dynamicPackages: ['my-custom-transport', 'some-plugin'],
},
});
Additionally, pino transport targets are now automatically detected from the bundled code, so most pino users won't need any configuration.
This keeps externals for its intended purpose (packages to not bundle) and
provides a clear mechanism for dynamic packages that need to be in the output
package.json.
Fixes #10893
Added observer context optimization for Observational Memory. The observation.previousObserverTokens field reduces Observer input token costs for long-running conversations: (#13568)
2000): Truncates the 'Previous Observations' section to a token budget, keeping the most recent observations and automatically replacing already-reflected lines with the buffered reflection summary. Set to 0 to omit previous observations entirely, or false to disable truncation and keep the full observation history.const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
previousObserverTokens: 10_000,
},
},
},
});
Updated exporters and event bus to use renamed observability types from @mastra/core. Added EventBuffer for batching non-tracing signals with configurable flush intervals. (#14214)
Breaking changes:
ObservabilityBus now takes a config object in its constructor (cardinalityFilter, autoExtractMetrics); setCardinalityFilter() and enableAutoExtractedMetrics() removedFixed agent playground panels growing together when content overflows. Left and right columns now scroll independently. (#14244)
Fixed an agent chat editor crash in Playground UI caused by duplicate CodeMirror state instances. (#14241)
Improved studio loading performance by lazy-loading the Prettier code formatter. Prettier and its plugins are now loaded on-demand when formatting is triggered, rather than being bundled in the initial page load. (#13934)
Improved list-style pages across the Playground UI (agents, datasets, MCPs, processors, prompt blocks, scorers, tools, workflows) with a new list layout and updated empty states. (#14173)
@mastra/schema-compat: patch (#14195)
Fixed published @mastra/schema-compat types so AI SDK v5 schemas resolve correctly for consumers
Fixed false z.toJSONSchema is not available errors for compatible Zod versions. (#14264)
What changed
Added @mastra/server/schemas export with utility types that infer path params, query params, request body, and response types from any route in SERVER_ROUTES. When you add a new route via createRoute(), it automatically appears in the RouteMap type — no manual contract needed. (#14008)
import type { RouteMap, RouteContract, InferPathParams, InferBody, InferResponse } from '@mastra/server/schemas';
type GetAgentParams = InferPathParams<RouteMap['GET /agents/:agentId']>;
// => { agentId: string }
type GenerateBody = InferBody<RouteMap['POST /agents/:agentId/generate']>;
// => { messages: CoreMessage[], ... }
type AgentResponse = InferResponse<RouteMap['GET /agents/:agentId']>;
// => { name: string, tools: ..., ... }
Fixed OpenAPI spec for custom route paths. Custom routes registered via registerApiRoute are served at the root path (e.g. /health), not under /api. The OpenAPI spec now correctly represents this so that API tools and clients using the spec will resolve them to the correct URL. (#13930)
Fixed an unnecessary runtime dependency in @mastra/server, reducing install size for consumers. Moved @mastra/schema-compat from dependencies to devDependencies since it is only needed at build time. (#14223)
The following packages were updated with dependency changes only:
@mastra/cloudflare adds a new Durable Objects–backed storage implementation (in addition to KV), with SQLite persistence, batch operations, and table/column validation—enabling more robust stateful storage on Cloudflare.
LocalFilesystem no longer treats absolute paths like /file.txt as workspace-relative; absolute paths now resolve to real filesystem locations (with containment checks), relative paths resolve against basePath, and ~/ expands to the home directory.
MCP tool calls are now traced with a dedicated MCP_TOOL_CALL span type (with server name/version metadata), Studio adds MCP-specific timeline styling, processor-triggered aborts are fully visible in traces, and workflow suspend/resume now preserves trace continuity under the original span.
Fixes include the agent loop continuing correctly when onIterationComplete returns continue: true, and preventing exponential token growth by running token-based message pruning at every step (including tool call continuations).
Sandbox process IDs are now string-based (ProcessHandle.pid: string) to support session IDs across providers, and sandboxes/filesystems expose underlying SDK instances via new provider-specific getters (e.g., sandbox.daytona, sandbox.blaxel, filesystem.client for S3, filesystem.storage/bucket for GCS).
LocalFilesystem no longer treats absolute paths (e.g. /src/index.ts) as basePath-relative; update callers to pass relative paths when targeting the workspace.ProcessHandle.pid changed from number to string; update any code that assumes numeric PIDs (including processes.get(...)).MCP tool calls now use MCP_TOOL_CALL span type instead of TOOL_CALL in traces. CoreToolBuilder detects mcpMetadata on tools and creates spans with MCP server name, version, and tool description attributes. (#13274)
Absolute paths now resolve to real filesystem locations instead of being treated as workspace-relative. (#13804)
Previously, LocalFilesystem in contained mode treated absolute paths like /file.txt as shorthand for basePath/file.txt (a "virtual-root" convention). This could silently resolve paths to unexpected locations — for example, /home/user/.config/file.txt would resolve to basePath/home/user/.config/file.txt instead of the real path.
Now:
/) are real filesystem paths, subject to containment checksfile.txt, src/index.ts) resolve against basePath~/Documents) expand to the home directoryIf your code passes paths like /file.txt to workspace filesystem methods expecting them to resolve relative to basePath, change them to relative paths:
// Before
await filesystem.readFile('/src/index.ts');
// After
await filesystem.readFile('src/index.ts');
Also fixed:
allowedPaths resolving against the working directory instead of basePath, causing unexpected permission errors when basePath differed from cwdallowedPaths directories that don't exist yet (e.g., during skills discovery)Changed ProcessHandle.pid type from number to string to support sandbox providers that use non-numeric process identifiers (e.g., session IDs). (#13591)
Before:
const handle = await sandbox.processes.spawn('node server.js');
handle.pid; // number
await sandbox.processes.get(42);
After:
const handle = await sandbox.processes.spawn('node server.js');
handle.pid; // string (e.g., '1234' for local, 'session-abc' for Daytona)
await sandbox.processes.get('1234');
Added a mastra/<version> User-Agent header to all provider API requests (OpenAI, Anthropic, Google, Mistral, Groq, xAI, DeepSeek, and others) across models.dev, Netlify, and Azure gateways for better traffic attribution. (#13087)
Update provider registry and model documentation with latest models and providers (9cede11)
Fixed processor-triggered aborts not appearing in traces. Processor spans now include abort details (reason, retry flag, metadata) and agent-level spans capture the same information when an abort short-circuits the agent run. This makes guardrail and processor aborts fully visible in tracing dashboards. (#14038)
Fix agent loop not continuing when onIterationComplete returns continue: true (#14170)
Fixed exponential token growth during multi-step agent workflows by implementing processInputStep on TokenLimiterProcessor and removing the redundant processInput method. Token-based message pruning now runs at every step of the agentic loop (including tool call continuations), keeping the in-memory message list within budget before each LLM call. Also refactored Tiktoken encoder to use the shared global singleton from getTiktoken() instead of creating a new instance per processor. (#13929)
Sub-agents with defaultOptions.memory configurations were having their memory settings overridden when called as tools from a parent agent. The parent unconditionally passed its own memory option (with newly generated thread/resource IDs), which replaced the sub-agent's intended memory configuration due to shallow object merging. (#11561)
This fix checks if the sub-agent has its own defaultOptions.memory before applying parent-derived memory settings. Sub-agents without their own memory config continue to receive parent-derived IDs as a fallback.
No code changes required for consumers - sub-agents with explicit defaultOptions.memory will now work correctly when used via the agents: {} option.
Fixed listConfiguredInputProcessors() and listConfiguredOutputProcessors() returning a combined workflow instead of individual processors. Previously, these methods wrapped all configured processors into a single committed workflow, making it impossible to inspect or look up processors by ID. Now they return the raw flat array of configured processors as intended. (#14158)
fetchWithRetry now backs off in sequence 2s → 4s → 8s and then caps at 10s. (#14159)
Preserve trace continuity across workflow suspend/resume for workflows run by the default engine, so resumed workflows appear as children of the original span in tracing tools. (#12276)
Added provider-specific blaxel getter to access the underlying Blaxel SandboxInstance directly. Deprecated the generic instance getter in favor of the new blaxel getter for better IDE discoverability and consistency with other sandbox providers. (#14166)
// Before
const blaxelSandbox = sandbox.instance;
// After
const blaxelSandbox = sandbox.blaxel;
Use provider-native string process IDs directly as ProcessHandle.pid, removing the previous parseInt() workaround. (#13591)
const handle = await sandbox.processes.spawn('node server.js');
handle.pid; // string — the Blaxel SDK's native process ID
feat: add Cloudflare Durable Objects storage adapter (#12366)
Adds a new Durable Objects-based storage implementation alongside the existing KV store. Includes SQL-backed persistence via DO's SQLite storage, batch operations, and proper table/column validation.
Added provider-specific daytona getter to access the underlying Daytona Sandbox instance directly. Deprecated the generic instance getter in favor of the new daytona getter for better IDE discoverability and consistency with other sandbox providers. (#14166)
// Before
const daytonaSandbox = sandbox.instance;
// After
const daytonaSandbox = sandbox.daytona;
Improved Daytona process handling to use provider session IDs directly as ProcessHandle.pid. (#13591)
const handle = await sandbox.processes.spawn('node server.js');
await sandbox.processes.get(handle.pid);
Fixed sandbox reconnection when Daytona sandbox is externally stopped or times out due to inactivity. Previously, the error thrown by the Daytona SDK (e.g. "failed to resolve container IP") did not match the known dead-sandbox patterns, so the automatic retry logic would not trigger and the error would propagate to the user. Added two new error patterns to correctly detect stopped sandboxes and trigger automatic recovery. (#14175)
Improved Studio load times by serving compressed static assets in both deploy and dev. Large bundles now download much faster and use significantly less bandwidth. (#13945)
--- (#14162)
@mastra/deployer: patch
Fixed deployment dependency resolution so required schema compatibility packages are resolved automatically.
Fixed gzip compression being applied globally to all API routes, causing JSON responses to be unreadable by clients that don't auto-decompress. Compression is now scoped to studio static assets only. (#14190)
ProcessHandle.pid is now a string. Numeric PIDs from the E2B SDK are stringified automatically. (#13591)
const handle = await sandbox.processes.spawn('node server.js');
handle.pid; // string (e.g., '1234')
Added public storage and bucket getters to access the underlying Google Cloud Storage instances directly. Use these when you need GCS features not exposed through the WorkspaceFilesystem interface. (#14166)
const gcsStorage = filesystem.storage;
const gcsBucket = filesystem.bucket;
mcpMetadata (server name and version) to every tool it creates, enabling automatic MCP_TOOL_CALL span tracing without user code changes. (#13274)Added stderr and cwd options to stdio server configuration so you can control child process error output and set the server working directory. (#13959)
import { MCPClient } from '@mastra/mcp';
const mcp = new MCPClient({
servers: {
myServer: {
command: 'node',
args: ['server.js'],
stderr: 'pipe',
cwd: '/path/to/server',
},
},
});
Observational Memory now performs local threshold checks with lower CPU and memory overhead. (#14178)
This update keeps the same multimodal thresholding behavior for image-aware inputs, so existing Observational Memory configurations continue to work without changes.
Updated form field components in Studio to use the new FieldBlock design system pattern. Replaced legacy SelectField, InputField, and SearchField with SelectFieldBlock, TextFieldBlock, and SearchFieldBlock across all domain components (observability, scores, datasets, templates). Refined button styles and layout improvements. (#14138)
Fixed Studio form crash when workflow input schemas contain z.array() fields with Zod v4. Array, union, and intersection fields now render and accept input correctly in the workflow run form. (#14131)
Added MCP-specific icon and color in trace timeline for mcp_tool_call spans. (#13274)
Change file browser root path from / to . so workspace navigation starts from the workspace directory instead of the host filesystem root. (#13804)
Added public client getter to access the underlying S3Client instance directly. Use this when you need S3 features not exposed through the WorkspaceFilesystem interface (e.g., presigned URLs, multipart uploads). (#14166)
const s3Client = filesystem.client;
zod/v4 compat layer from Zod 3.25.x is used. Schemas like ask_user and other harness tools were not being properly converted to JSON Schema when ~standard.jsonSchema was absent, causing type: "None" errors from the Anthropic API. (#14157)The following packages were updated with dependency changes only:
Agents can now use model functions that return full fallback arrays (ModelWithRetries[]), enabling context-driven model routing (tier/region/etc.) with nested/async selection and proper maxRetries inheritance.
Mastra adds Standard Schema normalization (toStandardSchema, standardSchemaToJSONSchema) across Zod v3/v4, AI SDK Schema, and JSON Schema via @mastra/schema-compat, unifying schema handling and improving strict-mode provider compatibility.
New onValidationError hook on ServerConfig and createRoute() lets you control status codes and response bodies for Zod validation failures, supported consistently in Hono/Express/Fastify/Koa adapters.
requestContext is now captured on tracing spans (and persisted in ClickHouse/PG/LibSQL/MSSQL span tables) and is supported on dataset items and experiments, allowing request-scoped metadata (tenant/user/flags) to flow through evaluation and observability.
Semantic recall is significantly faster across multiple adapters (notably Postgres for very large threads), PgVector adds metadataIndexes for btree indexing filtered metadata fields, and @mastra/pg now supports pgvector bit and sparsevec vector types.
^3.25.0 (for v3) or ^4.0.0 (for v4 support).feat: support dynamic functions returning model fallback arrays (#11975)
Agents can now use dynamic functions that return entire fallback arrays based on runtime context. This enables:
const agent = new Agent({
model: ({ requestContext }) => {
const tier = requestContext.get('tier');
if (tier === 'premium') {
return [
{ model: 'openai/gpt-4', maxRetries: 2 },
{ model: 'anthropic/claude-3-opus', maxRetries: 1 },
];
}
return [{ model: 'openai/gpt-3.5-turbo', maxRetries: 1 }];
},
});
const agent = new Agent({
model: ({ requestContext }) => {
const region = requestContext.get('region');
return [
{
model: ({ requestContext }) => {
// Select model variant based on region
return region === 'eu' ? 'openai/gpt-4-eu' : 'openai/gpt-4';
},
maxRetries: 2,
},
{ model: 'anthropic/claude-3-opus', maxRetries: 1 },
];
},
maxRetries: 1, // Agent-level default for models without explicit maxRetries
});
const agent = new Agent({
model: async ({ requestContext }) => {
// Fetch user's tier from database
const userId = requestContext.get('userId');
const user = await db.users.findById(userId);
if (user.tier === 'enterprise') {
return [
{ model: 'openai/gpt-4', maxRetries: 3 },
{ model: 'anthropic/claude-3-opus', maxRetries: 2 },
];
}
return [{ model: 'openai/gpt-3.5-turbo', maxRetries: 1 }];
},
});
MastraModelConfig (single model) or ModelWithRetries[] (array)maxRetries inherit agent-level maxRetries defaultModelFallbacks with all required fields filled inmaxRetries when not explicitly specifiedgetModelList() now correctly handles dynamic functions that return arraysgetLLM() and getModel() return behavior while adding dynamic fallback array supportNo breaking changes. All existing model configurations continue to work:
model: 'openai/gpt-4'model: [{ model: 'openai/gpt-4', maxRetries: 2 }]model: ({ requestContext }) => 'openai/gpt-4'model: ({ requestContext }) => [{ model: 'openai/gpt-4', maxRetries: 2 }]Closes #11951
Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added requestContext field to tracing spans. Each span now automatically captures a snapshot of the active RequestContext, making request-scoped values like user IDs, tenant IDs, and feature flags available when viewing traces. (#14020)
Added allowedWorkspaceTools to HarnessSubagent. Subagents now automatically inherit the parent agent's workspace. Use allowedWorkspaceTools to restrict which workspace tools a subagent can see: (#13940)
const subagent: HarnessSubagent = {
id: 'explore',
name: 'Explore',
allowedWorkspaceTools: ['view', 'search_content', 'find_files'],
};
Enabled tracing for tool executions through mcp server (#12804)
Traces now appear in the Observability UI for MCP server tool calls
Added result to processOutputResult args, providing resolved generation data (usage, text, steps, finishReason) directly. This replaces raw stream chunks with an easy-to-use OutputResult object containing the same data available in the onFinish callback. (#13810)
const usageProcessor: Processor = {
id: 'usage-processor',
processOutputResult({ result, messages }) {
console.log(`Text: ${result.text}`);
console.log(`Tokens: ${result.usage.inputTokens} in, ${result.usage.outputTokens} out`);
console.log(`Finish reason: ${result.finishReason}`);
console.log(`Steps: ${result.steps.length}`);
return messages;
},
};
Added requestContext support for dataset items and experiments. (#13938)
Dataset items now accept an optional requestContext field when adding or updating items. This lets you store per-item request context alongside inputs and ground truths.
Datasets now support a requestContextSchema field to describe the expected shape of request context on items.
Experiments now accept a requestContext option that gets passed through to agent.generate() during execution. Per-item request context merges with (and takes precedence over) the experiment-level context.
// Add item with request context
await dataset.addItem({
input: messages,
groundTruth: expectedOutput,
requestContext: { userId: '123', locale: 'en' },
});
// Run experiment with global request context
await runExperiment(mastra, {
datasetId: 'my-dataset',
targetType: 'agent',
targetId: 'my-agent',
requestContext: { environment: 'staging' },
});
Add Zod v4 and Standard Schema support (#12238)
z.record() calls to use 2-argument form (key + value schema) as required by Zod v4ZodError.errors to ZodError.issues (Zod v4 API change)@ai-sdk/provider versions for Zod v4 compatibilitypackages/core/src/schema/ module that re-exports from @mastra/schema-compatPublicSchema type for schema parameterstoStandardSchema() for normalizing schemas across Zod v3, Zod v4, AI SDK Schema, and JSON SchemastandardSchemaToJSONSchema() for JSON Schema conversion@mastra/schema-compat/adapters/ai-sdk, @mastra/schema-compat/adapters/zod-v3, @mastra/schema-compat/adapters/json-schemaunrepresentable: 'any' supportBREAKING CHANGE: Minimum Zod version is now ^3.25.0 for v3 compatibility or ^4.0.0 for v4
Update provider registry and model documentation with latest models and providers (332c014)
fix(workflows): add generic bail signature with overloads. The bail() function now uses method overloads - bail(result: TStepOutput) for backward compatibility and bail<T>(result: ...) for workflow type inference. This allows flexible early exits while maintaining type safety for workflow chaining. Runtime validation will be added in a follow-up. (#12211)
Fixed structured output parsing when JSON string fields include fenced JSON examples. (#13948)
Fixed writer being undefined in processOutputStream for all output processors. The root cause was that processPart in ProcessorRunner did not pass the writer to executeWorkflowAsProcessor in the outputStream phase. Since all user processors are wrapped into workflows via combineProcessorsIntoWorkflow, this meant no processor ever received a writer. Custom output processors (like guardrail processors) can now reliably use writer.custom() to emit stream events. (#14111)
Added JSON repair for malformed tool call arguments from LLM providers. When an LLM (e.g., Kimi/K2) generates broken JSON for tool call arguments, Mastra now attempts to fix common errors (missing quotes on property names, single quotes, trailing commas) before falling back to undefined. This reduces silent tool execution failures caused by minor JSON formatting issues. See https://github.com/mastra-ai/mastra/issues/11078 (#14033)
Fixed Windows shell command execution to avoid visible cmd.exe popups and broken output piping. (#13886)
Fixed OpenAI reasoning models (e.g. gpt-5-mini) failing with "function*call was provided without its required reasoning item" when the agent loops back after a tool call. The issue was that callProviderMetadata.openai carrying fc*\*item IDs was not being stripped alongside reasoning parts, causing the AI SDK to senditem_referenceinstead of inlinefunction_call content. (#14144)
Output processors can now inspect, modify, or block custom data-* chunks emitted by tools via writer.custom() during streaming. Processors must opt in by setting processDataParts = true to receive these chunks in processOutputStream. (#13823)
class MyDataProcessor extends Processor {
processDataParts = true;
processOutputStream(part, { abort }) {
if (part.type === 'data-sensitive') {
abort('Blocked sensitive data');
}
return part;
}
}
Fixed agent tool calls not being surfaced in evented workflow streams. Added StreamChunkWriter abstraction and stream format configuration ('legacy' | 'vnext') to forward agent stream chunks through the workflow output stream. (#12692)
Fixed OpenAI strict mode schema rejection when using agent networks with structured output. The compat layer was skipped when modelId was undefined, causing optional fields to be missing from the required array. (Fixes #12284) (#13695)
Fixed activeTools to also enforce at execution time, not just at the model prompt. Tool calls to tools not in the active set are now rejected with a ToolNotFoundError. (#13949)
Fix build failures on Windows when running build:patch-commonjs during pnpm run setup (#14029)
Experiments now fail immediately with a clear error when triggered on a dataset with zero items, instead of getting stuck in "pending" status forever. The experiment trigger API returns HTTP 400 for empty datasets. Unexpected errors during async experiment setup are now logged and mark the experiment as failed. (#14031)
fix: respect lastMessages: false in recall() to disable conversation history (#12951)
Setting lastMessages: false in Memory options now correctly prevents recall() from returning previous messages. Previously, the agent would retain the full conversation history despite this setting being disabled.
Callers can still pass perPage: false explicitly to recall() to retrieve all messages (e.g., for displaying thread history in a UI).
@mastra/core: patch (#14103)
Fixed reasoning content being lost in multi-turn conversations with thinking models (kimi-k2.5, DeepSeek-R1) when using OpenAI-compatible providers (e.g., OpenRouter).
Previously, reasoning content could be discarded during streaming, causing 400 errors when the model tried to continue the conversation. Multi-turn conversations now preserve reasoning content correctly across all turns.
fix(workflows): propagate logger to executionEngine (#12517)
When a custom logger is set on a Workflow via __registerPrimitives or __setLogger, it is now correctly propagated to the internal executionEngine. This ensures workflow step execution errors are logged through the custom logger instead of the default ConsoleLogger, enabling proper observability integration.
Added permission denied handling for dataset pages. Datasets now show a "Permission Denied" screen when the user lacks access, matching the behavior of agents, workflows, and other resources. (#13876)
Fixed stream freezing when using Anthropic's Programmatic Tool Calling (PTC). Streams that contain only tool-input streaming chunks (without explicit tool-call chunks) now correctly synthesize tool-call events and complete without hanging. See #12390. (#12400)
Fixed subagents receiving parent's tool call/result parts in their context messages. On subsequent queries in a conversation, these references to tools the subagent doesn't have caused models (especially via custom gateways) to return blank or incorrect results. Parent delegation tool artifacts are now stripped from context before forwarding to subagents. (#13927)
Memory now automatically creates btree indexes on thread_id and resource_id metadata fields when using PgVector. This prevents sequential scans on the memory_messages vector table, resolving performance issues under high load. (#14034)
Fixes #12109
Clarified the idGenerator documentation to reflect the current context-aware function signature and documented the available IdGeneratorContext fields used for type-specific ID generation. (#14081)
Reasoning content from OpenAI models is now stripped from conversation history before replaying it to the LLM, preventing API errors on follow-up messages while preserving reasoning data in the database. Fixes #12980. (#13418)
Added transient option for data chunks to skip database persistence. Chunks marked as transient are streamed to the client for live display but not saved to storage, reducing bloat from large streaming outputs. (#13869)
await context.writer?.custom({
type: 'data-my-stream',
data: { output: line },
transient: true,
});
Workspace tools now use this to mark stdout/stderr streaming chunks as transient.
Fixed message ID mismatch between generate/stream response and memory-stored messages. When an agent used memory, the message IDs returned in the response (e.g. response.uiMessages[].id) could differ from the IDs persisted to the database. This was caused by a format conversion that stripped message IDs during internal re-processing. Messages now retain their original IDs throughout the entire save pipeline. (#13796)
Fixed assistant messages to persist content.metadata.modelId during streaming. (#12969)
This ensures stored and processed assistant messages keep the model identifier.
Developers can now reliably read content.metadata.modelId from downstream storage adapters and processors.
Fixed savePerStep: true not actually persisting messages to storage during step execution. Previously, onStepFinish only accumulated messages in the in-memory MessageList but never flushed them to the storage backend. The only persistence path was executeOnFinish, which is skipped when the stream is aborted. Now messages are flushed to storage after each completed step, so they survive page refreshes and stream aborts. Fixes https://github.com/mastra-ai/mastra/issues/13984 (#14030)
Fixed agentic loop continuing indefinitely when model hits max output tokens (finishReason: 'length'). Previously, only 'stop' and 'error' were treated as termination conditions, causing runaway token generation up to maxSteps when using structuredOutput with generate(). The loop now correctly stops on 'length' finish reason. Fixes #13012. (#13861)
Fixed tool-call arguments being silently lost when LLMs append internal tokens to JSON (#13400)
LLMs (particularly via OpenRouter and OpenAI) sometimes append internal tokens like <|call|>, <|endoftext|>, or <|end|> to otherwise valid JSON in streamed tool-call arguments. Previously, these inputs would fail JSON.parse and the tool call would silently lose its arguments (set to undefined).
Now, sanitizeToolCallInput strips these token patterns before parsing, recovering valid data that was previously discarded. Valid JSON containing <|...|> inside string values is left untouched. Truly malformed JSON still gracefully returns undefined.
Fixes https://github.com/mastra-ai/mastra/issues/13185 and https://github.com/mastra-ai/mastra/issues/13261.
Fixed agent loop stopping prematurely when LLM returns tool calls with finishReason 'stop'. Some models (e.g., OpenAI gpt-5.3-codex) return 'stop' even when tool calls are present, causing the agent to halt instead of processing tool results and continuing. The agent now correctly continues the loop whenever tool calls exist, regardless of finishReason. (#14043)
Fixed (#14133)
Fixed observational memory activation using outdated buffered observations in some long-running threads. Activation now uses the latest thread state so the correct observations are promoted. (#13955)
Fixed model fallback retry behavior. Non-retryable errors (401, 403) are no longer retried on the same model before falling back. Retryable errors (429, 500) are now only retried by a single layer (p-retry) instead of being duplicated across two layers, preventing (maxRetries + 1)² total calls. The per-model maxRetries setting now correctly controls how many times p-retry retries on that specific model before the fallback loop moves to the next model. (#14039)
Added processor-driven response message ID rotation so streamed assistant IDs use the rotated ID. (#13887)
Processors that run outside the agent loop no longer need synthetic response message IDs.
Fixed a regression where dynamic model functions returning a single v1 model were treated as model arrays. (#14018)
Fixed requestContext not being forwarded to tools dynamically added by input processors. (#13827)
Added 'sandbox_access_request' to the HarnessEvent union type, enabling type-safe handling of sandbox access request events without requiring type casts. (#13648)
Fix wrong threadId and resourceId being sent to subagent (#13868)
handleChatStream not merging providerOptions from params and defaultOptions. Previously, params.providerOptions would completely replace defaultOptions.providerOptions instead of merging them. Now provider-specific keys from both sources are merged, with params.providerOptions taking precedence for the same provider. (#13820)requestContext column to the spans table. Request context data from tracing is now persisted alongside other span data. (#14020)Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Fixed slow semantic recall in the libsql, Cloudflare D1, and ClickHouse storage adapters. Recall performance no longer degrades as threads grow larger. (Fixes #11702) (#14022)
Added requestContext field to dataset item API endpoints and requestContextSchema to dataset CRUD endpoints. Added requestContext option to the experiment trigger endpoint, which gets forwarded to agent execution during experiments. (#13938)
Usage with @mastra/client-js:
// Create a dataset with a request context schema
await client.createDataset({
name: 'my-dataset',
requestContextSchema: {
type: 'object',
properties: { region: { type: 'string' } },
},
});
// Add an item with request context
await client.addDatasetItem({
datasetId: 'my-dataset',
input: { prompt: 'Hello' },
requestContext: { region: 'us-east-1' },
});
// Trigger an experiment with request context forwarded to agent
await client.triggerDatasetExperiment({
datasetId: 'my-dataset',
agentId: 'my-agent',
requestContext: { region: 'eu-west-1' },
});
Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Fixed slow semantic recall in the libsql, Cloudflare D1, and ClickHouse storage adapters. Recall performance no longer degrades as threads grow larger. (Fixes #11702) (#14022)
key:value format (e.g. instance_name:career-scout-api) were having :true appended to the value in the Datadog UI, resulting in career-scout-api:true instead of career-scout-api. Tags are now correctly split into proper key-value pairs before being sent to Datadog's LLM Observability API. (#13900)x-mastra-dev-playground header to the allowed CORS headers list. This resolves the browser error when the playground UI (running on a different port) makes requests to the Mastra dev server. (#14097)Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Improved semantic recall performance for large message histories. Semantic recall no longer loads entire threads when only the recalled messages are needed, eliminating delays that previously scaled with total message count. (Fixes #11702) (#14022)
Added requestContext column to the spans table. Request context data from tracing is now persisted alongside other span data. (#14020)
Added requestContext and requestContextSchema column support to dataset storage. Dataset items now persist request context alongside input and ground truth data. (#13938)
Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Fixed slow semantic recall in the libsql, Cloudflare D1, and ClickHouse storage adapters. Recall performance no longer degrades as threads grow larger. (Fixes #11702) (#14022)
Add image and file attachment support to Observational Memory. The observer can now see and reason about images and files in conversation history, and attachment token counts are included in observation thresholds. Provider-backed token counting is used when available, with results cached for faster subsequent runs. (#13953)
Added observational memory repro tooling for recording, analyzing, and sanitizing captures before sharing them. (#13877)
fix: respect lastMessages: false in recall() to disable conversation history (#12951)
Setting lastMessages: false in Memory options now correctly prevents recall() from returning previous messages. Previously, the agent would retain the full conversation history despite this setting being disabled.
Callers can still pass perPage: false explicitly to recall() to retrieve all messages (e.g., for displaying thread history in a UI).
fix(memory): handle dynamic functions returning ModelWithRetries[] in observational memory model resolution (#13902)
Fixed observational memory activation using outdated buffered observations in some long-running threads. Activation now uses the latest thread state so the correct observations are promoted. (#13955)
Fixed message loss when saving certain messages so text content is preserved. (#13918)
Added a compatibility guard so observational memory now fails fast when @mastra/core does not support request-response-id-rotation. (#13887)
requestContext column to the spans table. Request context data from tracing is now persisted alongside other span data. (#14020)Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Improved semantic recall performance for large message histories. Semantic recall no longer loads entire threads when only the recalled messages are needed, eliminating delays that previously scaled with total message count. (Fixes #11702) (#14022)
requestContext field to tracing spans. Each span now automatically captures a snapshot of the active RequestContext, making request-scoped values like user IDs, tenant IDs, and feature flags available when viewing traces. (#14020)Added metadataIndexes option to createIndex() for PgVector. This allows creating btree indexes on specific metadata fields in vector tables, significantly improving query performance when filtering by those fields. This is especially impactful for Memory's memory_messages table, which filters by thread_id and resource_id — previously causing sequential scans under load. (#14034)
Usage example:
await pgVector.createIndex({
indexName: 'my_vectors',
dimension: 1536,
metadataIndexes: ['thread_id', 'resource_id'],
});
Fixes #12109
Add support for pgvector's bit and sparsevec vector storage types (#12815)
You can now store binary and sparse vectors in @mastra/pg:
// Binary vectors for fast similarity search
await db.createIndex({
indexName: 'my_binary_index',
dimension: 128,
metric: 'hamming', // or 'jaccard'
vectorType: 'bit',
});
// Sparse vectors for BM25/TF-IDF representations
await db.createIndex({
indexName: 'my_sparse_index',
dimension: 500,
metric: 'cosine',
vectorType: 'sparsevec',
});
What's new:
vectorType: 'bit' for binary vectors with 'hamming' and 'jaccard' distance metricsvectorType: 'sparsevec' for sparse vectors (cosine, euclidean, dotproduct)bit defaults to 'hamming' when no metric is specifiedincludeVector round-trips work correctly for all vector typesAdded requestContext column to the spans table. Request context data from tracing is now persisted alongside other span data. (#14020)
Added requestContext and requestContextSchema column support to dataset storage. Dataset items now persist request context alongside input and ground truth data. (#13938)
Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. (#14021)
For example, calling db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } }) will silently ignore futureField if it doesn't exist in the database table, rather than throwing. The same applies to update — unknown fields in the data payload are dropped before building the SQL statement.
Fixed slow semantic recall in the Postgres storage adapter for large threads. Recall now completes in under 500ms even for threads with 7,000+ messages, down from ~30 seconds. (Fixes #11702) (#14022)
Added Playground and Traces tabs to the agent detail page. (#13938)
Agent Playground tab provides a side-by-side environment for iterating on agent configuration (instructions, tools, model settings) and testing changes in a live chat — without modifying the deployed agent. Includes version comparison, request context configuration, and the ability to trigger dataset experiments directly from the playground.
Agent Traces tab shows a compact table of all agent traces with columns for status, timestamp, input preview, output preview, and duration. Supports date range filtering, infinite scroll pagination, and clicking rows to inspect full trace details. Includes checkbox selection and bulk "Add to dataset" for quickly building evaluation datasets from production traces.
Tools edit page now shows configured (enabled) tools in a dedicated section at the top, making it easier to find and edit tools that are already in use.
Dataset save actions on the test chat: per-message save button on user messages and a "Save full conversation" action at the bottom of the thread.
Added input message preview column to the observability trace list. You can now see a truncated preview of user input messages directly in the trace table, making it easier to find specific traces without clicking into each one. (#14025)
The "Run Experiment" button is now disabled when a dataset has no items, with a tooltip explaining that items must be added first. (#14031)
fix: maxTokens from Studio Advanced Settings now correctly limits model output (#13912)
The modelSettingsArgs object was prematurely renaming maxTokens to maxOutputTokens. The React hook (useChat) destructures maxTokens from this object, so the rename caused it to receive undefined, and the value was silently dropped from the API request body.
Added permission denied handling for dataset pages. Datasets now show a "Permission Denied" screen when the user lacks access, matching the behavior of agents, workflows, and other resources. (#13876)
Fixed sandbox execution badge to show full streaming output during live sessions instead of snapping to the truncated tool result. The truncated view now only appears after page refresh when streaming data is no longer available. (#13869)
Fix the observational memory sidebar so the observation token label uses the live observation window token count shown by the progress UI. (#13953)
Add Zod v4 and Standard Schema support (#12238)
z.record() calls to use 2-argument form (key + value schema) as required by Zod v4ZodError.errors to ZodError.issues (Zod v4 API change)@ai-sdk/provider versions for Zod v4 compatibilitypackages/core/src/schema/ module that re-exports from @mastra/schema-compatPublicSchema type for schema parameterstoStandardSchema() for normalizing schemas across Zod v3, Zod v4, AI SDK Schema, and JSON SchemastandardSchemaToJSONSchema() for JSON Schema conversion@mastra/schema-compat/adapters/ai-sdk, @mastra/schema-compat/adapters/zod-v3, @mastra/schema-compat/adapters/json-schemaunrepresentable: 'any' supportBREAKING CHANGE: Minimum Zod version is now ^3.25.0 for v3 compatibility or ^4.0.0 for v4
Fixed Gemini supervisor agent tool calls failing with INVALID_ARGUMENT when delegated tool schemas include nullable fields. Fixes #13988. (#14012)
Fixed OpenAI and OpenAI Reasoning compat layers to ensure all properties appear in the JSON Schema required array when using processToJSONSchema. This prevents OpenAI strict mode rejections for schemas with optional, default, or nullish fields. (Fixes #12284) (#13695)
Added onValidationError hook to ServerConfig and createRoute(). When a request fails Zod schema validation (query parameters, request body, or path parameters), this hook lets you customize the error response — including the HTTP status code and response body — instead of the default 400 response. Set it on the server config to apply globally, or on individual routes to override per-route. All server adapters (Hono, Express, Fastify, Koa) support this hook. (#13477)
const mastra = new Mastra({
server: {
onValidationError: (error, context) => ({
status: 422,
body: {
ok: false,
errors: error.issues.map(i => ({
path: i.path.join('.'),
message: i.message,
})),
source: context,
},
}),
},
});
Added requestContext field to dataset item API endpoints and requestContextSchema to dataset CRUD endpoints. Added requestContext option to the experiment trigger endpoint, which gets forwarded to agent execution during experiments. (#13938)
Usage with @mastra/client-js:
// Create a dataset with a request context schema
await client.createDataset({
name: 'my-dataset',
requestContextSchema: {
type: 'object',
properties: { region: { type: 'string' } },
},
});
// Add an item with request context
await client.addDatasetItem({
datasetId: 'my-dataset',
input: { prompt: 'Hello' },
requestContext: { region: 'us-east-1' },
});
// Trigger an experiment with request context forwarded to agent
await client.triggerDatasetExperiment({
datasetId: 'my-dataset',
agentId: 'my-agent',
requestContext: { region: 'eu-west-1' },
});
Experiments now fail immediately with a clear error when triggered on a dataset with zero items, instead of getting stuck in "pending" status forever. The experiment trigger API returns HTTP 400 for empty datasets. Unexpected errors during async experiment setup are now logged and mark the experiment as failed. (#14031)
Fixed getPublicOrigin to parse only the first value from the X-Forwarded-Host header. When requests pass through multiple proxies, each proxy appends its host to the header, creating a comma-separated list. The previous code used the raw value, producing a malformed URL that broke OAuth redirect URIs. Now only the first (client-facing) host is used, per RFC 7239. (#13935)
Add new models to GeminiVoiceModel type and mark deprecated models with @deprecated JSDoc. (#12625)
Added:
gemini-live-2.5-flash-native-audio (GA)gemini-live-2.5-flash-preview-native-audio-09-2025gemini-2.5-flash-native-audio-preview-12-2025gemini-2.5-flash-native-audio-preview-09-2025Deprecated:
gemini-2.0-flash-exp (shut down 2025-12-09)gemini-2.0-flash-exp-image-generation (shut down 2025-11-14)gemini-2.0-flash-live-001 (shut down 2025-12-09)gemini-live-2.5-flash-preview-native-audio (use gemini-live-2.5-flash-preview-native-audio-09-2025)gemini-2.5-flash-exp-native-audio-thinking-dialog (shut down 2025-10-20)gemini-live-2.5-flash-preview (shut down 2025-12-09)The following packages were updated with dependency changes only:
inputExamples to improve model tool-call accuracyTool definitions can now include inputExamples, which are passed through to models that support them (e.g., Anthropic’s input_examples) to demonstrate valid inputs and reduce malformed tool calls.
RequestContext (auth/cookie forwarding)@mastra/mcp adds requestContext support to custom fetch functions for MCP HTTP server definitions, enabling request-scoped forwarding of cookies/bearer tokens during tool execution while remaining backward compatible with (url, init) fetch signatures.
Provider stream errors are now consistently surfaced from generate()/resumeGenerate(), AI SDK errors are routed through the Mastra logger with structured context, client-side tools no longer lose history in stateless deployments, and memory.deleteThread()/deleteMessages() now automatically cleans up orphaned vector embeddings across supported vector stores.
Add inputExamples support on tool definitions to show AI models what valid tool inputs look like. Models that support this (e.g., Anthropic's input_examples) will receive the examples alongside the tool schema, improving tool call accuracy. (#12932)
inputExamples field to ToolAction, CoreTool, and Tool classconst weatherTool = createTool({
id: "get-weather",
description: "Get weather for a location",
inputSchema: z.object({
city: z.string(),
units: z.enum(["celsius", "fahrenheit"])
}),
inputExamples: [{ input: { city: "New York", units: "fahrenheit" } }, { input: { city: "Tokyo", units: "celsius" } }],
execute: async ({ city, units }) => {
return await fetchWeather(city, units);
}
});
dependencies updates: (#13209)
p-map@^7.0.4 ↗︎ (from ^7.0.3, in dependencies)dependencies updates: (#13210)
p-retry@^7.1.1 ↗︎ (from ^7.1.0, in dependencies)Update provider registry and model documentation with latest models and providers (33e2fd5)
Fixed execute_command tool timeout parameter to accept seconds instead of milliseconds, preventing agents from accidentally setting extremely short timeouts (#13799)
Skill tools are now stable across conversation turns and prompt-cache friendly. (#13744)
skill-activate → skill — returns full skill instructions directly in the tool resultskill-read-reference, skill-read-script, skill-read-asset → skill_readskill-search → skill_search<available_skills> in the system message is now sorted deterministicallyFixed Cloudflare Workers build failures when using @mastra/core. Local process execution now loads its runtime dependency lazily, preventing incompatible Node-only modules from being bundled during worker builds. (#13813)
Fix mimeType → mediaType typo in sendMessage file part construction. This caused file attachments to be routed through the V4 adapter instead of V5, preventing them from being correctly processed by AI SDK v5 providers. (#13833)
Fixed onIterationComplete feedback being discarded when it returns { continue: false } — feedback is now added to the conversation and the model gets one final turn to produce a text response before the loop stops. (#13759)
Fixed generate() and resumeGenerate() to always throw provider stream errors. Previously, certain provider errors were silently swallowed, returning false "successful" empty responses. Now errors are always surfaced to the caller, making retry logic reliable when providers fail transiently. (#13802)
Remove the default maxSteps limit so stopWhen can control sub-agent execution (#13764)
Fix suspendedToolRunId required error when it shouldn't be required (#13722)
Fixed subagent tool defaulting maxSteps to 50 when no stop condition is configured, preventing unbounded execution loops. When stopWhen is set, maxSteps is left to the caller. (#13777)
Fixed prompt failures by removing assistant messages that only contain sources before model calls. (#13790)
Fixed RequestContext constructor crashing when constructed from a deserialized plain object. (#13856)
Fixed LLM errors (generateText, generateObject, streamText, streamObject) being swallowed by the AI SDK's default handler instead of being routed through the Mastra logger. Errors now appear with structured context (runId, modelId, provider, etc.) in your logger, and streaming errors are captured via onError callbacks. (#13857)
Fixed workspace tool output truncation so it no longer gets prematurely cut off when short lines precede a very long line (e.g. minified JSON). Output now uses the full token budget instead of stopping at line boundaries, resulting in more complete tool results. (#13828)
Fixed subagent tool to default maxSteps to 50 when no stopWhen condition is configured, preventing unbounded agent loops. When stopWhen is set, maxSteps remains unset so the stop condition controls termination. (#13777)
semver@^7.7.4 ↗︎ (from ^7.7.2, in dependencies)41e48c1, 82469d3, 33e2fd5, 7ef6e2c, 08072ec, ef9d0f0, b12d2a5, fa37d39, b12d2a5, 1391f22, 71c38bf, f993c38, f51849a, 3ceb231, 9bf3a0d, cafa045, 1fd9ddb, 1391f22, ef888d2, e7a567c, 3626623, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Fixes inline import() statements referencing workspace packages (via @internal/*) in publish .d.ts files (#13811)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
dependencies updates: (#13134)
jsonwebtoken@^9.0.3 ↗︎ (from ^9.0.2, in dependencies)dependencies updates: (#13135)
jwks-rsa@^3.2.2 ↗︎ (from ^3.2.0, in dependencies)ae52b89, 1ea40a9, 41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
lru-cache@^11.2.6 ↗︎ (from ^11.1.0, in dependencies)ae52b89, 1ea40a9, 41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
Fix agent losing conversation context ("amnesia") when using client-side tools with stateless server deployments. Recursive calls after tool execution now include the full conversation history when no threadId is provided. (#11476)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
couchbase@^4.6.1 ↗︎ (from ^4.6.0, in dependencies)41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, b12d2a5, d9d228c, 5576507, 79d69c9, 9fb4c06, 94f44b8, 13187db, 2ae5311, b5a8ea5, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Added custom user-agent header to all Elasticsearch requests. Every request now identifies itself as mastra-elasticsearch/<version> via the user-agent header, enabling usage tracking in Elasticsearch server logs and analytics tools. (#13740)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, b12d2a5, d9d228c, 5576507, 79d69c9, 9fb4c06, 94f44b8, 13187db, 2ae5311, b5a8ea5, 6135ef4]:
dependencies updates: (#10195)
fastembed@^2.1.0 ↗︎ (from ^1.14.4, in dependencies)Add warmup() export to pre-download fastembed models without creating ONNX sessions. This prevents concurrent download race conditions when multiple consumers call FlagEmbedding.init() in parallel, which could corrupt the model archive and cause Z_BUF_ERROR. (#13752)
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, b12d2a5, d9d228c, 5576507, 79d69c9, 9fb4c06, 94f44b8, 13187db, 2ae5311, b5a8ea5, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, b12d2a5, d9d228c, 5576507, 79d69c9, 9fb4c06, 94f44b8, 13187db, 2ae5311, b5a8ea5, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, b12d2a5, d9d228c, 5576507, 79d69c9, 9fb4c06, 94f44b8, 13187db, 2ae5311, b5a8ea5, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, a8e2e2e, 33e2fd5, 7ef6e2c, 08072ec, ef9d0f0, b12d2a5, 3ada2da, fa37d39, b12d2a5, 1391f22, 71c38bf, f993c38, f51849a, 3ceb231, 9bf3a0d, cafa045, 1fd9ddb, 1391f22, ef888d2, e7a567c, 3626623, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Added requestContext support to the custom fetch option in MCP client HTTP server definitions. The fetch function now receives the current request context as an optional third argument, enabling users to forward authentication cookies, bearer tokens, and other request-scoped data from the incoming request to remote MCP servers during tool execution. (#13773)
Example usage:
const mcp = new MCPClient({
servers: {
myServer: {
url: new URL("https://api.example.com/mcp"),
fetch: async (url, init, requestContext) => {
const headers = new Headers(init?.headers);
const cookie = requestContext?.get("cookie");
if (cookie) {
headers.set("cookie", cookie);
}
return fetch(url, { ...init, headers });
}
}
}
});
This change is fully backward-compatible — existing fetch functions with (url, init) signatures continue to work unchanged. Closes #13769.
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, 9e21667, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Improved confidence in observational memory threshold behavior through expanded automated test coverage. No public API changes. (#13785)
Improved Observational Memory reliability: fixed future-date annotations producing invalid strings, fixed a duplicate inline-date matching bug, and hardened the process-level operation registry against concurrent operation tracking errors. (#13774)
Fixed buffered activation cleanup to respect the configured retention floor so message history does not collapse unexpectedly after activation. (#13745)
Fixed orphaned vector embeddings accumulating when memory threads or messages are deleted. Calling memory.deleteThread() or memory.deleteMessages() now automatically cleans up associated vector embeddings across all supported vector store backends. Cleanup is non-blocking and does not slow down the delete call. Also fixed updateMessages not cleaning up old vectors correctly when using a non-default index separator (e.g. Pinecone). (#12227)
Repeated token counts in OM are faster and more reliable, estimates are now persisted on metadata, and totals remain consistent after saving and loading conversations. (#13745)
Improved observational memory marker creation consistency for more reliable debugging and UI status behavior. No public API changes. (#13779)
Fixed observational memory token counting to use stored model output for tool results transformed with toModelOutput. (#13862)
Fix working memory data corruption when using resource scope across threads (#12415)
updateWorkingMemory() to prevent race conditions during concurrent updates__experimental_updateWorkingMemoryVNext() to detect template duplicates with whitespace variationsupdateWorkingMemoryTool to prevent LLM from accidentally wiping existing data by sending empty templateUpdated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Fixed MongoDB observational memory buffering so legacy records with bufferedObservationChunks: null can append chunks safely and continue storing chunk buffers as arrays after activation. (#13803)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
@mastra/observability by requiring @mastra/core >= 1.9.0. (#13838)
This prevents installs with older core versions that can cause runtime errors.41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, 08072ec, ef9d0f0, b12d2a5, fa37d39, b12d2a5, 1391f22, 71c38bf, f993c38, f51849a, 3ceb231, 9bf3a0d, cafa045, 1fd9ddb, 1391f22, ef888d2, e7a567c, 3626623, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
dependencies updates: (#13236)
papaparse@^5.5.3 ↗︎ (from ^5.4.1, in dependencies)dependencies updates: (#13271)
@codemirror/merge@^6.12.0 ↗︎ (from ^6.10.2, in dependencies)@codemirror/view@^6.39.15 ↗︎ (from ^6.39.14, in dependencies)dependencies updates: (#13283)
semver@^7.7.4 ↗︎ (from ^7.7.2, in dependencies)dependencies updates: (#13771)
@uiw/codemirror-theme-dracula@^4.25.5 ↗︎ (from ^4.25.4, in dependencies)dependencies updates: (#13847)
@codemirror/autocomplete@^6.20.1 ↗︎ (from ^6.20.0, in dependencies)@codemirror/lang-javascript@^6.2.5 ↗︎ (from ^6.2.4, in dependencies)@codemirror/view@^6.39.16 ↗︎ (from ^6.39.15, in dependencies)Fixed experiment results page showing only 10 items, empty summary tab with no scorers, and scores not updating during experiment runs. (#13831)
Updated skill activation indicators to match new skill tool names. (#13744)
Fix saving traces and scores as dataset items in the Studio. (#13800)
Fixed Playground UI agent settings so temperature is no longer reset to 1 on refresh. Temperature now stays unset unless saved settings or code defaults provide a value. (#13778)
Fixed documentation link in empty datasets page pointing to the correct datasets docs instead of evals (#13872)
Fix wrong threads showing for agents on studio (#13789)
Fixed dev playground auth bypass not working in capabilities endpoint. The client now passes MastraClient headers (including x-mastra-dev-playground) to the auth capabilities endpoint, and the server returns disabled state when this header is present. This prevents the login gate from appearing in dev playground mode. (#13801)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, 88061a8, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, d1e26f0, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, d1e26f0, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, e9060ef, 13187db, 2ae5311, 6135ef4]:
Fixed Studio so custom gateway models appear in the provider list. (#13772) Improved /agents/providers API to include both built-in providers and providers from configured custom gateways.
Fixed dev playground auth bypass not working in capabilities endpoint. The client now passes MastraClient headers (including x-mastra-dev-playground) to the auth capabilities endpoint, and the server returns disabled state when this header is present. This prevents the login gate from appearing in dev playground mode. (#13801)
Updated dependencies [41e48c1, 82469d3, 33e2fd5, 7ef6e2c, b12d2a5, fa37d39, b12d2a5, 71c38bf, f993c38, f51849a, 9bf3a0d, cafa045, 1fd9ddb, 6135ef4, d9d228c, 5576507, 79d69c9, 94f44b8, 13187db, 2ae5311, 6135ef4]:
Workspaces get significant capabilities: workspace tool output is now token-limited, ANSI-stripped for model context, and .gitignore-aware to reduce token usage. Sandbox commands support abortSignal for cancellation, plus background process streaming callbacks (onStdout/onStderr/onExit), and local symlink mounts in LocalSandbox. Tools can be exposed under custom names via WorkspaceToolConfig.name. LSP binary resolution is now configurable (binaryOverrides, searchPaths, packageRunner), making workspace diagnostics work reliably across monorepos, global installs, and custom setups.
Mastra now ships a pluggable auth system (@mastra/core/auth) plus server-side auth routes and convention-based route permission enforcement (@mastra/server + all server adapters). New auth provider packages (@mastra/auth-cloud, @mastra/auth-studio, @mastra/auth-workos) add OAuth/SSO, session management, and RBAC—Studio UI also gains permission-gated auth screens/components.
Workflow results now include stepExecutionPath (also available mid-execution and preserved across resume/restart), and execution logs are smaller by deduping payloads. Storage backends add atomic updateWorkflowResults/updateWorkflowState with a supportsConcurrentUpdates() check—enabling safer concurrent workflow updates (supported in e.g. Postgres/LibSQL/MongoDB/DynamoDB/Upstash; explicitly not supported in some backends like ClickHouse/Cloudflare/Lance).
harness.sendMessage() now uses files instead of images (supports any file type, preserves filenames, and auto-decodes text-based files).Added onStepFinish and onError callbacks to NetworkOptions, allowing per-LLM-step progress monitoring and custom error handling during network execution. Closes #13362. (#13370)
Before: No way to observe per-step progress or handle errors during network execution.
const stream = await agent.network('Research AI trends', {
memory: { thread: 'my-thread', resource: 'my-resource' },
});
After: onStepFinish and onError are now available in NetworkOptions.
const stream = await agent.network('Research AI trends', {
onStepFinish: event => {
console.log('Step completed:', event.finishReason, event.usage);
},
onError: ({ error }) => {
console.error('Network error:', error);
},
memory: { thread: 'my-thread', resource: 'my-resource' },
});
Add workflow execution path tracking and optimize execution logs (#11755)
Workflow results now include a stepExecutionPath array showing the IDs of each step that executed during a workflow run. You can use this to understand exactly which path your workflow took.
// Before: no execution path in results
const result = await workflow.execute({ triggerData });
// result.stepExecutionPath → undefined
// After: stepExecutionPath is available in workflow results
const result = await workflow.execute({ triggerData });
console.log(result.stepExecutionPath);
// → ['step1', 'step2', 'step4'] — the actual steps that ran
stepExecutionPath is available in:
WorkflowResult.stepExecutionPath) — see which steps ran after execution completesExecutionContext.stepExecutionPath) — access the path mid-execution inside your stepsWorkflow execution logs are now more compact and easier to read. Step outputs are no longer duplicated as the next step's input, reducing the size of execution results while maintaining full visibility.
Key improvements:
stepExecutionPathThis is particularly beneficial for AI agents and LLM-based workflows where reducing context size improves performance and cost efficiency.
Related: #8951
Added authentication interfaces and Enterprise Edition RBAC support. (#13163)
New @mastra/core/auth export with pluggable interfaces for building auth providers:
IUserProvider — user lookup and managementISessionProvider — session creation, validation, and cookie handlingISSOProvider — SSO login and callback flowsICredentialsProvider — username/password authenticationDefault implementations included out of the box:
Enterprise Edition (@mastra/core/auth/ee) adds RBAC, ACL, and license validation:
import { buildCapabilities } from '@mastra/core/auth/ee';
const capabilities = buildCapabilities({
rbac: myRBACProvider,
acl: myACLProvider,
});
Built-in role definitions (owner, admin, editor, viewer) and a static RBAC provider are included for quick setup. Enterprise features require a valid license key via the MASTRA_EE_LICENSE environment variable.
Workspace sandbox tool results (execute_command, kill_process, get_process_output) sent to the model now strip ANSI color codes via toModelOutput, while streamed output to the user keeps colors. This reduces token usage and improves model readability. (#13440)
Workspace execute_command tool now extracts trailing | tail -N pipes from commands so output streams live to the user, while the final result sent to the model is still truncated to the last N lines.
Workspace tools that return potentially large output now enforce a token-based output limit (~3k tokens by default) using tiktoken for accurate counting. The limit is configurable per-tool via maxOutputTokens in WorkspaceToolConfig. Each tool uses a truncation strategy suited to its output:
read_file, grep, list_files — truncate from the end (keep imports, first matches, top-level tree)execute_command, get_process_output, kill_process — head+tail sandwich (keep early output + final status)const workspace = new Workspace({
tools: {
mastra_workspace_execute_command: {
maxOutputTokens: 5000, // override default 3k
},
},
});
Workspace tools (list_files, grep) now automatically respect .gitignore, filtering out directories like node_modules and dist from results. Explicitly targeting an ignored path still works. Also lowered the default tree depth from 3 to 2 to reduce token usage. (#13724)
Added maxSteps and stopWhen support to HarnessSubagent. (#13653)
You can now define maxSteps and stopWhen on a harness subagent so spawned subagents can use custom loop limits instead of relying only on the default maxSteps: 50 fallback.
const harness = new Harness({
id: 'dev-harness',
modes: [{ id: 'build', default: true, agent: buildAgent }],
subagents: [
{
id: 'explore',
name: 'Explore',
description: 'Inspect the codebase',
instructions: 'Investigate and summarize findings.',
defaultModelId: 'openai/gpt-4o',
maxSteps: 7,
stopWhen: ({ steps }) => steps.length >= 3,
},
],
});
Added OpenAI WebSocket transport for streaming responses with auto-close and manual transport access (#13531)
Added name property to WorkspaceToolConfig for remapping workspace tool names. Tools can now be exposed under custom names to the LLM while keeping the original constant as the config key. (#13687)
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './project' }),
tools: {
mastra_workspace_read_file: { name: 'view' },
mastra_workspace_grep: { name: 'search_content' },
mastra_workspace_edit_file: { name: 'string_replace_lsp' },
},
});
Also removed hardcoded tool-name cross-references from edit-file and ast-edit tool descriptions, since tools can be renamed or disabled.
Adds requestContext passthrough to Harness runtime APIs. (#13650)
Added
You can now pass requestContext to Harness runtime methods so tools and subagents receive request-scoped values.
Added binaryOverrides, searchPaths, and packageRunner options to LSPConfig to support flexible language server binary resolution. (#13677)
Previously, workspace LSP diagnostics only worked when language server binaries were installed in the project's node_modules/.bin/. There was no way to use globally installed binaries or point to a custom install.
New LSPConfig fields:
binaryOverrides: Override the binary command for a specific server, bypassing the default lookup. Useful when the binary is installed in a non-standard location.searchPaths: Additional directories to search when resolving Node.js modules (e.g. typescript/lib/tsserver.js). Each entry should be a directory whose node_modules contains the required packages.packageRunner: Package runner to use as a last-resort fallback when no binary is found (e.g. 'npx --yes', 'pnpm dlx', 'bunx'). Off by default — package runners can hang in monorepos with workspace links.Binary resolution order per server: explicit binaryOverrides override → project node_modules/.bin/ → process.cwd() node_modules/.bin/ → searchPaths node_modules/.bin/ → global PATH → packageRunner fallback.
const workspace = new Workspace({
lsp: {
// Point to a globally installed binary
binaryOverrides: {
typescript: '/usr/local/bin/typescript-language-server --stdio',
},
// Resolve typescript/lib/tsserver.js from a tool's own node_modules
searchPaths: ['/path/to/my-tool'],
// Use a package runner as last resort (off by default)
packageRunner: 'npx --yes',
},
});
Also exported buildServerDefs(config?) for building config-aware server definitions, and LSPConfig / LSPServerDef types from @mastra/core/workspace.
Added a unified observability type system with interfaces for structured logging, metrics (counters, gauges, histograms), scores, and feedback alongside the existing tracing infrastructure. (#13058)
Why? Previously, only tracing flowed through execution contexts. Logging was ad-hoc and metrics did not exist. This change establishes the type system and context plumbing so that when concrete implementations land, logging and metrics will flow through execute callbacks automatically — no migration needed.
What changed:
ObservabilityContext interface combining tracing, logging, and metrics contextsLoggerContext, MetricsContext, ScoreInput, FeedbackInput, and ObservabilityEventBuscreateObservabilityContext() factory and resolveObservabilityContext() resolver with no-op defaults for graceful degradationloggerVNext and metrics getters to the Mastra classAdded setServer() public method to the Mastra class, enabling post-construction configuration of server settings. This allows platform tooling to inject server defaults (e.g. auth) into user-created Mastra instances at deploy time. (#13729)
const mastra = new Mastra({ agents: { myAgent } });
// Platform tooling can inject server config after construction
mastra.setServer({ ...mastra.getServer(), auth: new MastraAuthWorkos() });
Added local symlink mounts in LocalSandbox so sandboxed commands can access locally-mounted filesystem paths. (#13474)
Improved mounted paths so commands resolve consistently in local sandboxes.
Improved workspace instructions so developers can quickly find mounted data paths.
Why: Local sandboxes can now run commands against locally-mounted data without manual path workarounds.
Usage example:
const workspace = new Workspace({
mounts: {
'/data': new LocalFilesystem({ basePath: '/path/to/data' }),
},
sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
});
await workspace.init();
// Sandboxed commands can access the mount path via symlink
await workspace.sandbox.executeCommand('ls data');
Abort signal and background process callbacks (#13597)
abortSignal in command optionsexecute_command now support onStdout, onStderr, and onExit callbacks for streaming output and exit notificationsbackgroundProcesses config in workspace tool options for wiring up background process callbacksAdded supportsConcurrentUpdates() method to WorkflowsStorage base class and abstract updateWorkflowResults/updateWorkflowState methods for atomic workflow state updates. The evented workflow engine now checks supportsConcurrentUpdates() and throws a clear error if the storage backend does not support concurrent updates. (#12575)
Update provider registry and model documentation with latest models and providers (edee4b3)
Fixed sandbox command execution crashing the parent process on some Node.js versions by explicitly setting stdio to pipe for detached child processes. (#13697)
Fixed an issue where generating a response in an empty thread (system-only messages) would throw an error. Providers that support system-only prompts like Anthropic and OpenAI now work as expected. A warning is logged for providers that require at least one user message (e.g. Gemini). Fixes #13045. (#13164)
Sanitize invalid tool names in agent history so Bedrock retries continue instead of failing request validation. (#13633)
Fixed path matching for auto-indexing and skills discovery. (#13511)
Single file paths, directory globs, and SKILL.md file globs now resolve consistently.
Trailing slashes are now handled correctly.
Harness.cloneThread() now resolves dynamic memory factories before cloning, fixing "cloneThread is not a function" errors when memory is provided as a factory function. HarnessConfig.memory type widened to DynamicArgument<MastraMemory>. (#13569)
Fixed workspace tools being callable by their old default names (e.g. mastra_workspace_edit_file) when renamed via tools config. The tool's internal id is now updated to match the remapped name, preventing fallback resolution from bypassing the rename. (#13694)
Reduced default max output tokens from 3000 to 2000 for all workspace tools. List files tool uses a 1000 token limit. Suppressed "No errors or warnings" LSP diagnostic message when there are no issues. (#13730)
Add first-class custom provider support for MastraCode model selection and routing. (#13682)
/custom-providers command to create, edit, and delete custom OpenAI-compatible providers and manage model IDs under each provider.settings.json with schema parsing/validation updates.customModelCatalogProvider so custom models appear in existing selectors (/models, /subagents).ModelRouterLanguageModel using provider-specific URL and optional API key settings.sendMessage now accepts files instead of images, supporting any file type with optional filename. (#13574)
Breaking change: Rename images to files when calling harness.sendMessage():
// Before
await harness.sendMessage({
content: 'Analyze this',
images: [{ data: base64Data, mimeType: 'image/png' }],
});
// After
await harness.sendMessage({
content: 'Analyze this',
files: [{ data: base64Data, mediaType: 'image/png', filename: 'screenshot.png' }],
});
files accepts { data, mediaType, filename? } — filenames are now preserved through storage and message historytext/*, application/json) are automatically decoded to readable text content instead of being sent as binary, which models could not processHarnessMessageContent now includes a file type, so file parts round-trip correctly through message historyFixed Agent Network routing failures for users running Claude models through AWS Bedrock by removing trailing whitespace from the routing assistant message. (#13624)
Fixed thread title generation when user messages include file parts (for example, images). (#13671) Titles now generate reliably instead of becoming empty.
Fixed parallel workflow tool calls so each call runs independently. (#13478)
When an agent starts multiple tool calls to the same workflow at the same time, each call now runs with its own workflow run context. This prevents duplicated results across parallel calls and ensures each call returns output for its own input. Also ensures workflow tool suspension and manual resumption correctly preserves the run context.
Fixed sub-agent instructions being overridden when the parent agent uses an OpenAI model. Previously, OpenAI models would fill in the optional instructions parameter when calling a sub-agent tool, completely replacing the sub-agent's own instructions. Now, any LLM-provided instructions are appended to the sub-agent's configured instructions instead of replacing them. (#13578)
Tool lifecycle hooks (onInputStart, onInputDelta, onInputAvailable, onOutput) now fire correctly during agent execution for tools created via createTool(). Previously these hooks were silently ignored. Affected: createTool, Tool, CoreToolBuilder.build, CoreTool. (#13708)
Fixed an issue where sub-agent messages inside a workflow tool would corrupt the parent agent's memory context. When an agent calls a workflow as a tool and the workflow runs sub-agents with their own memory threads, the parent's thread identity on the shared request context is now correctly saved before the workflow executes and restored afterward, preventing messages from being written to the wrong thread. (#13637)
Fix workspace tool output truncation to handle tokenizer special tokens (#13725)
Added a warning when a LocalFilesystem mount uses contained: false, alerting users to path resolution issues in mount-based workspaces. Use contained: true (default) or allowedPaths to allow specific host paths. (#13474)
Fixed harness handling for observational memory failures so streams stop immediately when OM reports a failed run or buffering cycle. (#13563)
The harness now emits the existing OM failure event (om_observation_failed, om_reflection_failed, or om_buffering_failed), emits a top-level error with OM context, and aborts the active stream. This prevents normal assistant output from continuing after an OM model failure.
Fixed subagents being unable to access files outside the project root. Subagents now inherit both user-approved sandbox paths and skill paths (e.g. ~/.claude/skills) from the parent agent. (#13700)
Fixed agent-as-tools schema generation so Gemini accepts tool definitions for suspend/resume flows. (#13715)
This prevents schema validation failures when resumeData is present.
Fixed tool approval resume failing when Agent is used without an explicit Mastra instance. The Harness now creates an internal Mastra instance with storage and registers it on mode agents, ensuring workflow snapshots persist and load correctly. Also fixed requestContext serialization using toJSON() to prevent circular reference errors during snapshot persistence. (#13519)
Fixed spawn error handling in LocalSandbox by switching to execa. Previously, spawning a process with an invalid working directory or missing command could crash with an unhandled Node.js exception. Now returns descriptive error messages instead. Also fixed timeout handling to properly kill the entire process group for compound commands. (#13734)
HTTP request logging can now be configured in detail via apiReqLogs in the server config. The new HttpLoggingConfig type is exported from @mastra/core/server. (#11907)
import type { HttpLoggingConfig } from '@mastra/core/server';
const loggingConfig: HttpLoggingConfig = {
enabled: true,
level: 'info',
excludePaths: ['/health', '/metrics'],
includeHeaders: true,
includeQueryParams: true,
redactHeaders: ['authorization', 'cookie'],
};
Remove internal processes field from sandbox provider options (#13597)
The processes field is no longer exposed in constructor options for E2B, Daytona, and Blaxel sandbox providers. This field is managed internally and was not intended to be user-configurable.
Fixed abort signal propagation in agent networks. When using abortSignal with agent.network(), the signal now correctly prevents tool execution when abort fires during routing, and no longer saves partial results to memory when sub-agents, tools, or workflows are aborted. (#13491)
Fixed Memory.recall() to include pagination metadata (total, page, perPage, hasMore) in its response, ensuring consistent pagination regardless of whether agentId is provided. Fixes #13277 (#13278)
Fixed harness getTokenUsage() returning zeros when using AI SDK v5/v6. The token usage extraction now correctly reads both inputTokens/outputTokens (v5/v6) and promptTokens/completionTokens (v4) field names from the usage object. (#13622)
Model pack selection is now more consistent and reliable in mastracode. (#13512)
/models is now the single command for choosing and managing model packs.varied.Added support for reading resource IDs from Harness. (#13690)
You can now get the default resource ID and list known resource IDs from stored threads.
const defaultId = harness.getDefaultResourceId();
const knownIds = await harness.getKnownResourceIds();
chore(harness): Update harness sub-agent instructions type to be dynamic (#13706)
Added MastraMessagePart to the public type exports of @mastra/core/agent, allowing it to be imported directly in downstream packages. (#13297)
Added deleteThread({ threadId }) method to the Harness class for deleting threads and their messages from storage. Releases the thread lock and clears the active thread when deleting the current thread. Emits a thread_deleted event. (#13625)
Fixed tilde (~) paths not expanding to the home directory in LocalFilesystem and LocalSandbox. Paths like ~/my-project were silently treated as relative paths, creating a literal ~/ directory instead of resolving to $HOME. This affects basePath, allowedPaths, setAllowedPaths(), all file operations in LocalFilesystem, and workingDirectory in LocalSandbox. (#13739)
Switched Mastra Code to workspace tools and enabled LSP by default (#13437)
old_string/new_string)Fixed tilde paths (~/foo) in contained LocalFilesystem silently writing to the wrong location. Previously, ~/foo would expand and then nest under basePath (e.g. basePath/home/user/foo). Tilde paths are now treated as real absolute paths, and throw PermissionError when the expanded path is outside basePath and allowedPaths. (#13741)
504fc8b, f9c150b, 88de7e8, edee4b3, 9311c17, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 359d687, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9e77e8f, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 56f2018, 85664e9, bc79650, 9257d01, 9311c17, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Fixed message history and semantic recall persistence after AI SDK streams finish. (#13297)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Expanded @mastra/auth-better-auth to implement the new auth interfaces (IUserProvider, ISessionProvider, ICredentialsProvider) from @mastra/core/auth. Adds support for username/password credential flows alongside the existing token-based authentication. (#13163)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Added @mastra/auth-cloud — a new auth provider for Mastra Cloud with PKCE OAuth flow, session management, and role-based access control. (#13163)
import { MastraCloudAuthProvider, MastraRBACCloud } from '@mastra/auth-cloud';
const mastra = new Mastra({
server: {
auth: new MastraCloudAuthProvider({
appId: process.env.MASTRA_APP_ID!,
apiKey: process.env.MASTRA_API_KEY!,
}),
rbac: new MastraRBACCloud({
appId: process.env.MASTRA_APP_ID!,
apiKey: process.env.MASTRA_API_KEY!,
}),
},
});
Handles the full OAuth lifecycle including login URL generation, PKCE challenge/verification, callback handling, and session cookie management.
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Added @mastra/auth-studio — an auth provider for deployed Mastra Studio instances that proxies authentication through the Mastra shared API. (#13163)
Deployed instances need no secrets — all WorkOS authentication is handled by the shared API. The package provides SSO login/callback flows, session management via sealed cookies, RBAC with organization-scoped permissions, and automatic forced account picker on deploy logins.
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Added full auth provider to @mastra/auth-workos with SSO, RBAC, SCIM directory sync, and admin portal support. (#13163)
import { MastraAuthWorkos, MastraRBACWorkos } from '@mastra/auth-workos';
const mastra = new Mastra({
server: {
auth: new MastraAuthWorkos({
apiKey: process.env.WORKOS_API_KEY,
clientId: process.env.WORKOS_CLIENT_ID,
}),
rbac: new MastraRBACWorkos({
apiKey: process.env.WORKOS_API_KEY,
clientId: process.env.WORKOS_CLIENT_ID,
roleMapping: {
admin: ['*'],
member: ['agents:read', 'workflows:*'],
},
}),
},
});
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Abort signal support in sandbox commands (#13597)
abortSignal in command optionsAdded background process management support for Blaxel sandboxes. Agents can now spawn, monitor, and kill long-running processes using the standard ProcessHandle interface. (79177b1)
Example usage:
const sandbox = new BlaxelSandbox({ timeout: '5m' });
const workspace = new Workspace({ sandbox });
// Process manager is available via sandbox.processes
const handle = await sandbox.processes.spawn('python server.py');
// Monitor output
handle.onStdout(data => console.log(data));
// Check status
const info = await sandbox.processes.list();
// Kill when done
await handle.kill();
Note: Process stdin is not supported in Blaxel sandboxes.
Additional improvements:
Fixed command timeouts in Blaxel sandboxes so long-running commands now respect configured limits. (#13520)
Changed the default Blaxel image to blaxel/ts-app:latest (Debian-based), which supports both S3 and GCS mounts out of the box.
Added distro detection for mount scripts so S3 mounts work on Alpine-based images (e.g. blaxel/node:latest) via apk, and GCS mounts give a clear error on Alpine since gcsfuse is unavailable.
Removed working directory from sandbox instructions to avoid breaking prompt caching.
Remove internal processes field from sandbox provider options (#13597)
The processes field is no longer exposed in constructor options for E2B, Daytona, and Blaxel sandbox providers. This field is managed internally and was not intended to be user-configurable.
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 6a72884, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
updateWorkflowResults and updateWorkflowState now throw a not-implemented error. This storage backend does not support concurrent workflow updates. (#12575)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Added getFullUrl helper method for constructing auth redirect URLs and exported the AuthCapabilities type. HTTP retries now skip 4xx client errors to avoid retrying authentication failures. (#13163)
Fixed CMS features (Create an agent button, clone, edit, create scorer) not appearing in built output. The build command now writes package metadata so the studio can detect installed Mastra packages at runtime. (#13163)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
updateWorkflowResults and updateWorkflowState now throw a not-implemented error. This storage backend does not support concurrent workflow updates. (#12575)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
updateWorkflowResults and updateWorkflowState now throw a not-implemented error. This storage backend does not support concurrent workflow updates. (#12575)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
updateWorkflowResults and updateWorkflowState now throw a not-implemented error. This storage backend does not support concurrent workflow updates. (#12575)
fix: use existing indexes for queryTable operations instead of full table scans (#13630)
The queryTable handler in the Convex storage mutation now automatically
selects the best matching index based on equality filters. Previously, all
queryTable operations performed a full table scan (up to 10,000 documents)
and filtered in JavaScript, which hit Convex's 16MB/32K document read limit
when enough records accumulated across threads.
Now, when equality filters are provided (e.g., thread_id for message queries
or resourceId for thread queries), the handler matches them against the
existing schema indexes (by_thread, by_thread_created, by_resource, etc.)
and uses .withIndex() for efficient indexed queries.
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 6a72884, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, e947652, 3c6ef79, 9257d01, ec248f6]:
Add DaytonaSandbox workspace provider — Daytona cloud sandbox integration for Mastra workspaces, implementing the WorkspaceSandbox interface with support for command execution, environment variables, resource configuration, snapshots, and Daytona volumes. (#13112)
Basic usage
import { Workspace } from '@mastra/core/workspace';
import { DaytonaSandbox } from '@mastra/daytona';
const sandbox = new DaytonaSandbox({
id: 'my-sandbox',
env: { NODE_ENV: 'production' },
});
const workspace = new Workspace({ sandbox });
await workspace.init();
const result = await workspace.sandbox.executeCommand('echo', ['Hello!']);
console.log(result.stdout); // "Hello!"
await workspace.destroy();
Added S3 and GCS cloud filesystem mounting support via FUSE (s3fs-fuse, gcsfuse). Daytona sandboxes can now mount cloud storage as local directories, matching the mount capabilities of E2B and Blaxel providers. (#13544)
New methods:
mount(filesystem, mountPath) — Mount an S3 or GCS filesystem at a path in the sandboxunmount(mountPath) — Unmount a previously mounted filesystemWhat changed:
Usage:
import { Workspace } from '@mastra/core/workspace';
import { S3Filesystem } from '@mastra/s3';
import { DaytonaSandbox } from '@mastra/daytona';
const workspace = new Workspace({
mounts: {
'/data': new S3Filesystem({
bucket: 'my-bucket',
region: 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
}),
},
sandbox: new DaytonaSandbox(),
});
Remove internal processes field from sandbox provider options (#13597)
The processes field is no longer exposed in constructor options for E2B, Daytona, and Blaxel sandbox providers. This field is managed internally and was not intended to be user-configurable.
Improved S3/GCS FUSE mounting reliability and sandbox reconnection. (#13543)
Mounting improvements
mount --move fallback when standard FUSE unmount fails on stuck mountsstop() now unmounts all filesystems before stopping the sandboxReconnection improvements
findExistingSandbox now looks up sandboxes by name first (works for stopped sandboxes), then falls back to label searchSandbox instructions no longer include a working directory path, keeping instructions stable across sessions. (#13520)
Updated dependencies [504fc8b, f9c150b, 88de7e8, edee4b3, 3790c75, e7a235b, d51d298, 6dbeeb9, d5f0d8d, 09c3b18, b896379, 85c84eb, a89272a, ee9c8df, 77b4a25, 276246e, 08ecfdb, d5f628c, 524c0f3, c18a0e9, 4bd21ea, 115a7a4, 22a48ae, 3c6ef79, 9311c17, 7edf78f, 1c4221c, d25b9ea, fe1ce5c, b03c0e0, 0a8366b, 85664e9, bc79650, 9257d01, 3a3a59e, 3108d4e, 0c33b2c, 191e5bd, f77cd94, e8135c7, daca48f, 257d14f, 352f25d, 93477d0, 31c78b3, 0bc0720, 36516ac, [`e947
A new supervisor pattern enables orchestrating multiple agents via stream() and generate(), with delegation hooks, iteration monitoring, completion scoring, memory isolation, tool approval propagation, context filtering, and a bail mechanism.
queryVector)Vector querying now supports metadata-only retrieval by making queryVector optional (with at least one of queryVector or filter required). @mastra/pg’s PgVector.query() explicitly supports filter-only queries, while other vector stores now throw a clear MastraError when metadata-only queries aren’t supported.
runEvals Target OptionsrunEvals adds targetOptions to forward execution/run options into agent.generate() or workflow.run.start(), plus per-item startOptions for workflow-specific overrides (e.g., initialState) on each eval datum.
Workspace edit tools (write_file, edit_file, ast_edit) can now surface Language Server Protocol diagnostics immediately after edits (TypeScript, Python/Pyright, Go/gopls, Rust/rust-analyzer, ESLint), helping catch type/lint errors before the next tool call.
@mastra/blaxel adds a Blaxel cloud sandbox provider, expanding deployment/runtime options for executing workspace tooling in a managed environment.
Make queryVector optional in the QueryVectorParams interface to support metadata-only queries. At least one of queryVector or filter must be provided. Not all vector store backends support metadata-only queries — check your store's documentation for details. (#13286)
Also fixes documentation where the query() parameter was incorrectly named vector instead of queryVector.
Added targetOptions parameter to runEvals that is forwarded directly to agent.generate() (modern path) or workflow.run.start(). Also added per-item startOptions field to RunEvalsDataItem for per-item workflow options like initialState. (#13366)
New feature: targetOptions
Pass agent execution options (e.g. maxSteps, modelSettings, instructions) through to agent.generate(), or workflow run options (e.g. perStep, outputOptions) through to workflow.run.start():
// Agent - pass modelSettings or maxSteps
await runEvals({
data,
scorers,
target: myAgent,
targetOptions: { maxSteps: 5, modelSettings: { temperature: 0 } },
});
// Workflow - pass run options
await runEvals({
data,
scorers,
target: myWorkflow,
targetOptions: { perStep: true },
});
New feature: per-item startOptions
Supply per-item workflow options (e.g. initialState) directly on each data item:
await runEvals({
data: [
{ input: { query: 'hello' }, startOptions: { initialState: { counter: 1 } } },
{ input: { query: 'world' }, startOptions: { initialState: { counter: 2 } } },
],
scorers,
target: myWorkflow,
});
Per-item startOptions take precedence over global targetOptions for the same key. Runeval-managed options (scorers, returnScorerData, requestContext) cannot be overridden via targetOptions.
Add supervisor pattern for multi-agent coordination using stream() and generate(). Includes delegation hooks, iteration monitoring, completion scoring, memory isolation, tool approval propagation, context filtering, and bail mechanism. (#13323)
Add LSP diagnostics to workspace edit tools (#13441)
Language Server Protocol (LSP) diagnostics now appear after edits made with write_file, edit_file, and ast_edit. Seeing type and lint errors immediately helps catch issues before the next tool call. Edits still work without diagnostics when language servers are not installed.
Supports TypeScript, Python (Pyright), Go (gopls), Rust (rust-analyzer), and ESLint.
Example
Before:
const workspace = new Workspace({ sandbox, filesystem });
After:
const workspace = new Workspace({ sandbox, filesystem, lsp: true });
Propagate tripwire's that are thrown from a nested workflow. (#13502)
Added isProviderDefinedTool helper to detect provider-defined AI SDK tools (e.g. google.tools.googleSearch(), openai.tools.webSearch()) for proper schema handling during serialization. (#13507)
Fixed ModelRouterEmbeddingModel.doEmbed() crashing with TypeError: result.warnings is not iterable when used with AI SDK v6's embedMany. The result now always includes a warnings array, ensuring forward compatibility across AI SDK versions. (#13369)
Fixed build error in ModelRouterEmbeddingModel.doEmbed() caused by warnings not existing on the return type. (#13461)
Fixed Harness.createThread() defaulting the thread title to "New Thread" which prevented generateTitle from working (see #13391). Threads created without an explicit title now have an empty string title, allowing the agent's title generation to produce a title from the first user message. (#13393)
Prevent unknown model IDs from being sorted to the front in reorderModels(). Models not present in the modelIds parameter are now moved to the end of the array. Fixes #13410. (#13445)
Include traceId on scores generated during experiment runs to restore traceability of experiment results (#13464)
Fixed skill-read-reference (and getReference, getScript, getAsset in WorkspaceSkillsImpl) to resolve file paths relative to the skill root instead of hardcoded subdirectories (references/, scripts/, assets/). (#13363)
Previously, calling skill-read-reference with referencePath: "docs/schema.md" would silently fail because it resolved to <skill>/references/docs/schema.md instead of <skill>/docs/schema.md. Now all paths like references/colors.md, docs/schema.md, and ./config.json resolve correctly relative to the skill root. Path traversal attacks (e.g. ../../etc/passwd) are still blocked.
Fixed workspace listing to show whether each workspace is global or agent-owned. (#13468) Agent-owned workspaces now include the owning agent's ID and name so clients can distinguish them from global workspaces.
Fixed Observational Memory not working with AI SDK v4 models (legacy path). The legacy stream/generate path now calls processInputStep, enabling processors like Observational Memory to inject conversation history and observations. (#13358)
Added resolveWorkspace() so callers can access a dynamic workspace before the first request. (#13457)
Fixed abortSignal not stopping LLM generation or preventing memory persistence. When aborting a stream (e.g., client disconnect), the LLM response no longer continues processing in the background and partial/full responses are no longer saved to memory. Fixes #13117. (#13206)
Fixed observation activation to always preserve a minimum amount of context. Previously, swapping buffered observation chunks could unexpectedly drop the context window to near-zero tokens. (#13476)
Fixed a crash where the Node.js process would terminate with an unhandled TypeError when an LLM stream encountered an error. The ReadableStreamDefaultController would throw "Controller is already closed" when chunks were enqueued after a downstream consumer cancelled or terminated the stream. All controller.enqueue(), controller.close(), and controller.error() calls now check if the controller is still open before attempting operations. (https://github.com/mastra-ai/mastra/issues/13107) (#13206)
Updated dependencies [8d14a59]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, cb9f921, 1b6f651, 72df4a8]:
Fixed withMastra() re-persisting prior message history on later turns. When using generateText() multiple times on the same thread, previously stored messages were duplicated in storage. (fixes #13438) (#13459)
Suppress completion feedback display when suppressFeedback is set (#13323)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Adds Blaxel cloud sandbox provider (#13015)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 8d14a59, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, ddf8e5c, e622f1d, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, ae55343, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, ddf8e5c, e622f1d, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, ae55343, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, ddf8e5c, e622f1d, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, ae55343, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, ddf8e5c, e622f1d, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, ae55343, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, ddf8e5c, e622f1d, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, ae55343, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Fixed observation activation to always preserve a minimum amount of context. Previously, swapping buffered observation chunks could unexpectedly drop the context window to near-zero tokens. (#13476)
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, cb9f921, 1b6f651, c290cec, 4852a84, 72df4a8]:
Fixed MCP tool results returning empty {} when the server does not include structuredContent in responses (e.g. FastMCP, older MCP protocol versions). The client now extracts the actual result from the content array instead of returning the raw protocol envelope, which previously caused output schema validation to strip all properties. (#13469)
Fix MCP client connect() creating duplicate connections when called concurrently. This could leak stdio child processes or HTTP sessions. Fixes #13411. (#13444)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, b8621e2, c290cec, f03e794, aa4a5ae, de3f584, 74ae019, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Fixed observational memory buffering to preserve more context and activate at the right time. (#13476)
blockAfter behavior: values below 100 are treated as multipliers (e.g. 1.2 = 1.2× threshold), values ≥ 100 as absolute token counts.Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 8d14a59, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Fixed observation activation to always preserve a minimum amount of context. Previously, swapping buffered observation chunks could unexpectedly drop the context window to near-zero tokens. (#13476)
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, cb9f921, 1b6f651, c290cec, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
PgVector.query() now supports querying by metadata filters alone without providing a query vector — useful when you need to retrieve records by metadata without performing similarity search. (#13286)
Before (queryVector was required):
const results = await pgVector.query({
indexName: 'my-index',
queryVector: [0.1, 0.2, ...],
filter: { category: 'docs' },
});
After (metadata-only query):
const results = await pgVector.query({
indexName: 'my-index',
filter: { category: 'docs' },
});
// Returns matching records with score: 0 (no similarity ranking)
At least one of queryVector or filter must be provided. When queryVector is omitted, results are returned with score: 0 since no similarity computation is performed.
Set REPLICA IDENTITY USING INDEX on the mastra_workflow_snapshot table so PostgreSQL logical replication can track row updates. The table only has a UNIQUE constraint with no PRIMARY KEY, which caused "cannot update table because it does not have a replica identity and publishes updates" errors when logical replication was enabled. Fixes #13097. (#13178)
Fixed observation activation to always preserve a minimum amount of context. Previously, swapping buffered observation chunks could unexpectedly drop the context window to near-zero tokens. (#13476)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Target type and target ID fields in the experiment dialog are now searchable dropdowns. Scorers can be selected via a multi-select dropdown. All three dropdowns share a consistent searchable style and visual behavior. (#13463)
Show completion result UI for supervisor pattern delegations. Previously, completion check results were only displayed when metadata.mode === 'network'. Now they display for any response that includes completionResult metadata, supporting the new supervisor pattern. (#13323)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, b8f636a, e622f1d, 8d14a59, 114e7c1, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 114e7c1, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Improved token-based chunking performance in token and semantic-markdown strategies. Markdown knowledge bases now chunk significantly faster with lower tokenization overhead. (#13495)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Added completionResult to MastraUIMessageMetadata (#13323)
Updated dependencies:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
ZodNull throwing "does not support zod type: ZodNull" for Anthropic and OpenAI reasoning models. MCP tools with nullable properties in their JSON Schema produce z.null() which was unhandled by these provider compat layers. (#13496)Fixed the skill reference endpoint (GET /workspaces/:workspaceId/skills/:skillName/references/:referencePath) returning 404 for valid reference files. (#13506)
Fixed GET /api/workspaces returning source: 'mastra' for all workspaces. Agent workspaces now correctly return source: 'agent' with agentId and agentName populated. (#13468)
Fixed /tools API endpoint crashing with provider-defined tools (e.g. google.tools.googleSearch(), openai.tools.webSearch()). These tools have a lazy inputSchema that is not a Zod schema, which caused zodToJsonSchema to throw "Cannot read properties of undefined (reading 'typeName')". (#13507)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Add a clear runtime error when queryVector is omitted for vector stores that require a vector for queries. Previously, omitting queryVector would produce confusing SDK-level errors; now each store throws a structured MastraError with ErrorCategory.USER explaining that metadata-only queries are not supported by that backend. (#13286)
Updated dependencies [df170fd, ae55343, c290cec, f03e794, aa4a5ae, de3f584, d3fb010, 702ee1c, f495051, e622f1d, 861f111, 00f43e8, 1b6f651, 96a1702, cb9f921, 114e7c1, 1b6f651, 72df4a8]:
Workspaces now support spawning and managing long-running background processes (via SandboxProcessManager / ProcessHandle), with new tools like execute_command (background: true), get_process_output, and kill_process plus improved streaming terminal-style UI.
Workspace.setToolsConfig()You can dynamically enable/disable tools at runtime on an existing workspace instance (including re-enabling all tools by passing undefined), enabling safer modes like plan/read-only without recreating the workspace.
Core adds Harness.getObservationalMemoryRecord() for public access to the full OM record for the current thread, while @mastra/memory fixes major OM stability issues (shared tokenizer to prevent OOM/memory leaks, plus PostgreSQL deadlock fixes and clearer errors when threadId is missing).
Added getObservationalMemoryRecord() method to the Harness class. Fixes #13392. (#13395)
This provides public access to the full ObservationalMemoryRecord for the current thread, including activeObservations, generationCount, and observationTokenCount. Previously, accessing raw observation text required bypassing the Harness abstraction by reaching into private storage internals.
const record = await harness.getObservationalMemoryRecord();
if (record) {
console.log(record.activeObservations);
}
Added Workspace.setToolsConfig() method for dynamically updating per-tool configuration at runtime without recreating the workspace instance. Passing undefined re-enables all tools. (#13439)
const workspace = new Workspace({ filesystem, sandbox });
// Disable write tools (e.g., in plan/read-only mode)
workspace.setToolsConfig({
mastra_workspace_write_file: { enabled: false },
mastra_workspace_edit_file: { enabled: false },
});
// Re-enable all tools
workspace.setToolsConfig(undefined);
Added HarnessDisplayState so any UI can read a single state snapshot instead of handling 35+ individual events. (#13427)
Why: Previously, every UI (TUI, web, desktop) had to subscribe to dozens of granular Harness events and independently reconstruct what to display. This led to duplicated state tracking and inconsistencies across UI implementations. Now the Harness maintains a single canonical display state that any UI can read.
Before: UIs subscribed to raw events and built up display state locally:
harness.subscribe((event) => {
if (event.type === 'agent_start') localState.isRunning = true;
if (event.type === 'agent_end') localState.isRunning = false;
if (event.type === 'tool_start') localState.tools.set(event.toolCallId, ...);
// ... 30+ more event types to handle
});
After: UIs read a single snapshot from the Harness:
import type { HarnessDisplayState } from '@mastra/core/harness';
harness.subscribe(event => {
const ds: HarnessDisplayState = harness.getDisplayState();
// ds.isRunning, ds.tokenUsage, ds.omProgress, ds.activeTools, etc.
renderUI(ds);
});
Workspace instruction improvements (#13304)
Workspace.getInstructions(): agents now receive accurate workspace context that distinguishes sandbox-accessible paths from workspace-only paths.WorkspaceInstructionsProcessor: workspace context is injected directly into the agent system message instead of embedded in tool descriptions.Workspace.getPathContext() in favour of getInstructions().Added instructions option to LocalFilesystem and LocalSandbox. Pass a string to fully replace default instructions, or a function to extend them with access to the current requestContext for per-request customization (e.g. by tenant or locale).
const filesystem = new LocalFilesystem({
basePath: './workspace',
instructions: ({ defaultInstructions, requestContext }) => {
const locale = requestContext?.get('locale') ?? 'en';
return `${defaultInstructions}\nLocale: ${locale}`;
},
});
Added background process management to workspace sandboxes. (#13293)
You can now spawn, monitor, and manage long-running background processes (dev servers, watchers, REPLs) inside sandbox environments.
// Spawn a background process
const handle = await sandbox.processes.spawn('node server.js');
// Stream output and wait for exit
const result = await handle.wait({
onStdout: data => console.log(data),
});
// List and manage running processes
const procs = await sandbox.processes.list();
await sandbox.processes.kill(handle.pid);
SandboxProcessManager abstract base class with spawn(), list(), get(pid), kill(pid)ProcessHandle base class with stdout/stderr accumulation, streaming callbacks, and wait()LocalProcessManager implementation wrapping Node.js child_processhandle.reader / handle.writerexecuteCommand implementation built on process manager (spawn + wait)Added workspace tools for background process management and improved sandbox execution UI. (#13309)
execute_command now supports background: true to spawn long-running processes and return a PIDget_process_output tool to check output/status of background processes (supports wait to block until exit)kill_process tool to terminate background processesFixed agents-as-tools failing with OpenAI when using the model router. The auto-injected resumeData field (from z.any()) produced a JSON Schema without a type key, which OpenAI rejects. Tool schemas are now post-processed to ensure all properties have valid type information. (#13326)
Fixed stopWhen callback receiving empty toolResults on steps. step.toolResults now correctly reflects the tool results present in step.content. (#13319)
Added hasJudge metadata to scorer records so the studio can distinguish code-based scorers (e.g., textual-difference, content-similarity) from LLM-based scorers. This metadata is now included in all four score-saving paths: runEvals, scorer hooks, trace scoring, and dataset experiments. (#13386)
Fixed a bug where custom output processors could not emit stream events during final output processing. The writer object was always undefined when passed to output processors in the finish phase, preventing use cases like streaming moderation updates or custom UI events back to the client. (#13454)
Added per-file write locking to workspace tools (edit_file, write_file, ast_edit, delete). Concurrent tool calls targeting the same file are now serialized, preventing race conditions where parallel edits could silently overwrite each other. (#13302)
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
Fixed getInstructions() to report sandbox-level facts only (working directory, provider type) instead of counting all mount entries regardless of state. Added instructions option to E2BSandbox to override or extend default instructions. (#13304)
Added E2BProcessManager for background process management in E2B cloud sandboxes. (#13293)
Wraps E2B SDK's commands.run() with background: true and commands.connect() for reconnection. Processes spawned in E2B sandboxes are automatically cleaned up on stop() and destroy().
Bumps @mastra/core peer dependency to >=1.7.0-0 (requires SandboxProcessManager from core).
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
Fixed non-deterministic query ordering by adding secondary sort on id for dataset and dataset item queries. (#13399)
Updated dependencies [24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
3af89bb, 551dc24, e8afc44, 24284ff, f5097cc, 71e237f, c2e02f1, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
Fixed memory leak in Observational Memory (#13425)
Fixed several memory management issues that could cause OOM crashes in long-running processes with Observational Memory enabled:
cleanupStaticMaps.Fixed PostgreSQL deadlock when parallel agents with different threadIds share the same resourceId while using Observational Memory. Thread scope now requires a valid threadId and throws a clear error if one is missing. Also fixed the database lock ordering in synchronous observation to prevent lock inversions. (#13436)
Updated dependencies [24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
551dc24, e8afc44, 24284ff, f5097cc, 71e237f, c2e02f1, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
Fixed non-deterministic query ordering by adding secondary sort on id for dataset and dataset item queries. (#13399)
Updated dependencies [24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
Improved comparison selection behavior: selecting a third item now replaces the most recent selection instead of being blocked. Applies to dataset version, item version, and dataset item comparison flows. (#13406)
Improved the score dialog to show "N/A" with an explanation instead of "null" for empty scorer fields. Code-based scorers show "N/A — code-based scorer does not use prompts" and LLM scorers with unconfigured steps show "N/A — step not configured". Detection uses the hasJudge metadata flag with a heuristic fallback for older data. (#13386)
Added workspace tools for background process management and improved sandbox execution UI. (#13309)
execute_command now supports background: true to spawn long-running processes and return a PIDget_process_output tool to check output/status of background processes (supports wait to block until exit)kill_process tool to terminate background processesUpdated dependencies [24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
zeroentropy@0.1.0-alpha.7 ↗︎ (from 0.1.0-alpha.6, in dependencies)24284ff, f5097cc, 71e237f, 13a291e, 397af5a, d4701f7, 2b40831, 6184727, 0c338b8, 6f6385b, 14aba61, dd9dd1c]:
2b40831]:
mastra_workspace_ast_edit)A new AST edit tool enables intelligent code transformations (rename identifiers, add/remove/merge imports, pattern-based replacements with metavariables) and is automatically available when @ast-grep/napi is installed, enabling robust refactors beyond string-based edits.
Tool renderers now stream argument previews in real time (including diffs for edits and streamed file content for writes) via partial JSON parsing, and task_write/task_check are now built-in Harness tools automatically injected into agent calls for structured task tracking.
Observational Memory now preserves suggestedContinuation and currentTask across activations (with storage adapter support), improving conversational continuity when the message window shrinks; activation/priority handling is improved to better hit retention targets and avoid runaway observer output.
Added AST edit tool (workspace_ast_edit) for intelligent code transformations using AST analysis. Supports renaming identifiers, adding/removing/merging imports, and pattern-based find-and-replace with metavariable substitution. Automatically available when @ast-grep/napi is installed in the project. (#13233)
Example:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: '/my/project' }),
});
const tools = createWorkspaceTools(workspace);
// Rename all occurrences of an identifier
await tools['mastra_workspace_ast_edit'].execute({
path: '/src/utils.ts',
transform: 'rename',
targetName: 'oldName',
newName: 'newName',
});
// Add an import (merges into existing imports from the same module)
await tools['mastra_workspace_ast_edit'].execute({
path: '/src/app.ts',
transform: 'add-import',
importSpec: { module: 'react', names: ['useState', 'useEffect'] },
});
// Pattern-based replacement with metavariables
await tools['mastra_workspace_ast_edit'].execute({
path: '/src/app.ts',
pattern: 'console.log($ARG)',
replacement: 'logger.debug($ARG)',
});
Added streaming tool argument previews across all tool renderers. Tool names, file paths, and commands now appear immediately as the model generates them, rather than waiting for the complete tool call. (#13328)
old_str and new_str are available, even before the tool result arrivesAll tools use partial JSON parsing to progressively display argument information. This is enabled automatically for all Harness-based agents — no configuration required.
Added optional threadLock callbacks to HarnessConfig for preventing concurrent thread access across processes. The Harness calls acquire/release during selectOrCreateThread, createThread, and switchThread when configured. Locking is opt-in — when threadLock is not provided, behavior is unchanged. (#13334)
const harness = new Harness({
id: 'my-harness',
storage: myStore,
modes: [{ id: 'default', agent: myAgent }],
threadLock: {
acquire: threadId => acquireThreadLock(threadId),
release: threadId => releaseThreadLock(threadId),
},
});
Refactored all Harness class methods to accept object parameters instead of positional arguments, and standardized method naming. (#13353)
Why: Positional arguments make call sites harder to read, especially for methods with optional middle parameters or multiple string arguments. Object parameters are self-documenting and easier to extend without breaking changes.
list prefix (listModes, listAvailableModels, listMessages, listMessagesForThread)persistThreadSetting → setThreadSettingresolveToolApprovalDecision → respondToToolApproval (consistent with respondToQuestion / respondToPlanApproval)setPermissionCategory → setPermissionForCategorysetPermissionTool → setPermissionForToolBefore:
await harness.switchMode('build');
await harness.sendMessage('Hello', { images });
const modes = harness.getModes();
const models = await harness.getAvailableModels();
harness.resolveToolApprovalDecision('approve');
After:
await harness.switchMode({ modeId: 'build' });
await harness.sendMessage({ content: 'Hello', images });
const modes = harness.listModes();
const models = await harness.listAvailableModels();
harness.respondToToolApproval({ decision: 'approve' });
The HarnessRequestContext interface methods (registerQuestion, registerPlanApproval, getSubagentModelId) are also updated to use object parameters.
Added task_write and task_check as built-in Harness tools. These tools are automatically injected into every agent call, allowing agents to track structured task lists without manual tool registration. (#13344)
// Agents can call task_write to create/update a task list
await tools['task_write'].execute({
tasks: [
{ content: 'Fix authentication bug', status: 'in_progress', activeForm: 'Fixing authentication bug' },
{ content: 'Add unit tests', status: 'pending', activeForm: 'Adding unit tests' },
],
});
// Agents can call task_check to verify all tasks are complete before finishing
await tools['task_check'].execute({});
// Returns: { completed: 1, inProgress: 0, pending: 1, allDone: false, incomplete: [...] }
Fixed duplicate Vercel AI Gateway configuration that could cause incorrect API key resolution. Removed a redundant override that conflicted with the upstream models.dev registry. (#13291)
Fixed Vercel AI Gateway failing when using the model router string format (e.g. vercel/openai/gpt-oss-120b). The provider registry was overriding createGateway's base URL with an incorrect value, causing API requests to hit the wrong endpoint. Removed the URL override so the AI SDK uses its own correct default. Closes #13280. (#13287)
Fixed recursive schema warnings for processor graph entries by unrolling to a fixed depth of 3 levels, matching the existing rule group pattern (#13292)
Fixed Observational Memory status not updating during conversations. The harness was missing streaming handlers for OM data chunks (status, observation start/end, buffering, activation), so the TUI never received real-time OM progress updates. Also added switchObserverModel and switchReflectorModel methods so changing OM models properly emits events to subscribers. (#13330)
Fixed thread resuming in git worktrees. Previously, starting mastracode in a new worktree would resume a thread from another worktree of the same repo. Threads are now auto-tagged with the project path and filtered on resume so each worktree gets its own thread scope. (#13343)
Fixed a crash where the Node.js process would terminate with an unhandled TypeError when an LLM stream encountered an error. The ReadableStreamDefaultController would throw "Controller is already closed" when chunks were enqueued after a downstream consumer cancelled or terminated the stream. All controller.enqueue(), controller.close(), and controller.error() calls now check if the controller is still open before attempting operations. (https://github.com/mastra-ai/mastra/issues/13107) (#13142)
Added suggestedContinuation and currentTask fields to the in-memory storage adapter's Observational Memory activation result, aligning it with the persistent storage implementations. (#13354)
Fixed provider-executed tools (e.g. Anthropic web_search) causing stream bail when called in parallel with regular tools. The tool-call-step now provides a fallback result for provider-executed tools whose output was not propagated, preventing the mapping step from misidentifying them as pending HITL interactions. Fixes #13125. (#13126)
Updated dependencies [7184d87]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
Added MCP server table and CRUD operations to storage adapters, enabling MCP server configurations to be persisted alongside agents and workflows. (#13357)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 7184d87, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
Added MCP server table and CRUD operations to storage adapters, enabling MCP server configurations to be persisted alongside agents and workflows. (#13357)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
0d9efb4, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 940163f, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 940163f, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 940163f, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 940163f, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 940163f, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
Storage adapters now return suggestedContinuation and currentTask fields on Observational Memory activation, enabling agents to maintain conversational context across activation boundaries. (#13357)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
5c70aeb, 0d9efb4, 5caa13d, 270dd16, 940163f, 5c70aeb, b260123, 47892c8, 45bb78b, 5c70aeb, 70eef84, d84e52d, 24b80af, 608e156, 78d1c80, 2b2e157, 78d1c80, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
Improved conversational continuity when the message window shrinks during Observational Memory activation. The agent now preserves its suggested next response and current task across activation, so it maintains context instead of losing track of the conversation. (#13354)
Also improved the Observer to capture user messages more faithfully, reduce repetitive observations, and treat the most recent user message as the highest-priority signal.
Improved Observational Memory priority handling. User messages and task completions are now always treated as high priority, ensuring the observer captures the most relevant context during conversations. (#13329)
Improved Observational Memory activation to preserve more usable context after activation. Previously, activation could leave the agent with too much or too little context depending on how chunks aligned with the retention target. (#13305)
blockAfter, activation now aggressively reduces context to unblock the conversationbufferActivation now accepts absolute token values (>= 1000) in addition to ratios (0–1), giving more precise control over when activation triggersObservations no longer inflate token counts from degenerate LLM output. Runaway or repetitive observer/reflector output is automatically detected and retried, preventing excessive context usage after activation. (#13354)
Updated dependencies [0d9efb4, 7184d87, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
Storage adapters now return suggestedContinuation and currentTask fields on Observational Memory activation, enabling agents to maintain conversational context across activation boundaries. (#13357)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
Fixed telemetry spans being silently dropped when the default exporter was used. The exporter now holds spans in memory until initialization completes, ensuring all spans are propagated to your tracing backend. (#12936)
Fixed keysToStrip.has is not a function crash in deepClean() when bundlers transform new Set([...]) into a plain object or array. This affected agents with memory deployed to Mastra Cloud. (#13322)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
5c70aeb, 0d9efb4, 5caa13d, 270dd16, 940163f, 5c70aeb, b260123, 47892c8, 45bb78b, 5c70aeb, 70eef84, d84e52d, 24b80af, 608e156, 78d1c80, 2b2e157, 78d1c80, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
Storage adapters now return suggestedContinuation and currentTask fields on Observational Memory activation, enabling agents to maintain conversational context across activation boundaries. (#13357)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
Added Tree.Input component for inline file and folder creation within the Tree. Supports auto-focus, Enter to confirm, Escape to cancel, and blur handling with correct depth indentation. (#13264)
import { Tree } from '@mastra/playground-ui';
<Tree.Folder name="src" defaultOpen>
<Tree.Input
type="file"
placeholder="new-file.ts"
onSubmit={name => createFile(name)}
onCancel={() => setCreating(false)}
/>
<Tree.File name="index.ts" />
</Tree.Folder>;
dependencies updates: (#13284)
sonner@^2.0.7 ↗︎ (from ^2.0.5, in dependencies)dependencies updates: (#13300)
superjson@^2.2.6 ↗︎ (from ^2.2.2, in dependencies)Added a side-by-side diff view to the Dataset comparison pages (Compare Items and Compare Item Versions), making it easier to spot differences between dataset entries at a glance. (#13267)
Fixed the Experiment Result panel crashing with a type error when results contained nested objects instead of plain strings. (#13275)
Added a searchable combobox header to the Dataset page, allowing you to quickly filter and switch between datasets without scrolling through a long list. (#13273)
Added a composable Tree component for displaying file-system-like views with collapsible folders, file type icons, selection support, and action slots (#13259)
Updated dependencies [e4034e5, 0d9efb4, 7184d87, 5caa13d, 940163f, 47892c8, 3f8f1b3, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
tailwind-merge@^3.4.1 ↗︎ (from ^3.3.1, in dependencies)0d9efb4, 3f8f1b3]:
0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2246a6f, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417, b4b75ca]:
Fixed recursive schema warnings for processor graph entries by unrolling to a fixed depth of 3 levels, matching the existing rule group pattern (#13292)
Workspace tools like ast_edit are now correctly detected at runtime based on available dependencies (e.g. @ast-grep/napi), preventing missing tools from being advertised to agents. (#13233)
Updated dependencies [0d9efb4, 5caa13d, 940163f, 47892c8, 45bb78b, 70eef84, d84e52d, 24b80af, 608e156, 2b2e157, 59d30b5, 453693b, 78d1c80, c204b63, 742a417]:
A new generic Harness in @mastra/core provides a foundation for building agent-powered applications with modes, state management, built-in tools (ask_user, submit_plan), subagent support, Observational Memory integration, model discovery, permission-aware tool approval, and event-driven/thread/heartbeat management.
Workspaces gain least-privilege filesystem access via LocalFilesystem.allowedPaths (plus runtime updates with setAllowedPaths()), expanded glob-based configuration for file listing/indexing/skill discovery, and a new regex search tool mastra_workspace_grep to complement semantic search.
Tools can now define toModelOutput to transform tool results into model-friendly content while preserving raw outputs in storage, and workspace tools now return raw text (moving structured metadata to data-workspace-metadata stream chunks) to reduce token usage. Streaming reliability also improves (correct chunk types for tool errors, onChunk receives raw Mastra chunks, agent loop continues after tool errors).
Added allowedPaths option to LocalFilesystem for granting agents access to specific directories outside basePath without disabling containment. (#13054)
const workspace = new Workspace({
filesystem: new LocalFilesystem({
basePath: './workspace',
allowedPaths: ['/home/user/.config', '/home/user/documents'],
}),
});
Allowed paths can be updated at runtime using setAllowedPaths():
workspace.filesystem.setAllowedPaths(prev => [...prev, '/home/user/new-dir']);
This is the recommended approach for least-privilege access — agents can only reach the specific directories you allow, while containment stays enabled for everything else.
Added generic Harness class for orchestrating agents with modes, state management, built-in tools (ask_user, submit_plan), subagent support, Observational Memory integration, model discovery, and permission-aware tool approval. The Harness provides a reusable foundation for building agent-powered applications with features like thread management, heartbeat monitoring, and event-driven architecture. (#13245)
Added glob pattern support for workspace configuration. The list_files tool now accepts a pattern parameter for filtering files (e.g., **/*.ts, src/**/*.test.ts). autoIndexPaths accepts glob patterns like ./docs/**/*.md to selectively index files for BM25 search. Skills paths support globs like ./**/skills to discover skill directories at any depth, including dot-directories like .agents/skills. (#13023)
list_files tool with pattern:
// Agent can now use glob patterns to filter files
const result = await workspace.tools.workspace_list_files({
path: '/',
pattern: '**/*.test.ts',
});
autoIndexPaths with globs:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './project' }),
bm25: true,
// Only index markdown files under ./docs
autoIndexPaths: ['./docs/**/*.md'],
});
Skills paths with globs:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './project' }),
// Discover any directory named 'skills' within 4 levels of depth
skills: ['./**/skills'],
});
Note: Skills glob discovery walks up to 4 directory levels deep from the glob's static prefix. Use more specific patterns like ./src/**/skills to narrow the search scope for large workspaces.
Added direct skill path discovery — you can now pass a path directly to a skill directory or SKILL.md file in the workspace skills configuration (e.g., skills: ['/path/to/my-skill'] or skills: ['/path/to/my-skill/SKILL.md']). Previously only parent directories were supported. Also improved error handling when a configured skills path is inaccessible (e.g., permission denied), logging a warning instead of breaking discovery for all skills. (#13031)
Add optional instruction field to ObservationalMemory config types (#13240)
Adds instruction?: string to ObservationalMemoryObservationConfig and ObservationalMemoryReflectionConfig interfaces, allowing external consumers to pass custom instructions to observational memory.
Added typed workspace providers — workspace.filesystem and workspace.sandbox now return the concrete types you passed to the constructor, improving autocomplete and eliminating casts. (#13021)
When mounts are configured, workspace.filesystem returns a typed CompositeFilesystem<TMounts> with per-key narrowing via mounts.get().
Before:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: '/tmp' }),
sandbox: new E2BSandbox({ timeout: 60000 }),
});
workspace.filesystem; // WorkspaceFilesystem | undefined
workspace.sandbox; // WorkspaceSandbox | undefined
After:
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: '/tmp' }),
sandbox: new E2BSandbox({ timeout: 60000 }),
});
workspace.filesystem; // LocalFilesystem
workspace.sandbox; // E2BSandbox
// Mount-aware workspaces get typed per-key access:
const ws = new Workspace({
mounts: { '/local': new LocalFilesystem({ basePath: '/tmp' }) },
});
ws.filesystem.mounts.get('/local'); // LocalFilesystem
Added support for Vercel AI Gateway in the model router. You can now use model: 'vercel/google/gemini-3-flash' with agents and it will route through the official AI SDK gateway provider. (#13149)
Added toModelOutput support to the agent loop. Tool definitions can now include a toModelOutput function that transforms the raw tool result before it's sent to the model, while preserving the raw result in storage. This matches the AI SDK toModelOutput convention — the function receives the raw output directly and returns { type: 'text', value: string } or { type: 'content', value: ContentPart[] }. (#13171)
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
const weatherTool = createTool({
id: 'weather',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({
city,
temperature: 72,
conditions: 'sunny',
humidity: 45,
raw_sensor_data: [0.12, 0.45, 0.78],
}),
// The model sees a concise summary instead of the full JSON
toModelOutput: output => ({
type: 'text',
value: `${output.city}: ${output.temperature}°F, ${output.conditions}`,
}),
});
Added mastra_workspace_grep workspace tool for regex-based content search across files. This complements the existing semantic search tool by providing direct pattern matching with support for case-insensitive search, file filtering by extension, context lines, and result limiting. (#13010)
The tool is automatically available when a workspace has a filesystem configured:
import { Workspace, WORKSPACE_TOOLS } from '@mastra/core/workspace';
import { LocalFilesystem } from '@mastra/core/workspace';
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './my-project' }),
});
// The grep tool is auto-injected and available as:
// WORKSPACE_TOOLS.SEARCH.GREP → 'mastra_workspace_grep'
Removed outputSchema from workspace tools to return raw text instead of JSON, optimizing for token usage and LLM performance. Structured metadata that was previously returned in tool output is now emitted as data-workspace-metadata chunks via writer.custom(), keeping it available for UI consumption without passing it to the LLM. Tools are also extracted into individual files and can be imported directly (e.g. import { readFileTool } from '@mastra/core/workspace'). (#13166)
dependencies updates: (#13127)
hono@^4.11.9 ↗︎ (from ^4.11.3, in dependencies)dependencies updates: (#13167)
lru-cache@^11.2.6 ↗︎ (from ^11.2.2, in dependencies)Export AnyWorkspace type from @mastra/core/workspace for accepting any Workspace regardless of generic parameters. Updates Agent and Mastra to use AnyWorkspace so workspaces with typed mounts/sandbox (e.g. E2BSandbox, GCSFilesystem) are accepted without type errors. (#13155)
Update provider registry and model documentation with latest models and providers (e37ef84)
Fixed skill processor tools (skill-activate, skill-search, skill-read-reference, skill-read-script, skill-read-asset) being incorrectly suspended for approval when requireToolApproval: true is set. These internal tools now bypass the approval check and execute directly. (#13160)
Fixed a bug where requestContext metadata was not propagated to child spans. When using requestContextKeys, only root spans were enriched with request context values — child spans (e.g. agent_run inside a workflow) were missing them. All spans in a trace are now correctly enriched. Fixes #12818. (#12819)
Fixed semantic recall search in Mastra Studio returning no results when using non-default embedding dimensions (e.g., fastembed with 384-dim). The SemanticRecall processor now probes the embedder for its actual output dimension, ensuring the vector index name matches between write and read paths. Previously, the processor defaulted to a 1536-dim index name regardless of the actual embedder, causing a mismatch with the dimension-aware index name used by Studio's search. Fixes #13039 (#13059)
Fixed CompositeFilesystem instructions: agents and tools no longer receive an incorrect claim that files written via workspace tools are accessible at sandbox paths. The instructions now accurately describe only the available mounted filesystems. (#13221)
Fixed onChunk callback to receive raw Mastra chunks instead of AI SDK v5 converted chunks for tool results. Also added missing onChunk calls for tool-error chunks and tool-result chunks in mixed-error scenarios. (#13243)
Fixed tool execution errors stopping the agentic loop. The agent now continues after tool errors, allowing the model to see the error and retry with corrected arguments. (#13242)
Added runtime requestContext forwarding to tool executions. (#13094)
Tools invoked within agentic workflow steps now receive the caller's requestContext — including authenticated API clients, feature flags, and user metadata set by middleware. Runtime requestContext is preferred over build-time context when both are available.
Why: Previously, requestContext values were silently dropped in two places: (1) the workflow loop stream created a new empty RequestContext instead of forwarding the caller's, and (2) createToolCallStep didn't pass requestContext in tool options. This aligns both the agent generate/stream and agentic workflow paths with the agent network path, where requestContext was already forwarded correctly.
Before: Tools received an empty requestContext, losing all values set by the workflow step.
// requestContext with auth data set in workflow step
requestContext.set('apiClient', authedClient);
// tool receives empty RequestContext — apiClient is undefined
After: Pass requestContext via MastraToolInvocationOptions and tools receive it.
// requestContext with auth data flows through to the tool
requestContext.set('apiClient', authedClient);
// tool receives the same RequestContext — apiClient is available
Fixes #13088
Fixed tsc out-of-memory crash caused by step-schema.d.ts expanding to 50k lines. Added explicit type annotations to all exported Zod schema constants, reducing declaration output from 49,729 to ~500 lines without changing runtime behavior. (#13229)
Fixed TypeScript type generation hanging or running out of memory when packages depend on @mastra/core tool types. Changed ZodLikeSchema from a nominal union type to structural typing, which prevents TypeScript from performing deep comparisons of zod v3/v4 type trees during generic inference. (#13239)
Fixed tool execution errors being emitted as tool-result instead of tool-error in fullStream. Previously, when a tool's execute function threw an error, the error was caught and returned as a value, causing the stream to emit a tool-result chunk containing the error object. Now errors are properly propagated, so the stream emits tool-error chunks, allowing consumers (including the @mastra/ai-sdk conversion pipeline) to correctly distinguish between successful tool results and failed tool executions. Fixes #13123. (#13147)
Fixed thread title not being generated for pre-created threads. When threads were created before starting a conversation (e.g., for URL routing or storing metadata), the title stayed as a placeholder because the title generation condition checked whether the thread existed rather than whether it had a title. Threads created without an explicit title now get an empty title instead of a placeholder, and title generation fires whenever a thread has no title. Resolves #13145. (#13151)
Fixed inputData in dowhile and dountil loop condition functions to be properly typed as the step's output schema instead of any. This means you no longer need to manually cast inputData in your loop conditions — TypeScript will now correctly infer the type from your step's outputSchema. (#12977)
Migrated MastraCode from the prototype harness to the generic CoreHarness from @mastra/core. The createMastraCode function is now fully configurable with optional parameters for modes, subagents, storage, tools, and more. Removed the deprecated prototype harness implementation. (#13245)
Fixed the writer object being undefined in processOutputStream, allowing output processors to emit custom events to the stream during chunk processing. This enables use cases like streaming moderation results back to the client. (#13056)
Fixed sub-agent tool approval resume flow. When a sub-agent tool required approval and was approved, the agent would restart from scratch instead of resuming, causing an infinite loop. The resume data is now correctly passed through for agent tools so they properly resume after approval. (#13241)
Dataset schemas now appear in the Edit Dataset dialog. Previously the inputSchema and groundTruthSchema fields were not passed to the dialog, so editing a dataset always showed empty schemas. (#13175)
Schema edits in the JSON editor no longer cause the cursor to jump to the top of the field. Typing {"type": "object"} in the schema editor now behaves like a normal text input instead of resetting on every keystroke.
Validation errors are now surfaced when updating a dataset schema that conflicts with existing items. For example, adding a required: ["name"] constraint when existing items lack a name field now shows "2 existing item(s) fail validation" in the dialog instead of silently dropping the error.
Disabling a dataset schema from the Studio UI now correctly clears it. Previously the server converted null (disable) to undefined (no change), so the old schema persisted and validation continued.
Workflow schemas fetched via client.getWorkflow().getSchema() are now correctly parsed. The server serializes schemas with superjson, but the client was using plain JSON.parse, yielding a {json: {...}} wrapper instead of the actual JSON Schema object.
Fixed network mode messages missing metadata for filtering. All internal network messages (sub-agent results, tool execution results, workflow results) now include metadata.mode: 'network' in their content metadata, making it possible to filter them from user-facing messages without parsing JSON content. Previously, consumers had to parse the JSON body of each message to check for isNetwork: true — now they can simply check message.content.metadata.mode === 'network'. Fixes #13106. (#13144)
Fixed sub-agent memory context pollution that caused 'Exhausted all fallback models' errors when using Observational Memory with sub-agents. The parent agent's memory context is now preserved across sub-agent tool execution. (#13051)
Fixed CompositeAuth losing public and protected route configurations from underlying auth providers. Routes marked as public or protected now work correctly when deployed to Mastra Cloud. (#13086)
Trimmed the agent experiment result output to only persist relevant fields instead of the entire FullOutput blob. The stored output now contains: text, object, toolCalls, toolResults, sources, files, usage, reasoningText, traceId, and error. (#13158)
Dropped fields like steps, response, messages, rememberedMessages, request, providerMetadata, warnings, scoringData, suspendPayload, and other provider/debugging internals that were duplicated elsewhere or not useful for experiment evaluation.
Fixed .branch() condition receiving undefined inputData when resuming a suspended nested workflow after .map(). (#13055)
Previously, when a workflow used .map() followed by .branch() and a nested workflow inside the branch called suspend(), resuming would fail with TypeError: Cannot read properties of undefined because the branch conditions were unnecessarily re-evaluated with stale data.
Resume now skips condition re-evaluation for .branch() entries and goes directly to the correct suspended branch, matching the existing behavior for .parallel() entries.
Fixes #12982
Updated dependencies [1415bcd]:
@clack/prompts to v1 (#13095)dependencies updates: (#13127)
hono@^4.11.9 ↗︎ (from ^4.11.3, in dependencies)dependencies updates: (#13152)
@babel/core@^7.29.0 ↗︎ (from ^7.28.6, in dependencies)@babel/preset-typescript@^7.28.5 ↗︎ (from ^7.27.1, in dependencies)Fixes mastra build on Windows that incorrectly added spurious npm dependencies from monorepo directory names. (#13035)
Workspace paths are normalized to use forward slashes so import-path comparisons match Rollup on Windows.
Updated dependencies [252580a, f8e819f, 252580a, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 84fb4bf, 02dc07a, bb7262b, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 6909c74, 0a25952, ffa5468, 3264a04, 6fdd3d4, 10cf521, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, d03df73, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
compromise@^14.14.5 ↗︎ (from ^14.14.4, in dependencies)252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
pino-pretty@^13.1.3 ↗︎ (from ^13.0.0, in dependencies)252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
Add instruction property to observational memory configs (#13240)
Adds optional instruction field to ObservationConfig and ReflectionConfig that allows users to extend the built-in observer/reflector system prompts with custom guidance.
Example:
const memory = new ObservationalMemory({
model: openai('gpt-4'),
observation: {
instruction: 'Focus on user preferences about food and dietary restrictions.',
},
reflection: {
instruction: 'Prioritize consolidating health-related observations together.',
},
});
dependencies updates: (#13167)
lru-cache@^11.2.6 ↗︎ (from ^11.2.2, in dependencies)Reflection retry logic now attempts compression up to level 3, so reflections more consistently shrink to meet token limits (#13170)
sliceTokenEstimate * 0.75), making automatic trimming less aggressivetokensBuffered marker now reports the actual slice size rather than total observation tokens, giving accurate size monitoringThese changes reduce failed reflections and make reported metrics match what is actually being processed.
Fixed a bug where the OM context window would jump to extremely high token counts (e.g. 16k → 114k) after observation activation. Two issues were causing this: (#13070)
data-om-activation marker parts (which contain the full observation text, up to 150k+ characters) were being counted as message tokens when loaded from the database. These parts are never sent to the LLM and are now skipped during token counting.persistMarkerToMessage and persistMarkerToStorage now deduplicate by type + cycleId before adding a marker.Fixed thread title not being generated for pre-created threads. When threads were created before starting a conversation (e.g., for URL routing or storing metadata), the title stayed as a placeholder because the title generation condition checked whether the thread existed rather than whether it had a title. Threads created without an explicit title now get an empty title instead of a placeholder, and title generation fires whenever a thread has no title. Resolves #13145. (#13151)
Fixed sub-agent memory context pollution that caused 'Exhausted all fallback models' errors when using Observational Memory with sub-agents. The parent agent's memory context is now preserved across sub-agent tool execution. (#13051)
Updated dependencies [252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, 1415bcd, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
dependencies updates: (#12921)
@assistant-ui/react@^0.12.10 ↗︎ (from ^0.12.3, in dependencies)@assistant-ui/react-markdown@^0.12.3 ↗︎ (from ^0.12.1, in dependencies)@assistant-ui/react-syntax-highlighter@^0.12.3 ↗︎ (from ^0.12.1, in dependencies)dependencies updates: (#13100)
@codemirror/view@^6.39.14 ↗︎ (from ^6.39.13, in dependencies)Fixed React error #310 crash when using observational memory in Mastra Studio. The chat view would crash when observation markers appeared alongside regular tool calls during streaming. (#13216)
Fixed dragged column appearing offset from cursor when mapping CSV columns in dataset import dialog (#13176)
Fixed schema form to apply changes only on Save click instead of every keystroke. Removed AgentPromptExperimentProvider in favor of inline prompt rendering. Switched hooks to use merged request context for proper request-scoped data fetching. (#13034)
Added a "Try to connect" button in the MCP client sidebar to preview available tools before creating. Fixed SSE response parsing for MCP servers returning event streams. (#13093)
Fix dataset import creating a new version per item. CSV and JSON import dialogs now use the batch insert endpoint so all imported items land on a single version. (#13214)
Fix experiment result detail panel showing output data under "Input" label, add missing Output section, and add Input column to experiment results list table. (#13165)
Updated style of Button and Select experimental variants (#13186)
Added requestContext support to listScorers for request-scoped scorer resolution (#13034)
Added mount picker for skill installation when multiple filesystem mounts are available. Skills table and detail page now show skill paths and mount labels. (#13031)
Removed unused Dataset Item Edit Dialog (#13199)
Hide Dataset Item History panel when item is edited (#13195)
Dataset schemas now appear in the Edit Dataset dialog. Previously the inputSchema and groundTruthSchema fields were not passed to the dialog, so editing a dataset always showed empty schemas. (#13175)
Schema edits in the JSON editor no longer cause the cursor to jump to the top of the field. Typing {"type": "object"} in the schema editor now behaves like a normal text input instead of resetting on every keystroke.
Validation errors are now surfaced when updating a dataset schema that conflicts with existing items. For example, adding a required: ["name"] constraint when existing items lack a name field now shows "2 existing item(s) fail validation" in the dialog instead of silently dropping the error.
Disabling a dataset schema from the Studio UI now correctly clears it. Previously the server converted null (disable) to undefined (no change), so the old schema persisted and validation continued.
Workflow schemas fetched via client.getWorkflow().getSchema() are now correctly parsed. The server serializes schemas with superjson, but the client was using plain JSON.parse, yielding a {json: {...}} wrapper instead of the actual JSON Schema object.
Fixed "Tried to unmount a fiber that is already unmounted" error in the playground agent chat. Switching threads rapidly or creating new threads no longer causes this console error. (#13182)
Updated visuals of Dataset Items List empty state (#13203)
Updated workspace tool badges for execute command and list files tools. Execute command badge now shows running state for silent commands and correctly scopes output to individual tool calls during parallel execution. (#13166)
Updated dependencies [252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 55a0ab1, 02dc07a, bb7262b, 1415bcd, cf1c6e7, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 55a0ab1, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, ec36c0c, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:
The zodToJsonSchema function now reliably detects and routes Zod v3 vs v4 schemas regardless of which version the ambient zod import resolves to. Previously, the detection relied on checking 'toJSONSchema' in z against the ambient z import, which could resolve to either v3 or v4 depending on the environment (monorepo vs global install). This caused v3 schemas to be passed to v4's toJSONSchema() (crashing with "Cannot read properties of undefined (reading 'def')") or v4 schemas to be passed to the v3 converter (producing schemas missing the type field).
The fix explicitly imports z as zV4 from zod/v4 and routes based on the schema's own _zod property, making the behavior environment-independent.
Also migrates all mastracode tool files from zod/v3 to zod imports now that the schema-compat fix supports both versions correctly.
dependencies updates: (#13127)
hono@^4.11.9 ↗︎ (from ^4.11.3, in dependencies)Use dynamic import in server for stored skills related feature. (#13217)
Register mastra_workspace_grep tool in studio workspace tools listing so it appears in the agent metadata UI when a workspace has a filesystem configured. (#13010)
Fixed skill removal for glob-discovered skills. The remove handler now looks up a skill's actual discovered path instead of assuming the hardcoded .agents/skills directory, so skills discovered via glob patterns can be correctly deleted. (#13023)
Dataset schemas now appear in the Edit Dataset dialog. Previously the inputSchema and groundTruthSchema fields were not passed to the dialog, so editing a dataset always showed empty schemas. (#13175)
Added mount-aware skill installation for CompositeFilesystem workspaces. The install, remove, and update handlers now resolve the correct mount when multiple filesystem mounts are configured. Workspace info endpoint now includes mount metadata when available. (#13031)
Updated dependencies [252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]: