Skip to content

Release history

mastra releases

From the team behind Gatsby, Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

All releases

52 shown

Review required
@mastra/[email protected] Breaking risk
Auth RBAC Breaking upgrade

Routine maintenance and dependency updates.

Config change
@mastra/[email protected] Breaking risk
Breaking upgrade

Breaking changes — review before upgrading.

Review required
@mastra/[email protected] Breaking risk
Auth RBAC

ACP agents + XAI voice + metadata

Review required
@mastra/[email protected] Breaking risk
Auth Breaking upgrade

Breaking changes — review before upgrading.

@mastra/[email protected] Breaking risk
⚠ Upgrade required
  • Update database migrations to add `ownerType`, `ownerId` columns in `mastra_schedules` and rename/modify columns in `mastra_schedule_triggers` as described.
  • Adjust client‑JS code handling Vector methods to match the new return type shapes.
Breaking changes
  • Schedules storage schema changed: `mastra_schedules` now includes optional `ownerType` and `ownerId`; `mastra_schedule_triggers` renamed `status` to `outcome`, added stable primary key `id`, and new columns `triggerKind`, `parentTriggerId`, `metadata`. No compatibility shim provided.
  • Client‑JS Vector return types changed: `vector.getIndexes()` → `string[]`, `vector.upsert()` → `{ ids: string[] }`, `vector.query()` → `QueryResult[]`.
Notable features
  • Fine-Grained Authorization (FGA) across Mastra core, server adapters, and MCP with new `IFGAProvider`, `IFGAManager`, centralized `checkFGA()`, thread‑level access control, and WorkOS-backed provider (`MastraFGAWorkos`).
  • Scheduled workflows with cron‑native scheduling, automatic promotion to evented engine, safe multi‑instance claiming via `WorkflowScheduler`, new storage domains (PG/LibSQL/MongoDB), client/server APIs, and Studio UI for listing schedules, trigger history, pause/resume.
  • MCP Apps interactive UI resources (`ui://`) via `appResources` on `MCPServerBase`, with list/read endpoints, proxy helpers, and server‑Id stamping for multi‑server resolution (SEP‑1865).
Full changelog

Highlights

Fine-Grained Authorization (FGA) across Mastra (core + server adapters + MCP)

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.

WorkOS-backed FGA provider (@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.

Scheduled Workflows (cron-native) + scheduler + full HTTP/Studio/client support

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 Apps: interactive UI resources over MCP (SEP-1865) + resource listing/reading APIs

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.

Observability upgrades: nested-run querying + bounded high-cardinality metrics + Datadog bridge

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.

Breaking Changes

  • Schedules storage schema changed (mastra_schedules, mastra_schedule_triggers): adds ownerType/ownerId, renames ScheduleTrigger.statusoutcome, 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[] })

Changelog

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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).

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • Added MastraFGAWorkos provider for Fine-Grained Authorization using the WorkOS Authorization API. Implements IFGAManager interface with support for: (#15410)

    • Authorization checks (check(), require(), filterAccessible())
    • Resource management (createResource(), getResource(), listResources(), updateResource(), deleteResource())
    • Role assignments (assignRole(), removeRole(), listRoleAssignments())
    • resourceMapping and permissionMapping for translating Mastra resource types and permissions to WorkOS resource type slugs and permission slugs
    • Organization scoping that denies access when the user is not a member of the configured organization
    • Bearer-token / verified JWT support that carries service-token FGA context such as organization membership IDs, while ignoring JWT-derived memberships unless organization claims are trusted
    • Membership caching and batched accessible-resource discovery for lower per-request latency
    • Tenant inference and parent-resource filtering for scoped access checks
    • Paginated organization membership lookup and limited concurrent FGA checks when filtering accessible resources
    • Typed permission constants accepted in permissionMapping
    import { 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',
    });
    

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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',
    });
    
    • Added listBranches and getSpans implementations. (#16154)
    • Only spans recorded after this version is deployed are queryable via listBranches; historical traces remain accessible through the existing listTraces / getTrace APIs.

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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.

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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!,
            }),
          },
        },
      }),
    });
    

Patch Changes

@mastra/[email protected]

Minor Changes

    • Added listBranches and getSpans implementations. (#16154)
    • Historical span data is queryable immediately; no migration 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',
    });
    

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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>',
        },
      },
    });
    

@mastra/[email protected]

Patch Changes

  • Added FGA enforcement to server adapter middleware, ensuring authorization checks are applied consistently across all built-in adapters. (#15410)

@mastra/[email protected]

Patch Changes

  • Added FGA enforcement to server adapter middleware, ensuring authorization checks are applied consistently across all built-in adapters. (#15410)

@mastra/[email protected]

Patch Changes

  • Added FGA enforcement to server adapter middleware, ensuring authorization checks are applied consistently across all built-in adapters. (#15410)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • Added FGA enforcement to server adapter middleware, ensuring authorization checks are applied consistently across all built-in adapters. (#15410)

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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)

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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>',
        },
      },
    });
    

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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)

Patch Changes

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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)

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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.
    • A workflow's detail header shows a Schedules action when it has at least one schedule.
  • 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>
    

