AgentController
The AgentController feature is in beta stage and subject to breaking changes in minor versions until it graduates from its beta status.
The AgentController class is a shared host for one or more Session instances. Initialize the controller, create a session, then use session.* APIs for conversation state and run control.
For a guided introduction, see the AgentController overview.
Usage exampleDirect link to Usage example
The following example initializes a controller and creates a session. It subscribes to session events before sending a message.
import { Agent } from '@mastra/core/agent'
import { AgentController } from '@mastra/core/agent-controller'
import { Workspace } from '@mastra/core/workspace'
const agent = new Agent({
id: 'coding-agent',
name: 'Coding agent',
instructions: 'Help with software engineering tasks.',
model: 'anthropic/claude-sonnet-4-6',
})
const controller = new AgentController({
id: 'coding-controller',
agent,
workspace: new Workspace({ id: 'coding-workspace' }),
modes: [{ id: 'build', name: 'Build', metadata: { default: true } }],
})
await controller.init()
const session = await controller.createSession({ resourceId: 'project-42' })
const unsubscribe = session.subscribe(event => {
if (event.type === 'message_update') {
console.log(event.message)
}
})
await session.sendMessage({ content: 'Review the project structure.' })
unsubscribe()
Constructor parametersDirect link to Constructor parameters
id:
modes:
id:
name?:
defaultModelId?:
description?:
instructions?:
transitionsTo?:
submit_plan suspension.availableTools?:
metadata?:
metadata.default: true marks the default mode.tools?:
additionalTools.additionalTools?:
tools.agent?:
agent parameter.default?:
metadata.default or defaultModeId.agent?:
resourceId?:
id.storage?:
stateSchema?:
session.state updates.initialState?:
memory?:
defaultModeId?:
instructions?:
tools?:
workspace?:
browser?:
channels?:
intervalHandlers?:
init() and stopped by stopIntervals() or destroy().idGenerator?:
modelUseCountProvider?:
modelUseCountTracker?:
session.model.switch().subagents?:
subagent tool.id:
name:
description:
instructions:
tools?:
allowedControllerTools?:
allowedWorkspaceTools?:
defaultModelId?:
maxSteps?:
stopWhen?:
forked?:
gateways?:
omConfig?:
disableBuiltinTools?:
toolCategoryResolver?:
pubsub?:
threadLock?:
observability?:
PropertiesDirect link to Properties
id:
MethodsDirect link to Methods
SessionsDirect link to Sessions
createSession(options)Direct link to createsessionoptions
Get or create the live session registered for the (resourceId, scope) pair. Call init() before this method.
const session = await controller.createSession({
resourceId: 'project-42',
scope: 'editor-window-1',
threadId: 'thread-7',
})
The same resourceId and scope return the same Session instance. A different scope creates an isolated session for the same resource. When threadId is supplied, the method switches a cached session to that thread or creates the thread when it doesn't exist.
resourceId?:
resourceId or controller id.scope?:
threadId?:
id?:
id.ownerId?:
id.workspace?:
browser?:
requestContext?:
Returns: Promise<Session<TState>>
getSessionByResource(resourceId, scope?)Direct link to getsessionbyresourceresourceid-scope
Return the live session registered for a resource and optional scope.
const session = await controller.getSessionByResource('project-42', 'editor-window-1')
Returns: Promise<Session<TState> | undefined>
setResourceId(session, { resourceId })Direct link to setresourceidsession--resourceid-
Move a live session to another resource and clear its active thread binding.
await controller.setResourceId(session, { resourceId: 'project-43' })
getKnownResourceIds(session)Direct link to getknownresourceidssession
List resource identifiers present in stored threads.
const resourceIds = await controller.getKnownResourceIds(session)
Returns: Promise<string[]>
LifecycleDirect link to Lifecycle
init()Direct link to init
Initialize shared storage, workspace services, and configured interval handlers. Repeated calls reuse the same initialization promise.
await controller.init()
destroy()Direct link to destroy
Stop controller-owned interval handlers. This doesn't destroy Sessions created by the controller.
await controller.destroy()
Modes and agentsDirect link to Modes and agents
listModes()Direct link to listmodes
Return the configured mode definitions.
const modes = controller.listModes()
Returns: AgentControllerMode[]
getCurrentAgent(session)Direct link to getcurrentagentsession
Return the backing agent for the session's active mode.
const agent = controller.getCurrentAgent(session)
Returns: Agent
Workspace and browserDirect link to Workspace and browser
hasWorkspace()Direct link to hasworkspace
Report whether the controller has a static, dynamic, or object-based workspace configuration.
if (controller.hasWorkspace()) {
console.log('Workspace configured')
}
Returns: boolean
isWorkspaceReady()Direct link to isworkspaceready
Report whether the controller-level workspace is ready.
const ready = controller.isWorkspaceReady()
Returns: boolean
getWorkspace()Direct link to getworkspace
Return a static controller workspace. Dynamic workspace factories return undefined until resolved.
const workspace = controller.getWorkspace()
Returns: Workspace | undefined
resolveWorkspace({ session, requestContext? })Direct link to resolveworkspace-session-requestcontext-
Resolve a dynamic workspace for a session and cache the result on the controller.
const workspace = await controller.resolveWorkspace({ session, requestContext })
Returns: Promise<Workspace | undefined>
setBrowser(browser)Direct link to setbrowserbrowser
Replace the controller browser and propagate it to the backing agents.
controller.setBrowser(browser)
Mastra and channelsDirect link to Mastra and channels
getMastra()Direct link to getmastra
Return the parent Mastra instance or the internal instance created by init().
const mastra = controller.getMastra()
Returns: Mastra | undefined
getChannels()Direct link to getchannels
Return the configured chat channel integration.
const channels = controller.getChannels()
Returns: AgentControllerChannels | null
ModelsDirect link to Models
getCurrentModelAuthStatus(session)Direct link to getcurrentmodelauthstatussession
Return authentication status for the session's selected model.
const status = await controller.getCurrentModelAuthStatus(session)
Returns: Promise<ModelAuthStatus>
listAvailableModels()Direct link to listavailablemodels
List models from the configured and built-in gateways. Results are cached briefly and sorted with usage data when modelUseCountProvider is configured.
const models = await controller.listAvailableModels()
Returns: Promise<AvailableModel[]>
invalidateAvailableModelsCache()Direct link to invalidateavailablemodelscache
Clear the available-model cache.
controller.invalidateAvailableModelsCache()
Observational memory and permissionsDirect link to Observational memory and permissions
loadOMProgress(session)Direct link to loadomprogresssession
Load stored observational memory progress for the active thread and emit an om_status event.
await controller.loadOMProgress(session)
getObservationalMemoryRecord(session)Direct link to getobservationalmemoryrecordsession
Return the observational memory record for the active thread.
const record = await controller.getObservationalMemoryRecord(session)
Returns: Promise<ObservationalMemoryRecord | null>
getToolCategory({ toolName })Direct link to gettoolcategory-toolname-
Resolve the permission category for a tool.
const category = controller.getToolCategory({ toolName: 'execute_command' })
Returns: ToolCategory | null
IntervalsDirect link to Intervals
registerInterval(handler)Direct link to registerintervalhandler
Start or replace a periodic handler.
controller.registerInterval({
id: 'refresh',
intervalMs: 60_000,
handler: async () => refreshData(),
})
removeInterval({ id })Direct link to removeinterval-id-
Stop one interval and run its optional shutdown callback.
await controller.removeInterval({ id: 'refresh' })
stopIntervals()Direct link to stopintervals
Stop all intervals and run their optional shutdown callbacks.
await controller.stopIntervals()