Agent class
The Agent class is the foundation for creating AI agents in Mastra. It provides methods for generating responses, streaming interactions, and handling voice capabilities.
Usage examplesDirect link to Usage examples
Basic string instructionsDirect link to Basic string instructions
Passing instructions as a string or array of strings is the simplest way to set up an agent. This is useful for straightforward use cases where you need to provide a prompt without additional configuration.
import { Agent } from '@mastra/core/agent'
// String instructions
export const agent = new Agent({
id: 'test-agent',
name: 'Test Agent',
instructions: 'You are a helpful assistant that provides concise answers.',
model: 'openai/gpt-5.5',
})
// System message object
export const agent2 = new Agent({
id: 'test-agent-2',
name: 'Test Agent 2',
instructions: {
role: 'system',
content: 'You are an expert programmer',
},
model: 'openai/gpt-5.5',
})
// Array of system messages
export const agent3 = new Agent({
id: 'test-agent-3',
name: 'Test Agent 3',
instructions: [
{ role: 'system', content: 'You are a helpful assistant' },
{ role: 'system', content: 'You have expertise in TypeScript' },
],
model: 'openai/gpt-5.5',
})
Provider-specific configurationsDirect link to Provider-specific configurations
Each model provider also enables a few different options, including prompt caching and configuring reasoning. You can set providerOptions on the instruction level to set different caching strategy per system instruction/prompt.
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'core-message-agent',
name: 'Core Message Agent',
instructions: {
role: 'system',
content: 'You are a helpful assistant specialized in technical documentation.',
providerOptions: {
openai: {
reasoningEffort: 'low',
},
},
},
model: 'openai/gpt-5.5',
})
Mixed instruction formatsDirect link to Mixed instruction formats
import { Agent } from '@mastra/core/agent'
// This could be customizable based on the user
const preferredTone = {
role: 'system',
content: 'Always maintain a professional and empathetic tone.',
}
export const agent = new Agent({
id: 'multi-message-agent',
name: 'Multi Message Agent',
instructions: [
{ role: 'system', content: 'You are a customer service representative.' },
preferredTone,
{
role: 'system',
content: 'Escalate complex issues to human agents when needed.',
providerOptions: {
anthropic: { cacheControl: { type: 'ephemeral' } },
},
},
],
model: 'anthropic/claude-sonnet-4-6',
})
Thread signalsDirect link to Thread signals
Use Agent signals to send real-time input and context into a memory thread. Message APIs are for user-authored input. sendSignal() is the lower-level API for system-generated context.
When the target thread is running, sendMessage() delivers the message into the active agent loop. When the thread is idle, Mastra starts a stream with the message as the first input by default.
const subscription = await agent.subscribeToThread({
resourceId: 'user-123',
threadId: 'thread-abc',
})
void (async () => {
for await (const chunk of subscription.stream) {
console.log(chunk)
}
})()
agent.sendMessage('Use the latest customer note too.', {
resourceId: 'user-123',
threadId: 'thread-abc',
ifIdle: {
streamOptions: {
maxSteps: 3,
},
},
})
Use attributes to identify different users in a shared thread. The attributes are rendered as XML so the model can distinguish who said what:
agent.sendMessage(
{
contents: 'Can we simplify the API surface?',
attributes: { name: 'Devin', from: 'slack' },
},
{ resourceId: 'user-123', threadId: 'thread-abc' },
)
The model receives this as:
<user name="Devin" from="slack">Can we simplify the API surface?</user>
Use ifActive.attributes and ifIdle.attributes when the message should carry different context depending on whether the thread is currently running:
agent.sendMessage(
{
contents: 'Also cover the edge cases.',
attributes: { source: 'chat' },
},
{
resourceId: 'user-123',
threadId: 'thread-abc',
ifActive: { attributes: { delivery: 'while-active' } },
ifIdle: { attributes: { delivery: 'new-message' } },
},
)
When the thread is active, the model sees:
<user source="chat" delivery="while-active">Also cover the edge cases.</user>
When the thread is idle, the model sees:
<user source="chat" delivery="new-message">Also cover the edge cases.</user>
The UI sees the message contents and can also read attributes and metadata off the signal message for custom rendering (e.g. showing user names, avatars, or platform badges).
sendMessage(message, options)Direct link to sendmessagemessage-options
Sends a user message to an active run or memory thread. Use this when the active agent should receive the message immediately.
message:
options?:
runId?:
resourceId?:
threadId?:
ifActive?:
behavior?:
attributes?:
ifIdle?:
behavior?:
streamOptions?:
attributes?:
Set ifIdle.behavior to wake and pass ifIdle.streamOptions when an idle thread should start a new stream with custom execution options:
agent.sendMessage('Continue with the next step.', {
resourceId: 'user-123',
threadId: 'thread-abc',
ifIdle: {
behavior: 'wake',
streamOptions: {
maxSteps: 3,
},
},
})
Returns { accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void> }. persisted is only present for persist behavior and resolves when Mastra finishes writing the message to memory.
queueMessage(message, options)Direct link to queuemessagemessage-options
Queues a user message for the next turn on a thread. If the thread is active, Mastra waits for the active run to finish, then starts a new run with the queued message. If the thread is idle, Mastra starts a run immediately.
agent.queueMessage('Also check whether the tests need updates.', {
resourceId: 'user-123',
threadId: 'thread-abc',
})
queueMessage() accepts the same message and options shape as sendMessage() and returns { accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void> }.
sendSignal(signal, options)Direct link to sendsignalsignal-options
Sends a signal to an active run or memory thread.
signal:
options?:
runId?:
resourceId?:
threadId?:
ifActive?:
behavior?:
attributes?:
ifIdle?:
behavior?:
streamOptions?:
attributes?:
Returns { accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void> }. persisted is only present for persist behavior and resolves when Mastra finishes writing the signal to memory.
sendStateSignal(state, options)Direct link to sendstatesignalstate-options
Sends named, thread-scoped state context to an active run or memory thread. Use this when an external producer owns durable context that changes over time, such as browser state, editor state, or watcher output.
const result = await agent.sendStateSignal(
{
id: 'browser',
mode: 'snapshot',
cacheKey: 'browser:https://example.com:3-tabs',
contents: 'Browser is open. Active tab URL: https://example.com. 3 open tabs.',
value: {
activeUrl: 'https://example.com',
tabCount: 3,
open: true,
},
},
{
resourceId: 'user-123',
threadId: 'thread-abc',
},
)
state:
id:
cacheKey:
contents:
mode?:
value?:
delta?:
attributes?:
metadata?:
tagName?:
options:
Returns { accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void>, skipped?: false } when Mastra accepts new state. Returns { accepted: true, skipped: true, reason: 'unchanged' } when the same cacheKey and mode are already current for the state lane.
sendNotificationSignal(notification, options)Direct link to sendnotificationsignalnotification-options
Creates or coalesces a notification inbox record, resolves the notification delivery policy, and sends a notification signal when the decision is immediate.
const result = await agent.sendNotificationSignal(
{
source: 'github',
kind: 'ci-status',
priority: 'high',
summary: 'CI failed on main: 3 tests failed.',
dedupeKey: 'github:acme/app:main:ci',
},
{
resourceId: 'user-123',
threadId: 'thread-abc',
},
)
notification:
source:
kind:
summary:
priority?:
payload?:
dedupeKey?:
coalesceKey?:
attributes?:
metadata?:
options:
resourceId:
threadId:
ifIdle?:
streamOptions?:
Returns { accepted: true, record: NotificationRecord, decision: NotificationDeliveryDecision, runId?: string, signal?: CreatedAgentSignal, persisted?: Promise<void> }. record is the stored inbox record. decision is the delivery-policy result. signal and runId are present when ingress emits a signal immediately, including the immediate summary emitted for active high-priority notifications. persisted is present when the emitted signal is persisted without waking an idle thread.
Default delivery is priority-aware. urgent notifications deliver immediately. high notifications deliver immediately when the thread is idle; when the thread is active, Mastra emits a summary immediately and keeps deliverAt for later full delivery when the thread is idle. medium notifications deliver immediately when idle and batch into summaries when active. low notifications batch into summaries in both active and idle threads; idle low-priority summaries reach subscribers without waking the model loop. For the full flow, visit Signals.
Configure notifications.deliveryPolicy on the agent when some notifications should wait for a different dispatch window or summary rollup:
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: 'Help the user triage updates.',
model: 'openai/gpt-5.5',
notifications: {
deliveryPolicy: {
priorities: {
urgent: 'deliver',
},
decide: ({ record }) => {
if (record.priority === 'low') {
return {
action: 'summarize',
summaryAt: new Date(Date.now() + 30 * 60 * 1000),
}
}
},
},
},
})
subscribeToThread(options)Direct link to subscribetothreadoptions
Subscribes to raw stream chunks for a memory thread. Use this before calling sendMessage(), queueMessage(), or sendSignal() when you need to render stream output, observe signal echoes, or abort the active run.
options:
resourceId?:
threadId:
Returns an AgentThreadSubscription object with these members:
stream:
activeRunId:
abort:
unsubscribe:
Constructor parametersDirect link to Constructor parameters
id?:
name:
description?:
metadata?:
instructions:
model:
agents?:
tools?:
transform?:
workflows?:
defaultOptions?:
defaultGenerateOptionsLegacy?:
defaultStreamOptionsLegacy?:
mastra?:
scorers?:
memory?:
notifications?:
deliveryPolicy?:
voice?:
inputProcessors?:
outputProcessors?:
maxProcessorRetries?:
requestContextSchema?:
editor?:
Editor overridesDirect link to Editor overrides
When you register the MastraEditor, the editor field controls which parts of a code-defined agent can be changed through the editor. Fields owned by code are read-only in Studio and are stripped from saved overrides.
editor?:
The agent's id, name, and model always come from code and can't be overridden through the editor. See the Editor overview for usage.