Patch Changes

  • 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:

    • Variant toasts (success / error / warning / info) now render with the same notice color tokens as the <Notice> component, including bg, border and text color in both light and dark mode.
    • Sonner's native layout is back in charge — the loader on toast.promise, the close button position, the icon placement and the mobile width all work as documented instead of fighting custom overrides.
    • The native close button has its own polished hover: it blends with the toast at rest and lifts with a tinted bg + stronger border on hover, in every variant and theme.
    • Sticky toasts can be made truly non-dismissible by passing both 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)

@mastra/[email protected]

Patch Changes

  • Fixed custom data stream parts so stable ids are preserved in React UI messages. (#16067)

@mastra/[email protected]

Minor Changes

  • 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.
    • The libsql, pg, and mongodb adapters all add the new columns/indexes. Their @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.
    • Scheduler producer, server schemas/handler, and client SDK types are updated to use the new fields. The triggers response on GET /api/schedules/:id/triggers now returns outcome instead of status.
    • The bundled Studio (Mastra CLI) is updated to read 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 server
    • POST /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)

    • Route-level checks on detail endpoints, custom routes (including request-aware resource ID resolvers and path parameters), and resource-scoped search
    • Thread-level checks on reads, writes, creation, cloning, message saving, and listing — with unviewable threads hidden from totals and pagination
    • Message deletion now denies access when the message's thread cannot be verified
    • Authenticated user context preserved through thread authorization, and the thread's owning resourceId forwarded into the FGA context so providers can derive composite tenant-scoped resource IDs
    • Route permission derivation and memory clone checks now use the correct resource context
    • Typed FGA permission constants accepted in route and thread authorization config

Patch Changes

  • Fixed 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)

@mastra/[email protected]

Patch Changes

  • Fixed Slack app creation failing when agent description exceeds 139 characters. The manifest description is now automatically truncated to prevent the Slack API from rejecting the request. (#16093)

@mastra/[email protected]

Minor Changes

  • Added the new @mastra/temporal package for running Mastra workflows on Temporal. (#15789)

    What changed

    • Added init() to create Temporal-backed Mastra workflows and steps.
    • Added MastraPlugin to bundle workflow code for Temporal workers and load generated activities.
    • Added 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') })],
    });
    

Patch Changes

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Breaking changes
  • `IconButton` export removed from `@mastra/playground-ui`; use `Button` with `size="icon-*"` instead.
Notable features
  • Platform Channels Framework added across core, adapters, and client (ChannelProvider, ChannelsStorage, connect/disconnect/list APIs).
  • Slack channel integration (`@mastra/slack`) for OAuth provisioning, encrypted credentials, slash commands, threaded conversations.
  • NestJS server adapter (`@mastra/nestjs`) enabling Mastra inside NestJS/Express with DI, rate limiting, graceful shutdown.
Full changelog

Highlights

Platform Channels Framework (Core + Server + Client)

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.

Slack Channel Integration (@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.

NestJS Server Adapter (@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.

Google Drive Workspace Filesystem (@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.

Real-time Voice Provider for AWS Nova Sonic (@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.

Breaking Changes

  • @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".

Changelog

@mastra/[email protected]

Minor Changes

  • 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 },
      ),
    });
    

Patch Changes

  • 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)

    • SearchEngine: 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)
    • Workspace: Search auto-indexing reads files in parallel with a bounded concurrency, skips unreadable paths, awaits batch indexing, and falls back to per-file indexing when the batch path throws. Successful single-file indexing returns the path so callers can track what was indexed.
  • 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)

@mastra/[email protected]

Patch Changes

  • Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)

    • gen_ai.usage.cached_input_tokensgen_ai.usage.cache_read.input_tokens
    • gen_ai.usage.cache_write_tokensgen_ai.usage.cache_creation.input_tokens

    gen_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.

@mastra/[email protected]

