github mastra-ai/mastra @mastra/core@1.30.0
April 30, 2026

7 hours ago

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/core@1.30.0

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/client-js@1.15.2

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/editor@0.7.22

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/hono@1.4.10

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/inngest@1.3.0

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/memory@1.17.4

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/observability@1.10.3

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/playground-ui@24.0.2

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/redis@1.1.0

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/server@1.30.0

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/upstash@1.1.0

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:

Don't miss a new mastra release

NewReleases is sending notifications on new releases.