Mastra Agent Controller vs. LangChain Deep Agents

Compare Mastra Agent Controller and LangChain Deep Agents on sessions, tool approvals, memory, subagents, and observability, with a TypeScript quickstart.

Sam Bhagwat

Written by

Sam Bhagwat

Oct 1, 2026

·

13 min read

When you build an agent for multi-step tasks, you need to track its progress, decide when to ask for approval, and retain enough context for it to continue.

That means handling state, permissions, and execution alongside the model calls.

Mastra Agent Controller and LangChain Deep Agents provide much of that infrastructure. If you work in TypeScript, Mastra gives you a native runtime. Deep Agents is available in both Python and JavaScript/TypeScript, with capabilities built on LangChain and LangGraph.

What is Mastra Agent Controller?

Mastra Agent Controller is a TypeScript runtime for managing an agent across an ongoing conversation. A controller hosts the agent, with three separate responsibilities underneath it:

  • Session: handles turns, tool approvals, and live events for a user or task.
  • Storage: persists the thread and its messages.
  • Memory: selects the history passed to the model on later turns.

That separation gives you control over context. It also means storing a conversation does not automatically make the agent remember it.

Agent Controller includes user questions, plan approval, task tracking, and subagents. Modes change the agent's instructions and tools within the same conversation.

It ships inside @mastra/core and is still in beta, with possible breaking changes without a major version bump. The Agent Controller overview covers its APIs.

What is LangChain Deep Agents?

Deep Agents is an agent library built on LangChain and LangGraph. In Python, create_deep_agent includes:

  • Filesystem tools for intermediate work and context offloading.
  • Subagents for delegated tasks.
  • Summarization for longer conversations.

Skills supply instructions from files, while structured todo planning is optional middleware.

You invoke the agent with messages and a thread ID. A LangGraph checkpointer saves its state between invocations, including approval interrupts, and LangGraph handles streaming.

The package is deepagents. A JavaScript implementation runs on LangGraph for JavaScript, so you can use either library in TypeScript.

Mastra Agent Controller vs. Deep Agents at a glance

CapabilityMastra Agent ControllerLangChain Deep Agents
LanguageTypeScript-nativePython and JavaScript
Application APICreate a session, subscribe to events, and send turnsInvoke an agent with messages and a thread ID
Tool approvalAllow, ask, or deny by tool or category; live session grantsConfigure tool interrupts and resume the graph with a review decision
PersistenceStorage persists messages; memory selects model contextA checkpointer persists thread-scoped graph state
SubagentsDeclared types with tools, model, and step limits; session lifecycle eventsIsolated subagents, with general-purpose and specialized definitions
Context managementObservational memory can compress history in the backgroundSummarization and filesystem offloading during execution
Additional controlsModes, user questions, plan approval, and task trackingFilesystem tools, skills, and optional todo planning in Python

Mastra Agent Controller vs. Deep Agents: A feature-by-feature comparison

Once you get past the basic agent loop, you’ll see the differences clearly. How do you pause for approval? What survives a restart? And what happens when the conversation gets too long?

Here’s how each handles those parts.

1. Sessions, execution, and agent modes

Mastra gives you a live session through which you manage the agent. Messages, approvals, mode changes, and progress events all belong to that session. Modes let you change instructions and available tools without starting another conversation.

Deep Agents exposes the agent as a LangGraph graph. You invoke it with a thread ID, stream its execution, and invoke it again to continue or resume interrupted work. The checkpointer maintains continuity between those calls.

Application controlMastra Agent ControllerDeep Agents
Main interfaceA live session for turns, approvals, and eventsGraph invocations associated with a thread ID
Changing behaviorModes change instructions and tools within the conversationAgent configuration and middleware define behavior
Planning and interactionBuilt-in user questions, plan approval, and task trackingTool interrupts for review; optional todo middleware in Python

Verdict: Mastra's built-in modes change the shared agent's instructions and tools without replacing the Session or thread. This lets users move from read-only planning to approved execution without starting over or wiring up a handoff between separate agents. Deep Agents manages behavior with continuity provided by LangGraph checkpoints.

2. Tool permissions and human approval

Mastra evaluates tool calls against permission policies. You can allow, ask, or deny by tool or category, and grant access for the remainder of a live session.

Deep Agents uses configured tool interrupts. When a call needs review, execution pauses and returns control to you. You resume the graph with an approval, edit, or rejection decision. The current Python API also supports conditional interrupts, and its filesystem tools have path-based permission rules.