Patch Changes

  • Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)

    • gen_ai.usage.cached_input_tokensgen_ai.usage.cache_read.input_tokens
    • gen_ai.usage.cache_write_tokensgen_ai.usage.cache_creation.input_tokens

    gen_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.

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Minor Changes

  • Added Channels resource to MastraClient with listPlatforms, listInstallations, connect, and disconnect methods for managing platform channel integrations. (#15876)

Patch Changes

@mastra/[email protected]

Patch Changes

  • Fixed Convex workflow snapshot loads to use the workflow/run index. (#15971)

@mastra/[email protected]

Patch Changes

  • Fixed an issue where automatic thread title generation was skipped when using the DynamoDB storage adapter. The adapter was overwriting empty thread titles with a 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • GoogleDriveFilesystem tweaks: mkdir defaults to recursive, appendFile uses optimistic concurrency, rmdir skips redundant child listing, JSON body requests include Content-Type header, readFile uses consistent searchParams, and concurrent token refreshes are deduplicated. (#16010)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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

@mastra/[email protected]

Minor Changes

  • 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 {}
    

Patch Changes

@mastra/[email protected]

Minor Changes

  • Auto-attach the Mastra-level environment to all observability signals. (#15956)

Patch Changes

@mastra/[email protected]

Patch Changes

  • Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)

    • gen_ai.usage.cached_input_tokensgen_ai.usage.cache_read.input_tokens
    • gen_ai.usage.cache_write_tokensgen_ai.usage.cache_creation.input_tokens

    gen_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.

@mastra/[email protected]

Minor Changes

  • 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 });
    

Patch Changes

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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>
    

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Fixed suspended tool run IDs not being preserved after page refresh. (#15107)

@mastra/[email protected]

Patch Changes

  • Renamed emitted OTel GenAI cache usage attributes to match the OpenTelemetry semantic conventions: (#15966)

    • gen_ai.usage.cached_input_tokensgen_ai.usage.cache_read.input_tokens
    • gen_ai.usage.cache_write_tokensgen_ai.usage.cache_creation.input_tokens

    gen_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.

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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
    

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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:

    • Live microphone streaming (send / listen) and assistant audio playback
      via speaking events
    • Live transcription via writing events with SPECULATIVE / FINAL
      generation stages
    • Barge-in / interrupt detection
    • Speaker selection across all 18 Nova Sonic voices and configurable
      endpointing sensitivity
    • Tool calling with per-session RequestContext
    • Configurable AWS region, model id, credentials (or default credential
      provider chain), and inference / turn-detection parameters

Patch Changes

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
⚠ Upgrade required
  • Fix regression: custom API routes starting with /api no longer cause server startup crashes when using channel adapters.
  • MCP client support fixes in the agent editor (dirty state handling, tool name matching, auth token forwarding, context variable interpolation).
Notable features
  • DurableAgents (createDurableAgent, createEventedAgent, createInngestAgent) with resumable streaming
  • Pluggable PubSub + Cache infrastructure (defaults EventEmitterPubSub and InMemoryServerCache; Redis-backed recommended)
  • Improved A2A streaming artifacts emit incremental updates during full agent stream
Full changelog

Highlights

Durable Agents + Resumable Streams (crash/disconnect resilient execution)

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 }).

Workflow-backed “Durable Execution” (Evented + Inngest strategies)

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.

Pluggable PubSub + Cache infrastructure (Redis/Upstash-ready)

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.

Improved A2A streaming artifacts in @mastra/server

A2A streaming now emits incremental artifact updates during the full agent stream while still preserving final structured output artifacts.

Observability noise/volume reduction by default

Cloud observability uploads now filter model chunk spans by default and raise the default observability log level to warn, reducing data volume and chatter.

Breaking Changes

  • None called out in this changelog.

Changelog

@mastra/[email protected]

Minor Changes

  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution

Patch Changes

  • Fixed 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)

    • MCP client form dirty state: Save button now enables after adding/removing MCP clients
    • MCP tool name matching: Both bare and namespaced tool names are matched correctly
    • Auth token forwarding: Token from cookie or header is forwarded to auth-protected MCP servers
    • String interpolation: Request context variables in system prompts now resolve correctly

@mastra/[email protected]

Patch Changes

  • 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.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution

@mastra/[email protected]

Patch Changes

  • Fix MCP client support in the agent editor: (#15945)
    • MCP client form dirty state: Save button now enables after adding/removing MCP clients
    • MCP tool name matching: Both bare and namespaced tool names are matched correctly
    • Auth token forwarding: Token from cookie or header is forwarded to auth-protected MCP servers
    • String interpolation: Request context variables in system prompts now resolve correctly

@mastra/[email protected]

Patch Changes

  • Fixed 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)

@mastra/[email protected]

Minor Changes

  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution
  • Update peer dependencies to match core package version bump (1.0.5) (#12557)

Patch Changes

@mastra/[email protected]

Patch Changes

  • Fixed idle timeout and provider-change observation activations blocking on in-progress reflection buffering. These triggers now return immediately, letting the background reflection complete asynchronously. (#15937)

@mastra/[email protected]

Patch Changes

  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution
  • Reduced default cloud observability volume by filtering model chunk spans from CloudExporter uploads by default and raising the default observability log level to warn. (#15815)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • Update peer dependencies to match core package version bump (1.0.5) (#12557)

Patch Changes

  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution

@mastra/[email protected]

Minor Changes

  • Update peer dependencies to match core package version bump (1.0.5) (#12557)

Patch Changes

  • Fixed 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)

    • MCP client form dirty state: Save button now enables after adding/removing MCP clients
    • MCP tool name matching: Both bare and namespaced tool names are matched correctly
    • Auth token forwarding: Token from cookie or header is forwarded to auth-protected MCP servers
    • String interpolation: Request context variables in system prompts now resolve correctly
  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution
  • Fix A2A streaming to emit incremental artifact updates from the agent full stream while preserving final structured output artifacts. (#15941)

@mastra/[email protected]

Minor Changes

  • Update peer dependencies to match core package version bump (1.0.5) (#12557)

Patch Changes

  • Add durable agents with resumable streams (#12557)

    Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.

    The Problem

    Standard agent streaming has two fragility points:

    1. Connection drops - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
    2. Long-running operations - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.

    The Solution

    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.

    Usage

    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 |

    Resumable Streams

    // 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
    

    PubSub and Cache

    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.

    Class Hierarchy

    • DurableAgent extends Agent - base class with resumable streams
    • EventedAgent extends DurableAgent - fire-and-forget execution
    • InngestAgent extends DurableAgent - Inngest-powered execution

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
⚠ Upgrade required
  • Migrate TTS configuration: replace deprecated model identifiers and speaker names with the new `bulbul:v3` default speaker `shubh`.
  • Update any code sending a TTS request to use a single `text` field instead of an `inputs` array.
Breaking changes
  • Removed TTS model `bulbul:v1` and its speakers (`meera`, `pavithra`, `maitreyi`, `arvind`, `amol`, `amartya`, `diya`, `neel`, `misha`, `vian`, `arjun`, `maya`).
  • Removed STT models `saarika:v1`, `saarika:v2`, and `saarika:flash`.
  • Changed TTS request payload from `inputs[]` array to a single `text` string.
Notable features
  • Added support for Sarvam's new TTS models (`bulbul:v2`, `bulbul:v3`, `bulbul:v3-beta`) with 39 speakers and expanded parameters (temperature, dict_id, output_audio_codec).
  • Added STT model `saarika:v2.5` as default and introduced multi‑mode model `saaras:v3` supporting transcribe/translate/verbatim/translit/codemix.
  • Expanded `speech_sample_rate` options to 8000, 16000, 22050, 24000, 32000, 44100, 48000.
Full changelog

Highlights

Per-user resource scoping in server auth (secure by default)

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 + observability are now version-aware end-to-end

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.

Agent version targeting in AI SDK route handlers

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).

Tool calling reliability upgrades: strict mode + better API error recovery

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).

Browser automation persistence & stability improvements

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.

Breaking Changes

  • @mastra/[email protected] 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.

Changelog

@mastra/[email protected]

Minor Changes

  • 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 }),
    });
    

