We're excited to ship Durable Agents. Durable Agents can survive client disconnects, browser refreshes, or network blips.
Run multiple requests in parallel, watch them or leave them in flight and come back later. Or connect from a different client and observe in-progress or completed streams from the start.
Before Durable Agents, an agent stream was tied to the HTTP connection that started it. And Mastra's storage layer persisted on a per-turn (agents) or per-step (workflow) layer. But if the connection dropped, there was no way of resuming from the point it disconnected. You had to go back to the beginning of the turn or step.
The default implementation, createDurableAgent(), uses a server cache to persist the stream and routes events through Mastra's event system letting you observe a stream by subscribing using the runId. Durable agents wrap the agentic loop in a workflow.
Over time, we may decide to add this behavior as an agent default as well.
Get started
Install a cache backend. This example uses Upstash:
npm install @mastra/redis ioredisRequires @mastra/core@1.45.0 or later, added in PR #12557.
Configure your Mastra instance with cache and pubsub:
import { Mastra } from "@mastra/core/mastra";
import { EventEmitterPubSub } from "@mastra/core/events";
import { RedisServerCache } from "@mastra/redis";
import Redis from "ioredis";
import { durableVirtualDr } from "./agents/durable-virtual-dr";
export const mastra = new Mastra({
// ...
agents: { durableVirtualDr },
cache: new RedisServerCache({ client: new Redis(process.env.REDIS_URL!) }),
pubsub: new EventEmitterPubSub()
});Create a regular Mastra agent:
import { Agent } from "@mastra/core/agent";
import { medicalResearchTool } from "../tools/medical-research";
export const virtualDr = new Agent({
id: "virtualDr",
name: "Virtual Dr",
model: "anthropic/claude-opus-4-8",
instructions: "You are a careful medical research assistant...",
tools: { medicalResearchTool }
});Wrap your agent with createDurableAgent(). The agentic loop runs inside the HTTP request that called .stream(), with chunks cached as they're produced:
import { createDurableAgent } from "@mastra/core/agent/durable";
import { virtualDr } from "./virtual-dr";
export const durableVirtualDr = createDurableAgent({ agent: virtualDr });For fire-and-forget execution that outlives the HTTP request, use createEventedAgent() instead.
Observe using @mastra/client-js
Install the Mastra Client:
npm install @mastra/client-jsCall .stream() to start a run. The returned response exposes .processDataStream() which you can use to long stream chunks as they arrive:
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient({ baseUrl: "https://your-backend.example" });
const agent = client.getAgent("durableVirtualDr");
const response = await agent.stream([{ role: "user", content: "What's the first-line treatment for adult migraine?" }], { runId });
await response.processDataStream({ onChunk: (chunk) => console.log(chunk) });Connect and observe a run using .observe(runId):
const response = await agent.observe({ runId });
await response.processDataStream({ onChunk: (chunk) => console.log(chunk) });Durable agents also support tool approval for human-in-the-loop pauses, untilIdle streaming across background-task continuations, multi-client observe on the same runId, and createInngestAgent() for durable execution that survives backend crashes with automatic retries.
For more information and full configuration options, see:
- Durable agents overview
- DurableAgent reference
- createInngestAgent reference
- RedisServerCache reference
- Inngest deployment guide
- Background tasks
Appendix
Durable agents stream the same AgentChunkType events as a regular Agent.
The main event families:
- Lifecycle:
start,step-start,step-finish,finish,abort,error - Text:
text-start,text-delta,text-end - Reasoning:
reasoning-start,reasoning-delta,reasoning-end,reasoning-signature,redacted-reasoning - Tools:
tool-call,tool-call-input-streaming-start,tool-call-delta,tool-call-input-streaming-end,tool-result,tool-error,tool-call-approval,tool-call-suspended,tool-output - Output:
response-metadata,source,file,raw,object,object-result,step-output - Background tasks (with
untilIdle):background-task-started,background-task-running,background-task-progress,background-task-completed,background-task-failed - Misc:
watch,tripwire,is-task-complete,goal