Permission behaviorMastra Agent ControllerDeep Agents
Policy scopeTool and category rules, plus live session grantsTool review, conditional interrupts, and filesystem permission rules
Approval handlingRespond through the active sessionResume the checkpointed graph with a decision

Mastra's live approval gate and session grants do not automatically survive a process restart, and resumable tool suspensions are separate. The Mastra approval docs explain that distinction, while the Deep Agents approval docs cover checkpointed and conditional interrupts.

Verdict: Choose Mastra when you want tool-category policies and approval decisions tied to a live session. Choose Deep Agents when you want review to pause a checkpointed graph that you resume in a later invocation. Both support human review; compare the policy scope and restart behavior your application needs.

3. Persistence and conversation memory

Mastra separates what you store from what you send back to the model. Storage keeps thread messages, while memory selects the history included in later requests. Our blog post on AI Agent Memory explains how stored history, working memory, semantic recall, and observational memory contribute to that context.

Deep Agents uses a LangGraph checkpointer to persist thread-scoped graph state. You continue with the same thread ID, restoring the messages and execution state needed for the next invocation.

Persistence concernMastra Agent ControllerDeep Agents
Conversation historyStored thread messagesMessages in checkpointed graph state
Model contextSelected by the memory configurationManaged within the agent's message and context-processing flow
Continuing after a restartBind a new session to the stored threadInvoke with the same thread ID and persistent checkpointer
Live execution stateSession state is distinct from stored historyCheckpoints retain the state used to resume graph execution

With Mastra, configure both storage and memory: your UI can display stored messages even when those messages are absent from the model's context. With Deep Agents, choose a persistent checkpointer if you need state to survive a restart; an in-memory one loses its contents when the process exits.

For either product, distinguish conversation history from execution recovery. Reopening a conversation and resuming a pending tool operation place different demands on your runtime.

Verdict: Choose Mastra if you want to configure stored history and model-visible memory separately. Choose Deep Agents if saving and resuming graph execution is central to your application. Either way, configure durable storage before relying on continuity across restarts.

4. Subagent configuration and context

Both products can delegate work to subagents. The differences are in how you define their responsibilities, what context they receive, and how you observe them. Mastra's subagent documentation covers delegation controls, request context, and lifecycle hooks.

Delegation controlMastra Agent ControllerDeep Agents
DefinitionDeclare types with instructions, tools, and optional model and step budgetUse a general-purpose spawner or declare specialized subagents
Context handlingDelegation hooks and request-context controlsIsolated subagent context with a delegated task
VisibilityDedicated session events for start and completionSpawner tool calls, with additional detail through LangGraph streaming

Mastra gives you hooks to adjust delegation and inspect the result. Its request context carries application data across that boundary; it is separate from the model's conversation history.

Deep Agents' isolated context keeps child tasks separate from the parent's accumulated history, so each delegation needs enough information to complete the task. You can use LangGraph streaming when the spawner call alone is not enough for your UI.

Verdict: Choose Mastra if you need delegation hooks and subagent lifecycle events integrated with your session. Choose Deep Agents if you want to start with a general-purpose spawner and add specialized subagents as needed. With either, define what each child task needs to know and what it should return.

5. Context compaction and access to history

Both reduce the context sent to the model as a conversation grows. They differ in when compression happens and how older information remains available.

Context behaviorMastra observational memoryDeep Agents summarization
CompressionAn observer creates dated observations; a reflector compresses those observations laterThe agent summarizes older messages
TimingBackground observation with buffering enabledSummarization during execution when the threshold is reached
Older informationObservations enter model context; original messages remain in storageFull history is written to a file the agent can read again
VisibilityStructured memory and buffering eventsSummary and history file available during execution

Mastra's background buffering prepares observations before the context threshold is reached. Its async-buffering release post explains how buffered results activate and which streaming events report the work. Deep Agents performs summarization during execution and retains a readable history file.

For your workload, I would check whether background compression keeps up with incoming turns and whether the agent retrieves omitted details when it needs them.

Mastra also retains the original messages. Its observational memory documentation describes an optional recall tool that lets the agent retrieve source messages behind observations. The observational memory announcement explains the observer/reflector design.

Verdict: Choose Mastra if you want background observation and reflection to manage context in your TypeScript application. Choose Deep Agents if file-based context offloading and summarization fit how your agent works. Both can preserve source history; verify how your agent retrieves details after compression.