Patch Changes

  • 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.

@mastra/[email protected]

Minor Changes

  • Added storageState option and exportStorageState() method for lightweight auth persistence (cookies and localStorage). Also kills orphaned Chrome child processes on close to prevent zombies. (#15194)

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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,
    });
    

Patch Changes

  • Fixed reasoning streams so reasoning UI parts are only emitted when reasoning content is included. (#15207)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Resolving stored agent versions no longer mutates the shared singleton agent instance. Instruction and tool overrides are now applied to an isolated clone, making concurrent version resolution safe and preventing overrides from leaking onto the global agent. (#15314)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • Added 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)

Patch Changes

  • Preserve forwarded MCP client elicitation capabilities so client-supported URL and form elicitations work correctly. (#15233)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Fixed generation traces producing stringified JSON in messages instead of structured content. Input messages wrapped as {messages: [...]} and output objects with text are now properly extracted and formatted. (#15203)

@mastra/[email protected]

Patch Changes

  • --- (#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.

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Minor Changes

  • 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.).

Patch Changes

  • 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.

@mastra/[email protected]

Minor Changes

  • Added automatic cleanup on browser close: patches 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)

Patch Changes

@mastra/[email protected]

Major Changes

  • 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:

    • TTS models: bulbul:v2, bulbul:v3 (default), and bulbul:v3-beta. bulbul:v3 and bulbul:v3-beta support 39 speakers; bulbul:v2 supports 7 speakers.
    • STT models: 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.
    • New bulbul:v3 parameters: temperature, dict_id, output_audio_codec.
    • Expanded speech_sample_rate options: 8000, 16000, 22050, 24000, 32000, 44100, 48000.

    Breaking changes:

    • Removed the deprecated 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.
    • Removed the deprecated saarika:v1, saarika:v2, and saarika:flash STT models.
    • The default TTS model is now bulbul:v3 and the default speaker is shubh. Speakers are not interchangeable between bulbul versions — each has its own catalog.
    • The TTS request body now sends 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.

Patch Changes

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Notable features
  • Stream 'until idle' (streamUntilIdle, resumeStream) to include background task results in the same turn without requiring a second user message
  • Forked subagents for isolated execution on cloned parent thread while preserving prompt-cache prefix and parent tools
  • Azure Blob Storage workspace provider and AzureBlobStore for skill versioning with multiple auth methods
Full changelog

Highlights

Azure Blob Storage workspace + blob store (@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.

Stream “until idle” to include background task results in the same turn

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 suspended agent streams over HTTP (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.

Forked subagents for isolated execution on a cloned thread

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.

Cloudflare Workers / V8-isolate support for MCP JSON schema validation

@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.

Breaking Changes

  • None noted in this changelog.

Changelog

@mastra/[email protected]

Minor Changes

  • 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)

Patch Changes

  • 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) {
      /* ... */
    }
    

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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)

    • Added official-style A2A methods such as getAgentCard(), sendMessageStream(), getExtendedAgentCard(), and getTaskPushNotificationConfig().
    • Added typed A2A stream consumption for sendMessageStream() and resubscribeTask().
    • Kept older methods available as deprecated compatibility methods, including getCard() and sendStreamingMessage().

Patch Changes

  • 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) {
      /* ... */
    }
    

@mastra/[email protected]

