跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

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 example
Usage example的直接链接

The following example initializes a controller and creates a session. It subscribes to session events before sending a message.

src/mastra/agent-controller.ts
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 parameters
Constructor parameters的直接链接

id:

string
Unique controller identifier. It is also the default session and resource identifier.

modes:

AgentControllerMode[]
Mode definitions available to every session. At least one mode is required.
AgentControllerMode

id:

string
Unique mode identifier.

name?:

string
Display name.

defaultModelId?:

string
Model used when a session starts in this mode without a stored selection. Mode switches do not apply it.

description?:

string
Text shown in mode selectors.

instructions?:

string
Instructions layered above the backing agent instructions for this mode.

transitionsTo?:

string
Mode entered after an approved submit_plan suspension.

availableTools?:

string[]
Allowlist of exposed tool names. An empty array hides every tool in this mode.

metadata?:

Record<string, unknown>
Pass-through mode metadata. metadata.default: true marks the default mode.

tools?:

ToolsInput
Mode tools. Mutually exclusive with additionalTools.

additionalTools?:

ToolsInput
Tools added to the backing agent tools. Mutually exclusive with tools.

agent?:

Agent
Deprecated mode-specific agent. Use the top-level agent parameter.

default?:

boolean
Deprecated default marker. Use metadata.default or defaultModeId.

agent?:

Agent
Shared backing agent used by the configured modes.

resourceId?:

string
Default resource identifier for sessions and threads. Defaults to id.

storage?:

MastraCompositeStore
Storage used for persistent threads, messages, settings, and resumable run data.

stateSchema?:

PublicSchema<TState, any>
Schema used to validate session.state updates.

initialState?:

Partial<TState>
Initial state merged with schema defaults for each new session.

memory?:

DynamicArgument<MastraMemory>
Memory instance shared with backing agents that do not define their own memory.

defaultModeId?:

string
Default mode identifier. It takes precedence over mode metadata.

instructions?:

string
Controller instructions layered with the current mode instructions.

tools?:

DynamicArgument<ToolsInput | undefined>
Tools shared by controller runs and available to configured subagents.

workspace?:

DynamicArgument<Workspace | undefined>
Static workspace or per-session workspace factory. A workspace is optional. Sessions without one support threads, state, and agent runs. They have no workspace tools unless the mode's agent has its own workspace.

browser?:

DynamicArgument<MastraBrowser | undefined>
Static browser or per-session browser factory.

channels?:

AgentControllerChannelsConfig
Chat channel configuration used to route channel threads into controller sessions.

intervalHandlers?:

IntervalHandler[]
Periodic handlers started by init() and stopped by stopIntervals() or destroy().

idGenerator?:

() => string
Custom identifier generator for threads, messages, and signals.

modelUseCountProvider?:

ModelUseCountProvider
Returns model usage counts used to sort available models.

modelUseCountTracker?:

ModelUseCountTracker
Records a model selection after session.model.switch().

subagents?:

AgentControllerSubagent[]
Subagent types exposed through the built-in subagent tool.
AgentControllerSubagent

id:

string
Unique subagent type identifier.

name:

string
Display name.

description:

string
Description used by the generated tool.

instructions:

DynamicArgument<AgentInstructions>
Subagent instructions.

tools?:

ToolsInput
Tools owned by the subagent.

allowedControllerTools?:

string[]
Controller tool IDs added to the subagent tools.

allowedWorkspaceTools?:

string[]
Workspace tool names visible to the subagent.

defaultModelId?:

string
Default subagent model.

maxSteps?:

number
Maximum execution steps.

stopWhen?:

LoopOptions["stopWhen"]
Loop stop condition.

forked?:

boolean
Whether the subagent inherits a cloned parent thread by default.

resolveSubagentModel?:

(modelId: string, options: { requestContext?: RequestContext }) => MastraModelConfig
Resolves a subagent's model ID into a model config. It receives a copy of the calling run's request context without the parent thread and resource IDs, so tenant credentials and request-scoped providers work for subagents. When unset, the model ID goes to the model gateway router.

gateways?:

MastraModelGatewayInterface[]
Custom model gateways merged with the built-in gateways.

omConfig?:

AgentControllerOMConfig
Default observational memory model selections, automatic model resolver, and thresholds.
AgentControllerOMConfig

defaultObserverModelId?:

string
Concrete observer fallback used when automatic resolution returns no model or throws.

observerModel?:

'auto' | string
Default observer model. Use 'auto' to follow the active main model.

defaultReflectorModelId?:

string
Concrete reflector fallback used when automatic resolution returns no model or throws.

reflectorModel?:

'auto' | string
Default reflector model. Use 'auto' to follow the active main model.

resolveAutoModelId?:

(args: ResolveAutoOMModelArgs) => string | undefined
Synchronously resolves an automatic role selection to a concrete model ID from the role, current main model, and read-only session state.

defaultObservationThreshold?:

number
Default observation threshold in tokens.

defaultReflectionThreshold?:

number
Default reflection threshold in tokens.

disableBuiltinTools?:

BuiltinToolId[]
Built-in controller tools to omit from runs.

toolCategoryResolver?:

(toolName: string) => ToolCategory | null
Maps tool names to permission categories.

pubsub?:

PubSub
PubSub implementation propagated to backing agents.

threadLock?:

{ acquire: (threadId: string) => void | Promise<void>; release: (threadId: string) => void | Promise<void> }
Lock implementation used to coordinate thread ownership.

observability?:

ObservabilityEntrypoint
Observability configuration for a standalone controller Mastra instance.

Properties
Properties的直接链接

id:

string
The controller identifier passed to the constructor.

Methods
Methods的直接链接

Sessions
Sessions的直接链接

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?:

string
Memory resource and live-session registry key. Defaults to the configured resourceId or controller id.

scope?:

string
Optional registry namespace that allows multiple live sessions for one resource.

threadId?:

string
Exact thread to bind. Missing threads are created with this identifier.

createInitialThread?:

boolean
= true
Create a thread when no existing thread matches. Set 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?:

string
Stable session identifier. Defaults to the controller id.

ownerId?:

string
Stable identity of the process-local Session host. Defaults to id. New threads use it as their initial owner, but later transfers do not change this value.

tags?:

Record<string, string>
Tags copied to threads created by the session.

workspace?:

Workspace
Workspace override for this session.

browser?:

MastraBrowser
Browser override for this session.

requestContext?:

RequestContext
Context used to resolve dynamic workspace and browser factories.

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 queries
Storage 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>

Lifecycle
Lifecycle的直接链接

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 agents
Modes 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 browser
Workspace 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 channels
Mastra 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

Models
Models的直接链接

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 permissions
Observational 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

Intervals
Intervals的直接链接

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()