6. Observability and UI integration

Mastra exposes a session event stream that brings together the agent's messages, tools, approvals, and delegated work. Deep Agents exposes execution through LangGraph streaming, message metadata, and interrupt payloads.

Observability surfaceMastra Agent ControllerDeep Agents
Live dataRun lifecycle, messages, tool input, approvals, suspensions, subagents, token usage, and compactionMessages, LangGraph node and streaming events, and interrupts
Application integrationSubscribe to the sessionConsume the relevant graph streams and results
TracingMastra traces, exporters, and OpenTelemetry integrationLangSmith hosted tracing

With Mastra, you can build a progress view around the session subscription. With Deep Agents, you consume graph streams and interrupt payloads to show execution and approval state. Your existing UI and tracing integrations will affect how much code either approach requires.

Beyond session events, Mastra's tracing documentation covers spans, exporters, and OpenTelemetry integration. If you already use LangSmith, Deep Agents can use that hosted tracing alongside LangGraph streaming.

Verdict: Choose Mastra if you want to build your progress and approval UI around one session event stream. Choose Deep Agents if you already use LangGraph streaming and LangSmith. I would weigh the integrations you already have here: they can matter more than the number of events either library exposes.

Mastra Agent Controller or LangChain Deep Agents, which one should you use?

  • If you're building in TypeScript, start with Mastra Agent Controller when your agent shares an ongoing conversation with a user. Sessions, permission rules, and events reduce the application code you need around the agent. The costs are more configuration and a beta API.
  • If you're building in Python, start with Deep Agents. LangChain and LangGraph provide the tools, state, and pause/resume behavior together. You still need to configure approvals and durable storage for the operations that require them.

If you're already using LangGraph in TypeScript, Deep Agents' JavaScript package is another option.

But I would compare Mastra's session and permission APIs with your existing setup, then validate approval and restart behavior against your application's requirements.

Get started with Mastra Agent Controller

If you're ready to try Mastra for your agent workflows, here's a quick starter guide. You'll create an agent, open a session, and stream your first response using Agent Controller.

Install the packages

In a TypeScript project using ES modules ("type": "module" in package.json), install the latest releases:

npm install @mastra/core@latest @mastra/libsql@latest zod@latest
npm install --save-dev tsx@latest typescript@latest @types/node@latest

Add your model provider's key to .env:

OPENAI_API_KEY=your-api-key

Create the agent and controller

Create agent-controller.ts and import the agent, controller, and storage classes:

import { Agent } from '@mastra/core/agent';
import { AgentController } from '@mastra/core/agent-controller';
import { LibSQLStore } from '@mastra/libsql';
 
const controller = new AgentController({
  id: 'release-planning',
  agent: new Agent({
    id: 'release-assistant',
    name: 'Release assistant',
    instructions:
      'Help developers prepare releases. Give concise, actionable checklists.',
    model: 'openai/gpt-5.6-sol',
  }),
  storage: new LibSQLStore({
    id: 'release-history',
    url: 'file:./release-history.db',
  }),
});
 
await controller.init();

The model ID matches the current quickstart. Storage writes conversation history to a local database; to include that history in subsequent model calls, add a memory configuration.

Open a session and stream a response

Append this to the same file:

const releaseSession = await controller.createSession({
  resourceId: 'developer-1',
});
 
const stopListening = releaseSession.subscribe(update => {
  if (update.type !== 'message_update') return;
  if (update.event.type === 'text-delta') {
    process.stdout.write(update.event.delta);
  }
});
 
try {
  await releaseSession.sendMessage({
    content: 'Give me a five-step checklist for releasing a TypeScript library.',
  });
  process.stdout.write('\n');
} finally {
  stopListening();
}

Run it with your .env loaded:

npx tsx --env-file=.env agent-controller.ts

The response streams to your terminal. In an application, the same subscription can feed your UI. From here, add tool approval policies or agent modes when you need more control over what the agent does.

Ready to take it further? Sign up to try Mastra.

Share on X or LinkedIn
Sam Bhagwat

Sam Bhagwat is the founder and CEO of Mastra. He co-founded Gatsby, which was used by hundreds of thousands of developers. A Stanford graduate and veteran of web development, he authored 'Principles of Building AI Agents' (2025).

All articles by Sam Bhagwat →