Patch Changes

  • Fixed slow or stuck mastra dev startup in large monorepos when workspace packages share internal dependencies. (#12963)

    What changed

    • Mastra now avoids repeating the same dependency analysis work during dev startup when multiple workspace packages depend on the same internal package.
    • This reduces repeated startup work in large monorepos and helps the dev server reach a ready state more reliably.

    Fixes #12843.

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Patch Changes

  • Fixed the recall tool so message browsing uses the current thread by default and explains when it does. (#15807)

@mastra/[email protected]

Patch Changes

  • Fixed requestContext filtering in span creation to prevent large objects from being serialized into trace data. (#15642)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Updated posthog-node from v4 to v5 to pick up the latest fixes and LLM analytics improvements. Resolves #15858. (#15867)

@mastra/[email protected]

Patch Changes

  • The useChat hook stream now calls the new agent.streamUntilIdle method and the background-task chunks are processed in toUIMessage. (#15686)

@mastra/[email protected]

Patch Changes

  • Fixed Redis package releases to include built files. (#15763)

@mastra/[email protected]

Minor Changes

  • 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',
    });
    

    Fixes https://github.com/mastra-ai/mastra/issues/14289

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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),
    });
    

Patch Changes

  • 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)

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Breaking changes
  • Processor traces payload structure changed: stores only changed outputs instead of all hook inputs and outputs; direct PROCESSOR_RUN consumers must update parsers
Security fixes
  • Fixed credential leakage in observability spans: LLM API keys, auth headers, and gateway tokens no longer exposed in telemetry across model routers, gateways, and wrappers
Notable features
  • Background task execution with /api/background-tasks endpoints and storage support
  • Redis storage adapter (@mastra/redis) for memory, workflows, and scores
  • Netlify Edge deployment target with target: 'edge' option
Full changelog

Highlights

Background Tasks (Async Tool Execution + APIs + Storage Support)

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.

New Redis Storage Adapter (@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.

Netlify Edge Deployment Target

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.

Observability: RAG Runs in Traces + Lightweight Trace/Span Fetching

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.

Security & Governance for Telemetry (Credential Leak Fix + Per-request Redaction/Tags)

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.

Breaking Changes

  • None called out in the provided changelog (no consolidated breaking-change section for these versions).

Changelog

@mastra/[email protected]

Minor Changes

  • 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

    • Review existing telemetry data for leaked credentials and rotate any keys that may have been captured.
    • Custom gateways extending 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.
    • For any other class you pass into a span (e.g. as 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)

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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
      });
    

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)

@mastra/[email protected]

Patch Changes

  • Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)

@mastra/[email protected]

Patch Changes

  • Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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,
    });
    

Patch Changes

  • Fixed process kill to target the entire process group (negative PID) with fallback, ensuring child processes spawned inside the container are properly cleaned up. Tracked process handles are now cleared after container stop or destroy to prevent stale references. (#14500)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)

@mastra/[email protected]

Patch Changes

  • Add nack support and deliveryAttempt tracking on the subscriber callback, and enable exactly-once delivery on grouped subscriptions. (#15307)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Add BackgroundTasksStorage domain implementation so @mastra/core background task execution works with any storage adapter. (#15307)

@mastra/[email protected]

Minor Changes

  • Added new attribute mappings to the Langfuse exporter so more Mastra attributes are filterable in Langfuse's UI. (#15445)

    Observation-level metadatagen_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 attributesmastra.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.

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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:

    • The unreflected observation tail is at least as large as the buffered reflection, so the activated result is not dominated by compressed content.
    • The combined post-activation size is at least 75% of what a normal threshold activation would produce, so early activations do not cliff far below the regular target.

    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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Return 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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)

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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).

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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
    }
    

Patch Changes

  • 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/[email protected]

Major Changes

  • Added the @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)

Patch Changes

@mastra/[email protected]

Patch Changes

  • 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)

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Notable features
  • Per-request Workspace filesystem resolver for multi-tenant deployments and scoped permissions
  • Modal Cloud Sandbox Provider for isolated cloud-based workspace execution
  • Custom language server registration in LSPConfig
Full changelog

Highlights

Modal Cloud Sandbox Provider (@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.

Per-request Workspace Filesystem Resolver (Multi-tenant Routing)

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.

Custom Language Server Registration in LSPConfig

You 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).

Vector Search “Works Out of the Box” (Indexing + Large File Chunking)

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.

Streaming & Observational Memory Reliability + Better Usage Introspection

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.

Breaking Changes

  • None noted in this changelog.

Changelog

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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)

    • Large files that exceeded the embedding model token limit were previously silently skipped, leaving the vector store empty and causing search failures. Large files are now split into overlapping line-based chunks, each indexed separately with correct line-range tracking back to the original file.
    • The vector index is now created automatically before the first upsert. Previously, backends that require an explicit 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.

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Patch Changes

  • Replace uuid with @lukeed/uuid and node:crypto (#15691)

@mastra/[email protected]

Patch Changes

  • Replace uuid with @lukeed/uuid and node:crypto (#15691)

@mastra/[email protected]

Patch Changes

  • Fixed streamed tool results being replayed when observational memory runs mid-stream. (#15701)
    Fixed observational memory markers being saved as separate empty assistant messages.

@mastra/[email protected]

Minor Changes

  • 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!,
      }),
    });
    

Patch Changes

