AgentController
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 exampleUsage 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' && event.event.type === 'text-delta') {
process.stdout.write(event.event.delta)
}
})
await session.sendMessage({ content: 'Review the project structure.' })
unsubscribe()
A message lifecycle starts with the initial message in message_start. Compact message_update events address the message by ID and carry text, reasoning, or part changes. message_end carries the ID to finalize.
Constructor parametersConstructor 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?:
resolveSubagentModel?:
gateways?:
omConfig?:
defaultObserverModelId?:
observerModel?:
defaultReflectorModelId?:
reflectorModel?:
resolveAutoModelId?:
defaultObservationThreshold?:
defaultReflectionThreshold?:
disableBuiltinTools?:
toolCategoryResolver?:
pubsub?:
threadLock?:
observability?:
PropertiesProperties的直接链接
id:
MethodsMethods的直接链接
SessionsSessions的直接链接
createSession(options)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?:
createInitialThread?:
false to start the session without a thread; the first message or session.thread.ensureId() creates it, so unused sessions leave no empty thread behind.id?:
id.ownerId?:
id. New threads use it as their initial owner, but later transfers do not change this value.workspace?:
browser?:
requestContext?:
Returns: Promise<Session<TState>>
getSessionByResource(resourceId, scope?)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>
onSessionCreated(listener, options?)onsessioncreatedlistener-options的直接链接
Subscribe to process-local notifications after createSession() materializes a new live session, with isolated listener errors prevented from affecting other listeners. Call the returned function to unsubscribe.
By default listeners are fire-and-forget. Pass { blocking: true } to make createSession() await the listener before resolving the new session, so the host can prepare session state before the caller can start a run. Blocking listeners run sequentially in registration order, before fire-and-forget listeners are notified. A blocking listener must not call createSession() for the same (resourceId, scope) pair. That call would await its own hydration and deadlock.
const unsubscribe = controller.onSessionCreated(
async session => {
const settings = await loadSettings(session.identity.getResourceId())
if (settings) await session.state.set(settings)
},
{ blocking: true },
)
// Default listeners stay fire-and-forget.
controller.onSessionCreated(session => {
console.log(`Created ${session.identity.getResourceId()}`)
})
Listeners run once per newly materialized session, not for cached sessions returned by later createSession() calls. They run only in the current process and aren't persisted events.
Returns: () => void
onSessionDeleted(listener)onsessiondeletedlistener的直接链接
Subscribe to process-local notifications after deleteSession() tears down a live session, with isolated listener errors prevented from affecting other listeners. Call the returned function to unsubscribe.
const unsubscribe = controller.onSessionDeleted(session => {
console.log(`Closed ${session.identity.getResourceId()}`)
})
await controller.createSession({ resourceId: 'project-42' })
await controller.deleteSession({ resourceId: 'project-42' })
unsubscribe()
This listener is best-effort and runs only in the current process. It isn't a persisted deletion event.
Returns: () => void
deleteSession({ resourceId, scope? })deletesession-resourceid-scope-的直接链接
Tear down the materialized session for a resource and optional scope. The method aborts active work, then removes thread subscriptions, the active thread lock, and the live session from the controller registry. It doesn't delete persisted threads or messages.
const deleted = await controller.deleteSession({
resourceId: 'project-42',
scope: 'editor-window-1',
})
Returns: Promise<boolean>. The result is true when a live session was removed and false when no matching live session exists or when another deletion is already in progress for the same resource and scope.
setResourceId(session, { resourceId })setresourceidsession--resourceid-的直接链接
Move a live session to another resource and clear its active thread binding.
await controller.setResourceId(session, { resourceId: 'project-43' })
getKnownResourceIds(session)getknownresourceidssession的直接链接
List resource identifiers present in stored threads.
const resourceIds = await controller.getKnownResourceIds(session)
Returns: Promise<string[]>
listActiveThreadRuns()listactivethreadruns的直接链接
List every run in flight on this controller, across all resources and threads. The list comes from in-process run tracking, so it covers runs started by the current process and doesn't create or touch a session.
const runs = controller.listActiveThreadRuns()
Returns: ActiveThreadRun[]
interface ActiveThreadRun {
runId: string
resourceId?: string
threadId: string
}
Storage queriesStorage queries的直接链接
These methods read stored threads and messages without creating a Session or provisioning its workspace.
queryThreadById({ threadId })querythreadbyid-threadid-的直接链接
Return one stored thread, or null when the thread or storage doesn't exist.
const thread = await controller.queryThreadById({ threadId: 'thread-7' })
Returns: Promise<AgentControllerThread | null>
queryThreads(options)querythreadsoptions的直接链接
List stored threads. resourceId and metadata filter the results. Forked subagent threads are excluded unless includeForkedSubagents is true.
const threads = await controller.queryThreads({
resourceId: 'project-42',
includeForkedSubagents: false,
metadata: { repository: 'mastra' },
})
All options are optional. Returns: Promise<AgentControllerThread[]>
queryThreadMessages(options)querythreadmessagesoptions的直接链接
List stored messages for one thread with pagination, ordering, inclusion, and filtering options from StorageListMessagesInput. threadId is required. The default order is newest first by createdAt. When perPage is omitted, storage uses 40 messages per page.
const result = await controller.queryThreadMessages({
threadId: 'thread-7',
page: 0,
perPage: 20,
orderBy: { field: 'createdAt', direction: 'DESC' },
})
Returns: Promise<StorageListMessagesOutput> with controller-format messages.
generateThreadTitle(options)generatethreadtitleoptions的直接链接
Generate and store a title from a thread's conversation without creating a Session. threadId is required. resourceId, scope, model, and requestContext are optional. The method throws when the thread doesn't exist and returns undefined when the model produces no title.
const title = await controller.generateThreadTitle({
threadId: 'thread-7',
resourceId: 'project-42',
})
Returns: Promise<string | undefined>
LifecycleLifecycle的直接链接
init()init的直接链接
Initialize shared storage, propagate runtime services to agents, and start configured interval handlers. Configured workspaces initialize lazily when used. Repeated calls reuse the same initialization promise.
await controller.init()
initStorage()initstorage的直接链接
Initialize only the controller's storage layer without provisioning a workspace or starting the full controller runtime. The method is idempotent and is used by direct storage queries.
await controller.initStorage()
Returns: Promise<void>
destroy()destroy的直接链接
Stop controller-owned interval handlers. This doesn't destroy Sessions created by the controller.
await controller.destroy()
Modes and agentsModes and agents的直接链接
listModes()listmodes的直接链接
Return the configured mode definitions.
const modes = controller.listModes()
Returns: AgentControllerMode[]
getCurrentAgent(session)getcurrentagentsession的直接链接
Return the backing agent for the session's active mode.
const agent = controller.getCurrentAgent(session)
Returns: Agent
Workspace and browserWorkspace and browser的直接链接
hasWorkspace()hasworkspace的直接链接
Report whether the controller has a static, dynamic, or object-based workspace configuration.
if (controller.hasWorkspace()) {
console.log('Workspace configured')
}
Returns: boolean
isWorkspaceReady()isworkspaceready的直接链接
Report whether the controller-level workspace is ready.
const ready = controller.isWorkspaceReady()
Returns: boolean
getWorkspace()getworkspace的直接链接
Return a static controller workspace. Dynamic workspace factories resolve per session and return undefined here, so use resolveWorkspace instead.
const workspace = controller.getWorkspace()
Returns: Workspace | undefined
resolveWorkspace({ session, requestContext? })resolveworkspace-session-requestcontext-的直接链接
Return the workspace a session runs against. Sessions resolve theirs at creation, dynamic factories included, so this returns that instance and only falls back to the factory for a session created without one.
const workspace = await controller.resolveWorkspace({ session, requestContext })
Returns: Promise<Workspace | undefined>
setBrowser(browser)setbrowserbrowser的直接链接
Replace the controller browser and propagate it to the backing agents.
controller.setBrowser(browser)
Mastra and channelsMastra and channels的直接链接
getMastra()getmastra的直接链接
Return the parent Mastra instance or the internal instance created by init().
const mastra = controller.getMastra()
Returns: Mastra | undefined
getChannels()getchannels的直接链接
Return the configured chat channel integration.
const channels = controller.getChannels()
Returns: AgentControllerChannels | null
ModelsModels的直接链接
getCurrentModelAuthStatus(session)getcurrentmodelauthstatussession的直接链接
Return authentication status for the session's selected model.
const status = await controller.getCurrentModelAuthStatus(session)
Returns: Promise<ModelAuthStatus>
listAvailableModels()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()invalidateavailablemodelscache的直接链接
Clear the available-model cache.
controller.invalidateAvailableModelsCache()
Observational memory and permissionsObservational memory and permissions的直接链接
loadOMProgress(session)loadomprogresssession的直接链接
Load stored observational memory progress for the active thread and emit an om_status event.
await controller.loadOMProgress(session)
getObservationalMemoryRecord(session)getobservationalmemoryrecordsession的直接链接
Return the observational memory record for the active thread.
const record = await controller.getObservationalMemoryRecord(session)
Returns: Promise<ObservationalMemoryRecord | null>
getToolCategory({ toolName })gettoolcategory-toolname-的直接链接
Resolve the permission category for a tool.
const category = controller.getToolCategory({ toolName: 'execute_command' })
Returns: ToolCategory | null
IntervalsIntervals的直接链接
registerInterval(handler)registerintervalhandler的直接链接
Start or replace a periodic handler.
controller.registerInterval({
id: 'refresh',
intervalMs: 60_000,
handler: async () => refreshData(),
})
removeInterval({ id })removeinterval-id-的直接链接
Stop one interval and run its optional shutdown callback.
await controller.removeInterval({ id: 'refresh' })
stopIntervals()stopintervals的直接链接
Stop all intervals and run their optional shutdown callbacks.
await controller.stopIntervals()