@mastra/[email protected]

Patch Changes

  • Replace uuid with @lukeed/uuid and node:crypto (#15691)

@mastra/[email protected]

Patch Changes

  • 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.

@mastra/[email protected]

Patch Changes

  • Replace uuid with @lukeed/uuid and node:crypto (#15691)

@mastra/[email protected]

Patch Changes

  • 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:

    • X-Forwarded-Host (traditional reverse proxies) → always HTTPS
    • Host header (AWS ALB with Preserve Host Header) → respect X-Forwarded-Proto or default HTTPS
    • request.url (local development) → fallback

    Fixes OAuth callback URLs being resolved to http:// instead of https:// when deployed behind AWS ALB with Preserve Host Header enabled.

@mastra/[email protected]

Patch Changes

  • 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)

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Notable features
  • CLI-driven browser automation with CDP injection and screencast support
  • S3 prefix (subdirectory) mounts across workspace providers
  • New @mastra/tavily package with search, extract, crawl, and map tools
Full changelog

Highlights

CLI-Driven Browser Automation + Screencasts

@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.

S3 “Prefix Mounts” Across Workspace Providers

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.

More Robust Workflow Resumes for Parallel foreach

Fixes 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.

Observational Memory Improvements (Temporal Markers + Correctness Fixes)

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.

New Package: @mastra/tavily

New 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.

Breaking Changes

  • None noted in this changelog.

Changelog

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

  • 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/[email protected]

Patch Changes

  • Hide internal log during mastra dev startup (that was previously already hidden but got exposed again by a recent change) (#15616)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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
      })
    });
    

Patch Changes

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Patch Changes

  • Fix custom route handlers on the Fastify adapter silently overwriting request-body fields named 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)

@mastra/[email protected]

Minor Changes

  • 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)

Patch Changes

  • Fixed observer agent truncation that could cut UTF-16 surrogate pairs in half when formatting messages, tool results, or observation lines with emoji or other astral-plane characters. This produced lone surrogates that strict JSON parsers (including Anthropic's) reject with errors like no low surrogate in string, causing observer runs to fail. (#15634)

@mastra/[email protected]

Minor Changes

  • 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.

Patch Changes

@mastra/[email protected]

Patch Changes

  • 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)

@mastra/[email protected]

Patch Changes

  • Fixed runtime ERR_MODULE_NOT_FOUND for @tavily/core by making it a direct dependency. Consumers no longer need to install @tavily/core manually. (#15628)

Other updated packages

The following packages were updated with dependency changes only:

@mastra/[email protected] Breaking risk
Breaking changes
  • CloudExporter endpoint configuration format changed: configure a base endpoint URL, publisher paths are derived automatically
Notable features
  • RAG ingestion and query operations now traced with new span types (RAG_INGESTION, RAG_EMBEDDING, RAG_VECTOR_OPERATION, RAG_ACTION, GRAPH_ACTION) and helpers like startRagIngestion() and withRagIngestion()
  • CloudExporter now batches and uploads logs, metrics, scores, and feedback in addition to traces through a single exporter path
  • Span filtering via excludeSpanTypes and spanFilter options to reduce observability noise and per-span costs
@mastra/[email protected] Breaking risk
Notable features
  • ModelByInputTokens for memory model selection by token count
  • MongoDB dataset versioning with item history
  • Okta auth and RBAC with JWT verification
@mastra/[email protected] Breaking risk
Notable features
  • AI Gateway tool support in the agentic loop with merged provider results and skipped local execution when provider already returned result
  • Observational memory improvements with dated message boundary delimiters for cache stability and getObservationsAsOf() for replay and debugging
  • MCP client diagnostics including reconnectServer(), listToolsetsWithErrors(), and getServerStderr() for per-server operational control
@mastra/[email protected] Breaking risk
Breaking changes
  • MetricType (counter/gauge/histogram) deprecated; metrics now modeled as raw events with aggregation at query time
  • Score schemas use scorerId instead of scorerName
  • ObservabilityBus constructor now requires a config object with cardinalityFilter and autoExtractMetrics; setCardinalityFilter() and enableAutoExtractedMetrics() methods removed
Security fixes
  • CVE-2025-22871 and CVE-2025-61729 resolved via esbuild bump to ^0.27.3
  • CVE-2025-61729
Notable features
  • Observability storage domain with zod-based schemas and in-memory implementations for all observability signals
  • New AgentFSFilesystem workspace provider with Turso/SQLite-backed persistent file storage across sessions
  • Type-safe server route inference utilities via @mastra/server/schemas (RouteMap, InferPathParams, InferBody, InferResponse)
@mastra/[email protected] Breaking risk
Breaking changes
  • LocalFilesystem absolute paths now resolve to real filesystem instead of basePath-relative; use relative paths for workspace files
  • ProcessHandle.pid changed from number to string
Notable features
  • Cloudflare Durable Objects storage adapter with SQLite persistence
  • MCP tool call tracing with MCP_TOOL_CALL span type
@mastra/[email protected] Breaking risk
Breaking changes
  • Minimum Zod version now ^3.25.0 (v3) or ^4.0.0 (v4)
Notable features
  • Dynamic model fallback arrays returning ModelWithRetries[]
  • Standard Schema + Zod v4 compatibility layer
  • requestContext in tracing spans
@mastra/[email protected] Breaking risk
Breaking changes
  • Skill tools renamed: skill-activate → skill, skill-read-reference/skill-read-script/skill-read-asset → skill_read, skill-search → skill_search
Notable features
  • inputExamples field on tool definitions for improved AI model tool-call accuracy
  • MCP client fetch hooks now support RequestContext for request-scoped auth/cookie forwarding
  • memory.deleteThread() and deleteMessages() now automatically clean up orphaned vector embeddings
@mastra/[email protected] Breaking risk
Breaking changes
  • `harness.sendMessage()` now uses `files` instead of `images` parameter; `files` supports any file type, preserves filenames, and auto-decodes text-based files
Notable features
  • Pluggable authentication system (@mastra/core/auth) with OAuth/SSO, session management, and RBAC via new auth provider packages
  • Workspace sandbox upgrades: token-limited output (~3k tokens), ANSI stripping for model context, .gitignore filtering, process cancellation with abortSignal, symlink mount support
  • Workflow execution path tracking with `stepExecutionPath` in results and execution context; smaller optimized logs via deduped payloads
@mastra/[email protected] Breaking risk
Notable features
  • Supervisor pattern for multi-agent coordination with delegation hooks, iteration monitoring, completion scoring, memory isolation, tool approval propagation, context filtering, and bail mechanism
  • LSP diagnostics for workspace edit tools (TypeScript, Python/Pyright, Go/gopls, Rust/rust-analyzer, ESLint)
  • Optional queryVector parameter in vector queries supporting metadata-only retrieval (at least one of queryVector or filter required)
@mastra/[email protected] Breaking risk
Notable features
  • Background process management via SandboxProcessManager with spawn, list, get, and kill operations
  • Workspace.setToolsConfig() for dynamic per-tool enable/disable at runtime without workspace recreation
  • Harness.getObservationalMemoryRecord() provides public access to observational memory record state
@mastra/[email protected] Breaking risk
Breaking changes
  • Harness methods refactored: all now require object parameters instead of positional arguments
  • Method renames: getModes→listModes, getAvailableModels→listAvailableModels, resolveToolApprovalDecision→respondToToolApproval, persistThreadSetting→setThreadSetting, setPermissionCategory→setPermissionForCategory, setPermissionTool→setPermissionForTool
  • HarnessRequestContext interface methods updated to use object parameters
Notable features
  • AST-based workspace edit tool (workspace_ast_edit) for intelligent code transformations including rename, import management, and pattern-based replacements
  • Streaming tool argument previews in real-time with partial JSON parsing showing diffs and file content
  • Built-in task_write and task_check tools automatically injected for structured task tracking
@mastra/[email protected] Breaking risk
Breaking changes
  • Workspace tools no longer return JSON via `outputSchema`; they return raw text instead, with structured metadata emitted as `data-workspace-metadata` chunks
Notable features
  • New Harness class for orchestrating agent applications with modes, state management, built-in tools, subagent support, and Observational Memory integration
  • Workspace filesystem now supports least-privilege access via `allowedPaths` option and `setAllowedPaths()` method for selective directory access
  • New `mastra_workspace_grep` tool for regex-based content search; glob pattern support added to `list_files`, `autoIndexPaths`, and skills discovery
@mastra/[email protected] Breaking risk
Breaking changes
  • @mastra/memory observe() now takes single object parameter (e.g., observe({ threadId, resourceId })) instead of positional arguments
Notable features
  • Datasets and Experiments for evaluation with versioned collections, JSON Schema validation, and SCD-2 versioning
  • Workspace lifecycle split into FilesystemLifecycle and SandboxLifecycle with onInit/onDestroy callbacks
  • Workflow foreach progress streaming with real-time iteration tracking in Studio
@mastra/[email protected] Breaking risk
Breaking changes
  • Removed cloneAgent() from the Agent class
Notable features
  • Observational Memory async buffering
  • Workspace Mounts with CompositeFilesystem
  • Workspace registration and tool context support
[email protected] Breaking risk
Breaking changes
  • Elasticsearch vector document IDs now come from _id; stored id fields no longer written
Notable features
  • Observational Memory for long-running agents
  • Skills.sh ecosystem integration
  • Dynamic tool discovery with ToolSearchProcessor
[email protected] Breaking risk
Breaking changes
  • Google embedding model router removes deprecated text-embedding-004; use google/gemini-embedding-001
Notable features
  • Unified Workspace API
  • Observability and streaming improvements
  • Serverless MCP support
@mastra/[email protected] Breaking risk
Notable features
  • Structured output support for agent.network()
  • Zero-config environment variable support for all exporters
  • Datadog LLM Observability exporter
@mastra/[email protected] Breaking risk
Breaking changes
  • storage.supports property removed
  • StorageSupports type no longer exported
Notable features
  • Storage composition across domains from different adapters
  • onError hook for custom error handling
@mastra/[email protected] Breaking risk

Fix model-level header support for LLM calls and telemetry disabled configuration.

Full changelog

Changelog

@mastra/[email protected]

Patch Changes

  • Fix model-level and runtime header support for LLM calls (#11303)

    This fixes a bug where custom headers configured on models (like anthropic-beta) were not being passed through to the underlying AI SDK calls. The fix properly handles headers from multiple sources with correct priority:

    Header Priority (low to high):

    1. Model config headers - Headers set in model configuration
    2. ModelSettings headers - Runtime headers that override model config
    3. Provider-level headers - Headers baked into AI SDK providers (not overridden)

    Examples that now work:

    // Model config headers
    new Agent({
      model: {
        id: 'anthropic/claude-4-5-sonnet',
        headers: { 'anthropic-beta': 'context-1m-2025-08-07' },
      },
    });
    
    // Runtime headers override config
    agent.generate('...', {
      modelSettings: { headers: { 'x-custom': 'runtime-value' } },
    });
    
    // Provider-level headers preserved
    const openai = createOpenAI({ headers: { 'openai-organization': 'org-123' } });
    new Agent({ model: openai('gpt-4o-mini') });
    
  • Add helpful JSDoc comments to BundlerConfig properties (used with bundler option) (#11300)

  • Fix telemetry disabled configuration being ignored by decorators (#11267)

    The hasActiveTelemetry() function now properly checks the enabled configuration flag before creating spans. Previously, it only checked if a tracer existed (which always returns true in OpenTelemetry), causing decorators to create spans even when telemetry: { enabled: false } was set.

    What changed:

    • Added short-circuit evaluation in hasActiveTelemetry() to check globalThis.__TELEMETRY__?.isEnabled() before checking for tracer existence
    • This prevents unnecessary span creation overhead when telemetry is disabled

    How to use:

    // Telemetry disabled at initialization
    const mastra = new Mastra({
      telemetry: { enabled: false },
    });
    
    // Or disable at runtime
    Telemetry.setEnabled(false);
    

    Breaking changes: None - this is a bug fix that makes the existing API work as documented.


@mastra/[email protected]

Patch Changes

  • Allow for bundler.externals: true to be set. (#11300)

    With this configuration during mastra build all dependencies (except workspace dependencies) will be treated as "external" and not bundled. Instead they will be added to the .mastra/output/package.json file.

  • Fix generate system prompt by updating deprecated function call. (#11075)



Full Changelog: fd37787

2025-12-18 Breaking risk
Notable features
  • A2A protocol execution metadata in message responses
  • New scoring system for prompt handler
@mastra/[email protected] Breaking risk
Breaking changes
  • authenticateToken() now fails safely instead of throwing exceptions
  • Empty or invalid tokens are now rejected early
  • authorizeUser() now performs meaningful security checks
Notable features
  • AI SDK v6 (LanguageModelV3) support with usage normalization
  • Field filtering and withNestedWorkflows control for workflow execution results
  • Request context properly forwarded from middleware in chat and network routes
@mastra/[email protected] Breaking risk
Breaking changes
  • @mastra/client-js: Run methods (stream, resumeAsync, restartAsync, timeTravelAsync) cannot be called directly on workflow instances; must call workflow.createRun() first to get a Run instance
Notable features
  • Workflow errors now preserve custom properties (statusCode, responseHeaders, cause chains) for error-specific recovery logic
  • Client-side error deserialization enables instanceof Error checks and proper error handling using custom error types
  • Fixed duplicate assistant messages in useChat when memory is enabled
2025-12-10 Bug fix
Notable features
  • Added virtual check for tsconfigpaths plugin for CI environments
@mastra/[email protected] Breaking risk
Breaking changes
  • prepareStep messages format changed from AI SDK v5 model messages to MastraDBMessage format - use messageList.get.all.aiV5.model() if you need the old format
Notable features
  • Processor retry mechanism with LLM feedback via processOutputStep
  • Workflow tripwire status with detailed processor rejection information
  • Processor workflow composition - write processors using workflow primitives
@mastra/[email protected] Breaking risk
Breaking changes
  • RuntimeContext type renamed to ServerContext in route handler types
  • playground and isDev options removed from server adapter constructors
  • createTestRuntimeContext renamed to createTestServerContext in test utilities
Notable features
  • Typed structured output schema inference in agent workflow steps enabling type-safe chaining
  • Delete workflow run API for workflow management
  • Data persistence for custom chunks from writer.custom() in message storage
@mastra/[email protected] Mixed
Notable features
  • Agents can be persisted to database and dynamically instantiated at runtime with getStoredAgentById() and listStoredAgents() APIs
  • Added withMastra() wrapper for AI SDK models with input/output processors and memory integration
@mastra/[email protected] Mixed
Notable features
  • Client-js now supports z.record() and z.date() through unified zodToJsonSchema implementation
  • Fixed writer.custom() calls during workflow resume operations
  • Added flag to skip sessions and streaming in serverless MCP
@mastra/[email protected] Breaking risk
Breaking changes
  • setState is now async and must be awaited
Notable features
  • saveScore ID persistence fix
  • Human-in-the-loop workflow support
@mastra/[email protected] New feature
Notable features
  • Custom fetch function support in MastraClient
  • Partial response support for agents and workflows
  • Workflow time travel capability

Beta — feedback welcome: [email protected]