@mastra/mcp-docs-server 1.2.13 → 1.2.14-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.docs/docs/agents/a2a.md +1 -1
  2. package/.docs/docs/agents/acp.md +1 -1
  3. package/.docs/docs/agents/agent-approval.md +1 -1
  4. package/.docs/docs/agents/networks.md +2 -2
  5. package/.docs/docs/agents/overview.md +2 -2
  6. package/.docs/docs/agents/using-tools.md +2 -2
  7. package/.docs/docs/capabilities/channels/overview.md +1 -1
  8. package/.docs/docs/{agents/supervisor-agents.md → capabilities/subagents.md} +58 -58
  9. package/.docs/docs/deployment/sandbox.md +95 -1
  10. package/.docs/docs/getting-started/develop.md +2 -0
  11. package/.docs/docs/harness/agent-controller.md +370 -0
  12. package/.docs/docs/long-running-agents/background-tasks.md +1 -1
  13. package/.docs/docs/long-running-agents/goals.md +3 -3
  14. package/.docs/docs/mcp/overview.md +222 -281
  15. package/.docs/docs/memory/overview.md +2 -2
  16. package/.docs/docs/observability/integrations/exporters/confident-ai.md +140 -0
  17. package/.docs/docs/observability/integrations/overview.md +1 -1
  18. package/.docs/docs/observability/overview.md +122 -8
  19. package/.docs/docs/observability/tracing/overview.md +2 -2
  20. package/.docs/docs/server/mastra-client.md +1 -1
  21. package/.docs/docs/server/server-adapters.md +2 -0
  22. package/.docs/docs/storage/overview.md +2 -2
  23. package/.docs/guides/build-your-ui/copilotkit/channels.md +49 -39
  24. package/.docs/guides/concepts/multi-agent-systems.md +7 -7
  25. package/.docs/guides/guide/coding-agent.md +2 -2
  26. package/.docs/guides/guide/research-coordinator.md +1 -1
  27. package/.docs/guides/migrations/network-to-supervisor.md +1 -1
  28. package/.docs/models/index.md +1 -1
  29. package/.docs/models/providers/cortecs.md +2 -1
  30. package/.docs/models/providers/digitalocean.md +9 -9
  31. package/.docs/models/providers/kilo.md +1 -1
  32. package/.docs/models/providers/llmgateway.md +1 -1
  33. package/.docs/models/providers/opencode.md +2 -1
  34. package/.docs/reference/acp/acp-agent.md +1 -1
  35. package/.docs/reference/agent-controller/agent-controller-class.md +195 -506
  36. package/.docs/reference/agent-controller/session.md +274 -111
  37. package/.docs/reference/agents/network.md +1 -1
  38. package/.docs/reference/ai-sdk/handle-network-stream.md +1 -1
  39. package/.docs/reference/ai-sdk/network-route.md +1 -1
  40. package/.docs/reference/cli/create-mastra.md +1 -1
  41. package/.docs/reference/editor/versioning.md +1 -1
  42. package/.docs/reference/evals/rubric.md +1 -1
  43. package/.docs/reference/file-based-agents/observability.md +2 -2
  44. package/.docs/reference/file-based-agents/storage.md +1 -1
  45. package/.docs/reference/file-based-agents/subagents.md +1 -1
  46. package/.docs/reference/file-based-agents/tools.md +1 -1
  47. package/.docs/reference/observability/tracing/configuration.md +1 -1
  48. package/.docs/reference/observability/tracing/exporters/confident-ai.md +138 -0
  49. package/.docs/reference/observability/tracing/interfaces.md +29 -0
  50. package/.docs/reference/signals/signal-provider.md +2 -0
  51. package/.docs/reference/tools/mcp-server.md +1 -1
  52. package/.docs/reference/tools/submit-plan-tool.md +1 -1
  53. package/.docs/reference/workspace/railway-sandbox.md +5 -5
  54. package/CHANGELOG.md +14 -0
  55. package/package.json +3 -3
  56. package/.docs/docs/agent-controller/channels.md +0 -111
  57. package/.docs/docs/agent-controller/modes.md +0 -147
  58. package/.docs/docs/agent-controller/overview.md +0 -136
  59. package/.docs/docs/agent-controller/session.md +0 -161
  60. package/.docs/docs/agent-controller/subagents.md +0 -110
  61. package/.docs/docs/agent-controller/threads-and-state.md +0 -148
  62. package/.docs/docs/agent-controller/tool-approvals.md +0 -147
  63. package/.docs/docs/mcp/mcp-apps.md +0 -306
  64. package/.docs/docs/observability/config.md +0 -140
  65. package/.docs/docs/observability/storage.md +0 -81
@@ -1,738 +1,427 @@
1
1
  > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
2
 
3
- # AgentController class
3
+ # AgentController
4
4
 
5
5
  > **Beta:** The `AgentController` feature is in beta stage and subject to breaking changes in minor versions until it graduates from its beta status.
6
6
 
7
- The `AgentController` class coordinates agent modes with shared state, memory, and storage. It provides a control layer that a TUI or other UI can drive. The layer manages threads and model or mode switches. It sends messages and handles tool approvals while tracking events.
7
+ The `AgentController` class is a shared host for one or more [`Session`](https://mastra.ai/reference/agent-controller/session) instances. Initialize the controller, create a session, then use `session.*` APIs for conversation state and run control.
8
8
 
9
- Per-conversation state (identity, the active thread, mode and model selection, run state, grants, and the display snapshot) lives on the [`Session`](https://mastra.ai/reference/agent-controller/session), accessed through `agentController.session`.
10
-
11
- For a conceptual introduction, see the [AgentController overview](https://mastra.ai/docs/agent-controller/overview).
9
+ For a guided introduction, see the [AgentController overview](https://mastra.ai/docs/harness/agent-controller).
12
10
 
13
11
  ## Usage example
14
12
 
15
- Import the `AgentController` class and create a new instance with your agent, storage backend, and modes:
13
+ The following example initializes a controller and creates a session. It subscribes to session events before sending a message.
16
14
 
17
15
  ```typescript
16
+ import { Agent } from '@mastra/core/agent'
18
17
  import { AgentController } from '@mastra/core/agent-controller'
19
- import { LibSQLStore } from '@mastra/libsql'
20
- import { z } from 'zod'
21
-
22
- const agentController = new AgentController({
23
- id: 'my-coding-agent',
24
- agent: myAgent,
25
- storage: new LibSQLStore({ id: 'agent-storage', url: 'file:./data.db' }),
26
- stateSchema: z.object({
27
- currentModelId: z.string().optional(),
28
- }),
29
- modes: [
30
- {
31
- id: 'plan',
32
- name: 'Plan',
33
- metadata: { default: true },
34
- instructions: 'Reason about changes before making them.',
35
- },
36
- { id: 'build', name: 'Build', transitionsTo: 'plan' },
37
- ],
18
+ import { Workspace } from '@mastra/core/workspace'
19
+
20
+ const agent = new Agent({
21
+ id: 'coding-agent',
22
+ name: 'Coding agent',
23
+ instructions: 'Help with software engineering tasks.',
24
+ model: 'anthropic/claude-sonnet-4-6',
38
25
  })
39
26
 
40
- agentController.subscribe(event => {
27
+ const controller = new AgentController({
28
+ id: 'coding-controller',
29
+ agent,
30
+ workspace: new Workspace({ id: 'coding-workspace' }),
31
+ modes: [{ id: 'build', name: 'Build', metadata: { default: true } }],
32
+ })
33
+
34
+ await controller.init()
35
+
36
+ const session = await controller.createSession({ resourceId: 'project-42' })
37
+ const unsubscribe = session.subscribe(event => {
41
38
  if (event.type === 'message_update') {
42
- renderMessage(event.message)
39
+ console.log(event.message)
43
40
  }
44
41
  })
45
42
 
46
- await agentController.init()
47
- await agentController.selectOrCreateThread()
48
- await agentController.sendMessage({ content: 'Hello!' })
43
+ await session.sendMessage({ content: 'Review the project structure.' })
44
+ unsubscribe()
49
45
  ```
50
46
 
51
47
  ## Constructor parameters
52
48
 
53
- **id** (`string`): Unique identifier for this agentController instance.
54
-
55
- **resourceId** (`string`): Resource ID for grouping threads (e.g., project identifier). Threads are scoped to this resource ID. Defaults to id.
49
+ **id** (`string`): Unique controller identifier. It is also the default session and resource identifier.
56
50
 
57
- **storage** (`MastraCompositeStore`): Storage backend for persistence (threads, messages, state).
51
+ **modes** (`AgentControllerMode[]`): Mode definitions available to every session. At least one mode is required.
58
52
 
59
- **stateSchema** (`StandardJSONSchemaV1`): Standard JSON Schema defining the shape of application state, accessed at runtime via session.state. Used for validation and extracting defaults.
53
+ **modes.id** (`string`): Unique mode identifier.
60
54
 
61
- **initialState** (`Partial<z.infer<TState>>`): Initial state values. Must conform to the schema if provided.
55
+ **modes.name** (`string`): Display name.
62
56
 
63
- **memory** (`MastraMemory`): Memory configuration shared across all modes. Propagated to mode agents that don't have their own memory.
57
+ **modes.defaultModelId** (`string`): Model selected when a session enters this mode without a stored selection.
64
58
 
65
- **modes** (`AgentControllerMode[]`): Available agent modes. At least one mode is required. When a top-level agent is provided, each mode layers its own instructions and tool overrides on top of the shared agent.
59
+ **modes.description** (`string`): Text shown in mode selectors.
66
60
 
67
- **modes.id** (`string`): Unique identifier for this mode (e.g., "plan", "build").
61
+ **modes.instructions** (`string`): Instructions layered above the backing agent instructions for this mode.
68
62
 
69
- **modes.name** (`string`): Human-readable name for display.
63
+ **modes.transitionsTo** (`string`): Mode entered after an approved submit\_plan suspension.
70
64
 
71
- **modes.default** (`boolean`): Whether this is the default mode when the agentController starts. Deprecated in favor of metadata.default or the top-level defaultModeId.
65
+ **modes.availableTools** (`string[]`): Allowlist of exposed tool names. An empty array hides every tool in this mode.
72
66
 
73
- **modes.defaultModelId** (`string`): Default model ID for this mode (e.g., "anthropic/claude-sonnet-4-20250514"). Used when no per-mode model has been explicitly selected.
67
+ **modes.metadata** (`Record<string, unknown>`): Pass-through mode metadata. metadata.default: true marks the default mode.
74
68
 
75
- **modes.description** (`string`): Description surfaced in mode pickers and Studio UI.
69
+ **modes.tools** (`ToolsInput`): Mode tools. Mutually exclusive with additionalTools.
76
70
 
77
- **modes.instructions** (`string`): Additional instructions layered above the backing agent's own instructions for this mode.
71
+ **modes.additionalTools** (`ToolsInput`): Tools added to the backing agent tools. Mutually exclusive with tools.
78
72
 
79
- **modes.transitionsTo** (`string`): Target mode ID to switch to on submit\_plan approval. Must reference another mode's id.
73
+ **modes.agent** (`Agent`): Deprecated mode-specific agent. Use the top-level agent parameter.
80
74
 
81
- **modes.metadata** (`Record<string, unknown>`): Arbitrary metadata. metadata.default === true marks the default mode when defaultModeId is unset.
75
+ **modes.default** (`boolean`): Deprecated default marker. Use metadata.default or defaultModeId.
82
76
 
83
- **modes.tools** (`ToolsInput`): Replaces the backing agent's tools for this mode. Mutually exclusive with additionalTools.
77
+ **agent** (`Agent`): Shared backing agent used by the configured modes.
84
78
 
85
- **modes.additionalTools** (`ToolsInput`): Tools layered on top of the backing agent's tools. Mutually exclusive with tools.
79
+ **resourceId** (`string`): Default resource identifier for sessions and threads. Defaults to id.
86
80
 
87
- **modes.availableTools** (`string[]`): Per-mode tool visibility allowlist. When set, only tools whose final exposed names appear in this list are visible to the model and executable during this mode's runs. undefined = all tools visible; \[] = no tools. Per-tool and per-category deny rules take precedence over this list. Workspace tools use the same list: reference them by exposed names (view, write\_file, etc.).
81
+ **storage** (`MastraCompositeStore`): Storage used for persistent threads, messages, settings, and resumable run data.
88
82
 
89
- **modes.agent** (`Agent`): The agent for this mode. Deprecated in favor of the top-level agent config with mode-level overrides.
83
+ **stateSchema** (`PublicSchema<TState, any>`): Schema used to validate session.state updates.
90
84
 
91
- **agent** (`Agent`): Shared backing agent that each mode forks and decorates. When provided, modes layer instructions and tool overrides on top of this agent instead of providing their own.
85
+ **initialState** (`Partial<TState>`): Initial state merged with schema defaults for each new session.
92
86
 
93
- **defaultModeId** (`string`): Default mode to enter when a thread has no persisted mode. Takes precedence over metadata.default on individual modes.
87
+ **memory** (`DynamicArgument<MastraMemory>`): Memory instance shared with backing agents that do not define their own memory.
94
88
 
95
- **instructions** (`string`): Base instructions shared across all modes. Appended to the backing agent's instructions.
89
+ **defaultModeId** (`string`): Default mode identifier. It takes precedence over mode metadata.
96
90
 
97
- **tools** (`ToolsInput | ((ctx) => ToolsInput)`): Tools available to all agents across all modes. It can be a static tools object or a dynamic function that receives the request context.
91
+ **instructions** (`string`): Controller instructions layered with the current mode instructions.
98
92
 
99
- **workspace** (`Workspace | ((ctx) => Workspace)`): Workspace instance or a dynamic factory function. When omitted, each session created via createSession must provide its own workspace. The factory receives the request context and Mastra instance.
93
+ **tools** (`DynamicArgument<ToolsInput | undefined>`): Tools shared by controller runs and available to configured subagents.
100
94
 
101
- **browser** (`MastraBrowser | ((ctx) => MastraBrowser)`): Browser automation instance or a dynamic factory function. When omitted, each session created via createSession can provide its own browser.
95
+ **workspace** (`DynamicArgument<Workspace | undefined>`): Static workspace or per-session workspace factory. A session must resolve a valid workspace.
102
96
 
103
- **subagents** (`AgentControllerSubagent[]`): Subagent definitions. When provided, the agentController creates a built-in subagent tool that parent agents can call to spawn focused subagents.
97
+ **browser** (`DynamicArgument<MastraBrowser | undefined>`): Static browser or per-session browser factory.
104
98
 
105
- **subagents.id** (`string`): Unique identifier for this subagent type (e.g., "explore", "execute").
99
+ **channels** (`AgentControllerChannelsConfig`): Chat channel configuration used to route channel threads into controller sessions.
106
100
 
107
- **subagents.name** (`string`): Human-readable name shown in tool output.
101
+ **intervalHandlers** (`IntervalHandler[]`): Periodic handlers started by init() and stopped by stopIntervals() or destroy().
108
102
 
109
- **subagents.description** (`string`): Description of what this subagent does. Used in the auto-generated tool description.
103
+ **idGenerator** (`() => string`): Custom identifier generator for threads, messages, and signals.
110
104
 
111
- **subagents.instructions** (`string`): System prompt for this subagent.
105
+ **modelUseCountProvider** (`ModelUseCountProvider`): Returns model usage counts used to sort available models.
112
106
 
113
- **subagents.tools** (`ToolsInput`): Tools this subagent has direct access to.
107
+ **modelUseCountTracker** (`ModelUseCountTracker`): Records a model selection after session.model.switch().
114
108
 
115
- **subagents.allowedAgentControllerTools** (`string[]`): Tool IDs from the agentController's shared tools config. Merged with tools above to let subagents use a subset of agentController tools.
109
+ **subagents** (`AgentControllerSubagent[]`): Subagent types exposed through the built-in subagent tool.
116
110
 
117
- **subagents.allowedWorkspaceTools** (`string[]`): Workspace tool names the subagent is allowed to use. Uses the exposed names (after any renames via workspace tool config). When set, workspace tools not in this list are hidden from the model. Non-workspace tools are never affected. When omitted, all workspace tools are visible.
111
+ **subagents.id** (`string`): Unique subagent type identifier.
118
112
 
119
- **subagents.defaultModelId** (`string`): Default model ID for this subagent type.
113
+ **subagents.name** (`string`): Display name.
120
114
 
121
- **subagents.maxSteps** (`number`): Optional maximum number of steps for the spawned subagent. Defaults to 50 when omitted.
115
+ **subagents.description** (`string`): Description used by the generated tool.
122
116
 
123
- **subagents.stopWhen** (`LoopOptions['stopWhen']`): Optional stop condition for the spawned subagent.
117
+ **subagents.instructions** (`DynamicArgument<AgentInstructions>`): Subagent instructions.
124
118
 
125
- **subagents.forked** (`boolean`): When true, calls to this subagent default to forked mode: the subagent runs on a clone of the parent thread, reusing the parent agent’s instructions, tools, and model so the prompt-cache prefix stays intact. Requires memory to be configured. The subagent definition’s own instructions, tools, allowedAgentControllerTools, allowedWorkspaceTools, defaultModelId, maxSteps, and stopWhen are ignored in forked mode. Callers can still override per-invocation via forked: false in the subagent tool input. See the Forked subagents section below for full semantics.
119
+ **subagents.tools** (`ToolsInput`): Tools owned by the subagent.
126
120
 
127
- **resolveModel** (`(modelId: string) => MastraLanguageModel`): Converts a model ID string (e.g., "anthropic/claude-sonnet-4") to a language model instance. Used by subagents and observational memory model resolution.
121
+ **subagents.allowedControllerTools** (`string[]`): Controller tool IDs added to the subagent tools.
128
122
 
129
- **omConfig** (`AgentControllerOMConfig`): Default configuration for observational memory (observer/reflector model IDs and thresholds).
123
+ **subagents.allowedWorkspaceTools** (`string[]`): Workspace tool names visible to the subagent.
130
124
 
131
- **disableBuiltinTools** (`BuiltinToolId[]`): Built-in tool IDs to remove from the controllerBuiltIn toolset. Valid values are ask\_user, submit\_plan, task\_write, task\_update, task\_complete, task\_check, and subagent.
125
+ **subagents.defaultModelId** (`string`): Default subagent model.
132
126
 
133
- **intervalHandlers** (`IntervalHandler[]`): Periodic background tasks started during init(). Use for gateway sync, cache refresh, and similar tasks.
127
+ **subagents.maxSteps** (`number`): Maximum execution steps.
134
128
 
135
- **idGenerator** (`() => string`): Custom ID generator for AgentController-managed IDs such as threads and mode-run identifiers. (Default: `timestamp + random string`)
129
+ **subagents.stopWhen** (`LoopOptions["stopWhen"]`): Loop stop condition.
136
130
 
137
- **modelAuthChecker** (`ModelAuthChecker`): Custom auth checker for model providers. Return true/false to override the default environment variable check, or undefined to fall back to defaults.
131
+ **subagents.forked** (`boolean`): Whether the subagent inherits a cloned parent thread by default.
138
132
 
139
- **modelUseCountProvider** (`ModelUseCountProvider`): Provides per-model use counts for sorting and display in listAvailableModels().
133
+ **gateways** (`MastraModelGatewayInterface[]`): Custom model gateways merged with the built-in gateways.
140
134
 
141
- **modelUseCountTracker** (`ModelUseCountTracker`): Callback invoked when a model is selected via session.model.switch(). Use to track and persist model usage for ranking.
135
+ **omConfig** (`AgentControllerOMConfig`): Default observational memory models and thresholds.
142
136
 
143
- **customModelCatalogProvider** (`CustomModelCatalogProvider`): Catalog hook for additional models (e.g., user-defined custom providers). Returned entries are merged into listAvailableModels().
137
+ **disableBuiltinTools** (`BuiltinToolId[]`): Built-in controller tools to omit from runs.
144
138
 
145
- **gateways** (`MastraModelGatewayInterface[]`): Model gateways registered on the internal Mastra instance. Apps that need gateway-backed model resolution should also provide resolveModel.
139
+ **toolCategoryResolver** (`(toolName: string) => ToolCategory | null`): Maps tool names to permission categories.
146
140
 
147
- **toolCategoryResolver** (`(toolName: string) => ToolCategory | null`): Maps tool names to permission categories ('read', 'edit', 'execute', 'mcp', 'other'). Used by the permission system to resolve category-level policies.
141
+ **pubsub** (`PubSub`): PubSub implementation propagated to backing agents.
148
142
 
149
- **pubsub** (`PubSub`): PubSub instance used by the internal Mastra instance and mode agents for event coordination.
143
+ **threadLock** (`{ acquire: (threadId: string) => void | Promise<void>; release: (threadId: string) => void | Promise<void> }`): Lock implementation used to coordinate thread ownership.
150
144
 
151
- **threadLock** (`{ acquire, release }`): Thread locking callbacks to prevent concurrent access from multiple processes. acquire should throw if the lock is held.
152
-
153
- **observability** (`ObservabilityEntrypoint`): Observability entrypoint for tracing, scoring, and feedback. When provided, the internal Mastra instance produces trace spans for agent runs.
145
+ **observability** (`ObservabilityEntrypoint`): Observability configuration for a standalone controller Mastra instance.
154
146
 
155
147
  ## Properties
156
148
 
157
- **id** (`string`): AgentController identifier, set at construction.
158
-
159
- **session** (`Session`): The per-conversation state for the active conversation: identity, the active thread binding and reads, mode and model selection, run and abort state, the live stream, tool suspensions, follow-ups, approvals, permission grants, token usage, and the display-state snapshot. See the Session reference for the full API.
149
+ **id** (`string`): The controller identifier passed to the constructor.
160
150
 
161
151
  ## Methods
162
152
 
163
- ### Lifecycle
164
-
165
- #### `init()`
166
-
167
- Initialize the agentController. Loads storage, initializes a static workspace (runtime-defined factory workspaces are resolved per-session during `createSession`), propagates memory and workspace to mode agents, and starts interval handlers. Call this before using the agentController.
168
-
169
- ```typescript
170
- await agentController.init()
171
- ```
172
-
173
- #### `createSession({ id, ownerId, resourceId?, tags?, workspace?, browser?, requestContext? })`
174
-
175
- Create a new, fully-wired `Session` and bring it online. The session starts in the default mode with the seeded model, connects to the AgentController's shared machinery (agent, storage/lock, config catalog), and has a current thread (the most recent thread for the resource, or a freshly created one). Call `init()` once before creating sessions so shared storage is ready.
153
+ ### Sessions
176
154
 
177
- The AgentController owns no session of its own: every consumer creates its own session and drives all work through it. A `resourceId` maps to exactly one session per AgentController (get-or-create): calling `createSession` with the same `resourceId` returns the existing session, so reconnects resume rather than fork the conversation. Different `resourceId`s produce independent sessions with isolated event bus, mode, model, state, and current thread. Use `session.thread.create()` and `session.thread.switch()` to manage multiple conversations within one session.
155
+ #### `createSession(options)`
178
156
 
179
- `id` and `ownerId` are required: they mirror `SessionRecord.id` and `SessionRecord.ownerId` and are stable for the life of the session. `resourceId` is optional and defaults to `config.resourceId` then `config.id`.
180
-
181
- Each session owns its own `Workspace` and `Browser` instance. When `workspace` is omitted, the AgentController resolves its configured workspace (a static instance or a runtime-defined factory) and passes it to the session. Pass a `workspace` override to give a specific session a different workspace than the AgentController default. The workspace is initialized during session creation; `workspace_ready` and `workspace_status_changed` events are emitted on the session bus after `init()` completes, and late subscribers receive a replay of the last workspace status.
182
-
183
- ```typescript
184
- const session = await agentController.createSession({
185
- id: 'session-xyz',
186
- ownerId: 'user-123',
187
- })
188
- ```
189
-
190
- You can also override the resource:
191
-
192
- ```typescript
193
- const session = await agentController.createSession({
194
- id: 'session-xyz',
195
- ownerId: 'user-123',
196
- resourceId: 'project-abc',
197
- })
198
- ```
199
-
200
- Override the workspace and browser for a specific session:
157
+ Get or create the live session registered for the `(resourceId, scope)` pair. Call `init()` before this method.
201
158
 
202
159
  ```typescript
203
- const session = await agentController.createSession({
204
- id: 'session-xyz',
205
- ownerId: 'user-123',
206
- workspace: myWorkspace,
207
- browser: myBrowser,
160
+ const session = await controller.createSession({
161
+ resourceId: 'project-42',
162
+ scope: 'editor-window-1',
163
+ threadId: 'thread-7',
208
164
  })
209
165
  ```
210
166
 
211
- `tags` scopes initial thread selection: a thread is a resume candidate only when its metadata matches every provided tag. This lets worktrees sharing a resourceId each resume their own thread (via a `projectPath` tag).
212
-
213
- Switching the resource ID via `agentController.setResourceId()` changes only the resource ID, not `id` or `ownerId`. Read them through `session.identity.getId()` and `session.identity.getOwnerId()`.
167
+ 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.
214
168
 
215
- #### `selectOrCreateThread()`
169
+ **resourceId** (`string`): Memory resource and live-session registry key. Defaults to the configured resourceId or controller id.
216
170
 
217
- Select the most recent thread for the current resource, or create one if none exist. Loads thread metadata and acquires a thread lock.
171
+ **scope** (`string`): Optional registry namespace that allows multiple live sessions for one resource.
218
172
 
219
- ```typescript
220
- const thread = await agentController.selectOrCreateThread()
221
- ```
173
+ **threadId** (`string`): Exact thread to bind. Missing threads are created with this identifier.
222
174
 
223
- #### `destroy()`
224
-
225
- Stop all interval handlers and clean up resources.
226
-
227
- ```typescript
228
- await agentController.destroy()
229
- ```
175
+ **id** (`string`): Stable session identifier. Defaults to the controller id.
230
176
 
231
- #### `removeInterval({ id })`
177
+ **ownerId** (`string`): Stable session owner identifier. Defaults to id.
232
178
 
233
- Remove a specific interval handler by ID. Calls the handler's `shutdown()` callback if defined.
179
+ **tags** (`Record<string, string>`): Tags copied to threads created by the session.
234
180
 
235
- ```typescript
236
- await agentController.removeInterval({ id: 'gateway-sync' })
237
- ```
181
+ **workspace** (`Workspace`): Workspace override for this session.
238
182
 
239
- #### `stopIntervals()`
183
+ **browser** (`MastraBrowser`): Browser override for this session.
240
184
 
241
- Stop and remove all interval handlers.
185
+ **requestContext** (`RequestContext`): Context used to resolve dynamic workspace and browser factories.
242
186
 
243
- ```typescript
244
- await agentController.stopIntervals()
245
- ```
187
+ Returns: `Promise<Session<TState>>`
246
188
 
247
- #### `getCurrentAgent()`
189
+ #### `getSessionByResource(resourceId, scope?)`
248
190
 
249
- Return the fully-configured Agent for the current mode with runtime services (storage, memory, workspace, pubsub, telemetry) propagated.
191
+ Return the live session registered for a resource and optional scope.
250
192
 
251
193
  ```typescript
252
- const agent = agentController.getCurrentAgent()
194
+ const session = await controller.getSessionByResource('project-42', 'editor-window-1')
253
195
  ```
254
196
 
255
- #### `getResolvedMemory()`
256
-
257
- Return the resolved memory instance, or `null` if no memory is configured.
258
-
259
- ```typescript
260
- const memory = await agentController.getResolvedMemory()
261
- ```
197
+ Returns: `Promise<Session<TState> | undefined>`
262
198
 
263
- #### `getMastra()`
199
+ #### `setResourceId(session, { resourceId })`
264
200
 
265
- Return the internal `Mastra` instance, or `undefined` before `init()`. Useful for scorer registration, observability access, and eval tooling.
201
+ Move a live session to another resource and clear its active thread binding.
266
202
 
267
203
  ```typescript
268
- const mastra = agentController.getMastra()
204
+ await controller.setResourceId(session, { resourceId: 'project-43' })
269
205
  ```
270
206
 
271
- #### `getWorkspace()`
207
+ #### `getKnownResourceIds(session)`
272
208
 
273
- Return the AgentController-level workspace if it's a static `Workspace` instance. Dynamic factory workspaces aren't resolved here: use [`resolveWorkspace()`](#resolveworkspace-session-requestcontext-) to resolve a factory against a session's request context.
209
+ List resource identifiers present in stored threads.
274
210
 
275
211
  ```typescript
276
- const workspace = agentController.getWorkspace()
212
+ const resourceIds = await controller.getKnownResourceIds(session)
277
213
  ```
278
214
 
279
- #### `resolveWorkspace({ session, requestContext? })`
280
-
281
- Eagerly resolve and cache the workspace. For runtime-defined workspaces (factory function), this triggers the factory against the session's request context and caches the result so `getWorkspace()` returns it. Returns the resolved workspace or `undefined` if none is configured.
282
-
283
- ```typescript
284
- const workspace = await agentController.resolveWorkspace({ session })
285
- ```
215
+ Returns: `Promise<string[]>`
286
216
 
287
- ```typescript
288
- // With an explicit request context
289
- const requestContext = new RequestContext()
290
- const workspace = await agentController.resolveWorkspace({ session, requestContext })
291
- ```
217
+ ### Lifecycle
292
218
 
293
- #### `hasWorkspace()`
219
+ #### `init()`
294
220
 
295
- Whether a workspace is configured on this AgentController (static instance or runtime-defined factory). Sessions without an explicit workspace override fall back to this.
221
+ Initialize shared storage, workspace services, and configured interval handlers. Repeated calls reuse the same initialization promise.
296
222
 
297
223
  ```typescript
298
- if (agentController.hasWorkspace()) {
299
- // ...
300
- }
224
+ await controller.init()
301
225
  ```
302
226
 
303
- #### `isWorkspaceReady()`
227
+ #### `destroy()`
304
228
 
305
- Whether the AgentController-level static workspace has been initialized. Dynamic factory workspaces are resolved and initialized per-session during `createSession`, so this returns `false` for factory configs until a session is created.
229
+ Stop controller-owned interval handlers. This doesn't destroy Sessions created by the controller.
306
230
 
307
231
  ```typescript
308
- if (agentController.isWorkspaceReady()) {
309
- // ...
310
- }
232
+ await controller.destroy()
311
233
  ```
312
234
 
313
- ### Modes
235
+ ### Modes and agents
314
236
 
315
237
  #### `listModes()`
316
238
 
317
- Return all configured `AgentControllerMode` instances.
239
+ Return the configured mode definitions.
318
240
 
319
241
  ```typescript
320
- const modes = agentController.listModes()
242
+ const modes = controller.listModes()
321
243
  ```
322
244
 
323
- To read the active mode, use [`session.mode.get()`](https://mastra.ai/reference/agent-controller/session); to resolve it to a full `AgentControllerMode`, use [`session.mode.resolve()`](https://mastra.ai/reference/agent-controller/session).
245
+ Returns: `AgentControllerMode[]`
324
246
 
325
- ### Models
326
-
327
- To read the active model ID, use [`session.model.get()`](https://mastra.ai/reference/agent-controller/session); for a short display name, use [`session.model.displayName()`](https://mastra.ai/reference/agent-controller/session); to check whether a model is selected, use [`session.model.hasSelection()`](https://mastra.ai/reference/agent-controller/session).
328
-
329
- #### `getCurrentModelAuthStatus()`
330
-
331
- Check if the current model's provider has authentication configured. Uses `modelAuthChecker` if provided, falling back to environment variable checks from the provider registry.
332
-
333
- ```typescript
334
- const status = await agentController.getCurrentModelAuthStatus()
335
- // { hasAuth: true, apiKeyEnvVar: 'ANTHROPIC_API_KEY' }
336
- ```
337
-
338
- #### `listAvailableModels()`
247
+ #### `getCurrentAgent(session)`
339
248
 
340
- Retrieve all available models from the provider registry, including their authentication status and use counts.
249
+ Return the backing agent for the session's active mode.
341
250
 
342
251
  ```typescript
343
- const models = await agentController.listAvailableModels()
344
- // [{ id, provider, modelName, hasApiKey, apiKeyEnvVar, useCount }]
252
+ const agent = controller.getCurrentAgent(session)
345
253
  ```
346
254
 
347
- ### Threads
255
+ Returns: `Agent`
348
256
 
349
- The agentController owns thread lifecycle transitions (creating, switching, cloning, renaming, and deleting threads) because they coordinate the shared thread lock and emit events. The active thread binding and thread/message reads live on [`session.thread`](https://mastra.ai/reference/agent-controller/session).
257
+ ### Workspace and browser
350
258
 
351
- #### `createThread({ title? })`
352
-
353
- Creates a new thread and initializes its metadata. The method saves it to storage and acquires a thread lock before emitting a `thread_created` event.
354
-
355
- ```typescript
356
- const thread = await agentController.createThread({ title: 'New conversation' })
357
- ```
358
-
359
- #### `switchThread({ threadId })`
360
-
361
- Switch to a different thread. This aborts in-progress operations and acquires a lock on the new thread. It releases the previous thread lock and loads the new thread metadata. It then emits a `thread_changed` event.
362
-
363
- ```typescript
364
- await agentController.switchThread({ threadId: 'thread-abc123' })
365
- ```
366
-
367
- To list threads from storage, use [`session.thread.list()`](https://mastra.ai/reference/agent-controller/session). By default it returns only threads for the current resource and hides transient [forked subagent](#forked-subagents) threads. Pass `includeForkedSubagents: true` to opt back into seeing them: e.g. for a debug panel.
368
-
369
- #### `renameThread({ title })`
370
-
371
- Update the title of the current thread.
372
-
373
- ```typescript
374
- await agentController.renameThread({ title: 'Updated title' })
375
- ```
376
-
377
- #### `cloneThread({ sourceThreadId?, title?, resourceId? })`
259
+ #### `hasWorkspace()`
378
260
 
379
- Clone an existing thread and switch to the clone. Copies all messages and acquires a lock on the new thread. It then releases the lock on the previous thread and emits a `thread_created` event. If `sourceThreadId` is omitted, the current thread is cloned. When [Observational Memory](https://mastra.ai/docs/memory/observational-memory) is enabled, OM records are cloned with remapped message IDs.
261
+ Report whether the controller has a static, dynamic, or object-based workspace configuration.
380
262
 
381
263
  ```typescript
382
- // Clone the current thread
383
- const cloned = await agentController.cloneThread()
384
-
385
- // Clone a specific thread with a custom title
386
- const cloned = await agentController.cloneThread({
387
- sourceThreadId: 'thread-abc123',
388
- title: 'Alternative approach',
389
- })
264
+ if (controller.hasWorkspace()) {
265
+ console.log('Workspace configured')
266
+ }
390
267
  ```
391
268
 
392
- See [`Memory.cloneThread()`](https://mastra.ai/reference/memory/cloneThread) for details on what gets cloned.
393
-
394
- To read the current resource ID, use [`session.identity.getResourceId()`](https://mastra.ai/reference/agent-controller/session).
269
+ Returns: `boolean`
395
270
 
396
- #### `setResourceId({ resourceId })`
271
+ #### `isWorkspaceReady()`
397
272
 
398
- Set the resource ID and clear the current thread.
273
+ Report whether the controller-level workspace is ready.
399
274
 
400
275
  ```typescript
401
- agentController.setResourceId({ resourceId: 'project-xyz' })
276
+ const ready = controller.isWorkspaceReady()
402
277
  ```
403
278
 
404
- #### `getKnownResourceIds()`
405
-
406
- Return the distinct resource IDs that have threads in storage.
279
+ Returns: `boolean`
407
280
 
408
- ```typescript
409
- const resourceIds = await agentController.getKnownResourceIds()
410
- ```
411
-
412
- #### `getSession()`
281
+ #### `getWorkspace()`
413
282
 
414
- Return current session information including thread ID, mode ID, and the list of threads.
283
+ Return a static controller workspace. Dynamic workspace factories return `undefined` until resolved.
415
284
 
416
285
  ```typescript
417
- const session = await agentController.getSession()
418
- // { currentThreadId, currentModeId, threads }
286
+ const workspace = controller.getWorkspace()
419
287
  ```
420
288
 
421
- ### Messages
289
+ Returns: `Workspace | undefined`
422
290
 
423
- #### `sendMessage({ content, files?, requestContext? })`
291
+ #### `resolveWorkspace({ session, requestContext? })`
424
292
 
425
- Send a message to the current agent. Creates a thread if none exists, builds a `RequestContext` and toolsets, and streams the agent's response. Handles tool calls, approvals, and errors automatically. If you provide `requestContext`, the agentController forwards it to tools and subagents during the run.
293
+ Resolve a dynamic workspace for a session and cache the result on the controller.
426
294
 
427
295
  ```typescript
428
- await agentController.sendMessage({ content: 'Explain the authentication flow' })
296
+ const workspace = await controller.resolveWorkspace({ session, requestContext })
429
297
  ```
430
298
 
431
- Reading messages is owned by [`session.thread`](https://mastra.ai/reference/agent-controller/session): use `listActiveMessages()` for the active thread, `listMessages({ threadId })` for a specific thread, and `firstUserMessage({ threadId })` / `firstUserMessages({ threadIds })` for thread previews.
432
-
433
- ### Memory
434
-
435
- The `memory` property bundles thread management operations into a single namespace. `memory.createThread`, `memory.switchThread`, and `memory.renameThread` delegate to the corresponding AgentController lifecycle methods documented above. `memory.listThreads` delegates to [`session.thread.list()`](https://mastra.ai/reference/agent-controller/session).
299
+ Returns: `Promise<Workspace | undefined>`
436
300
 
437
- #### `memory.deleteThread({ threadId })`
301
+ #### `setBrowser(browser)`
438
302
 
439
- Delete a thread and all its messages from storage. If the deleted thread is the currently active thread, the thread lock is released and the agentController clears its active thread. Emits a `thread_deleted` event.
303
+ Replace the controller browser and propagate it to the backing agents.
440
304
 
441
305
  ```typescript
442
- await agentController.memory.deleteThread({ threadId: 'thread-abc123' })
306
+ controller.setBrowser(browser)
443
307
  ```
444
308
 
445
- ### Flow control
309
+ ### Mastra and channels
446
310
 
447
- #### `abort()`
311
+ #### `getMastra()`
448
312
 
449
- Abort any in-progress generation.
313
+ Return the parent Mastra instance or the internal instance created by `init()`.
450
314
 
451
315
  ```typescript
452
- agentController.abort()
316
+ const mastra = controller.getMastra()
453
317
  ```
454
318
 
455
- #### `steer({ content, requestContext? })`
319
+ Returns: `Mastra | undefined`
456
320
 
457
- Steer the agent mid-stream by injecting an instruction into the current generation.
321
+ #### `getChannels()`
458
322
 
459
- ```typescript
460
- agentController.steer({ content: 'Focus on security implications' })
461
- ```
462
-
463
- #### `followUp({ content, requestContext? })`
464
-
465
- Queue a follow-up message to be sent after the current generation completes. If no operation is running, sends the message immediately.
323
+ Return the configured chat channel integration.
466
324
 
467
325
  ```typescript
468
- agentController.followUp({ content: 'Now apply those changes' })
326
+ const channels = controller.getChannels()
469
327
  ```
470
328
 
471
- ### Tool approvals
472
-
473
- Responding to a pending tool approval is owned by the session: see [`session.respondToToolApproval()`](https://mastra.ai/reference/agent-controller/session). The agentController owns the permission _policy_ that decides when approval is required, documented under [Permissions](#permissions) below.
329
+ Returns: `AgentControllerChannels | null`
474
330
 
475
- ### Tool suspensions and plans
476
-
477
- #### `respondToToolSuspension({ resumeData, toolCallId?, requestContext? })`
331
+ ### Models
478
332
 
479
- Respond to a pending tool suspension. Interactive built-in tools such as `ask_user` and `request_access` pause through the native tool-suspension primitive, which emits a `tool_suspended` event carrying `toolCallId`, `toolName`, and `suspendPayload`. Pass `resumeData` to resume the suspended tool with the user's response.
333
+ #### `getCurrentModelAuthStatus(session)`
480
334
 
481
- Provide `toolCallId` to select which suspension to resume. It's required when more than one tool is suspended concurrently (for example, parallel `ask_user` calls). When omitted, it resolves to the sole pending suspension.
335
+ Return authentication status for the session's selected model.
482
336
 
483
337
  ```typescript
484
- agentController.subscribe(event => {
485
- if (event.type === 'tool_suspended' && event.toolName === 'ask_user') {
486
- const { question } = event.suspendPayload as { question: string }
487
- // Show `question` to the user, then resume the tool with their answer.
488
- agentController.respondToToolSuspension({
489
- toolCallId: event.toolCallId,
490
- resumeData: 'Yes, proceed with the refactor',
491
- })
492
- }
493
- })
494
- ```
495
-
496
- For multi-select questions, pass the selected option labels as a string array.
497
-
498
- ```typescript
499
- agentController.respondToToolSuspension({
500
- toolCallId: event.toolCallId,
501
- resumeData: ['Add tests', 'Update docs'],
502
- })
338
+ const status = await controller.getCurrentModelAuthStatus(session)
503
339
  ```
504
340
 
505
- #### Responding to a submitted plan
341
+ Returns: `Promise<ModelAuthStatus>`
506
342
 
507
- The `submit_plan` built-in tool pauses via the native tool-suspension primitive, so it surfaces through the same `tool_suspended` event as other interactive tools. Resume it with [`respondToToolSuspension`](#respondtotoolsuspension-resumedata-toolcallid-requestcontext-), passing a `resumeData` object with `action` (`'approved'` or `'rejected'`) and an optional `feedback` string.
343
+ #### `listAvailableModels()`
508
344
 
509
- On approval, the AgentController automatically switches to its default (execution) mode. On rejection, the plan-mode run resumes so the agent can revise and submit again.
345
+ List models from the configured and built-in gateways. Results are cached briefly and sorted with usage data when `modelUseCountProvider` is configured.
510
346
 
511
347
  ```typescript
512
- agentController.respondToToolSuspension({
513
- toolCallId: event.toolCallId,
514
- resumeData: { action: 'approved' },
515
- })
516
- agentController.respondToToolSuspension({
517
- toolCallId: event.toolCallId,
518
- resumeData: { action: 'rejected', feedback: 'Needs more detail' },
519
- })
348
+ const models = await controller.listAvailableModels()
520
349
  ```
521
350
 
522
- ### Permissions
351
+ Returns: `Promise<AvailableModel[]>`
523
352
 
524
- #### `getToolCategory({ toolName })`
353
+ #### `invalidateAvailableModelsCache()`
525
354
 
526
- Resolve a tool's category using the configured `toolCategoryResolver`.
355
+ Clear the available-model cache.
527
356
 
528
357
  ```typescript
529
- const category = agentController.getToolCategory({ toolName: 'mastra_workspace_write_file' })
530
- // 'edit'
358
+ controller.invalidateAvailableModelsCache()
531
359
  ```
532
360
 
533
- ### Observational Memory
361
+ ### Observational memory and permissions
534
362
 
535
- #### `loadOMProgress()`
363
+ #### `loadOMProgress(session)`
536
364
 
537
- Load observational memory records for the current thread and emit an `om_status` event with reconstructed progress.
365
+ Load stored observational memory progress for the active thread and emit an `om_status` event.
538
366
 
539
367
  ```typescript
540
- await agentController.loadOMProgress()
368
+ await controller.loadOMProgress(session)
541
369
  ```
542
370
 
543
- #### `getObservationalMemoryRecord()`
371
+ #### `getObservationalMemoryRecord(session)`
544
372
 
545
- Return the full `ObservationalMemoryRecord` for the current thread and resource, or `null` if no thread is selected or no record exists.
373
+ Return the observational memory record for the active thread.
546
374
 
547
375
  ```typescript
548
- const record = await agentController.getObservationalMemoryRecord()
549
-
550
- if (record) {
551
- console.log(record.activeObservations)
552
- console.log(record.generationCount)
553
- console.log(record.observationTokenCount)
554
- }
376
+ const record = await controller.getObservationalMemoryRecord(session)
555
377
  ```
556
378
 
557
- The observer/reflector model selection and observation/reflection thresholds live on the Session under [`session.om`](https://mastra.ai/reference/agent-controller/session), grouped by role. Read them with `session.om.observer.modelId()` / `session.om.reflector.modelId()` and `session.om.observer.threshold()` / `session.om.reflector.threshold()`, and change a role's model with `session.om.observer.switchModel()` / `session.om.reflector.switchModel()`.
558
-
559
- ### Forked subagents
379
+ Returns: `Promise<ObservationalMemoryRecord | null>`
560
380
 
561
- By default, a subagent runs with a fresh context: it doesn't see the parent conversation. **Forked subagents** opt into a different model: the subagent runs on a clone of the parent thread and reuses the parent agent's full configuration. This is useful when the subagent needs the full context of the conversation so far (e.g., recalling earlier user-supplied facts), and when prompt-cache hit rates matter.
562
-
563
- #### Enabling forked mode
381
+ #### `getToolCategory({ toolName })`
564
382
 
565
- Set `forked: true` either on the `AgentControllerSubagent` definition (per-type default) or on each `subagent` tool call (per-invocation override):
383
+ Resolve the permission category for a tool.
566
384
 
567
385
  ```typescript
568
- // Per-type default: every call to this subagent forks unless overridden.
569
- const subagents: AgentControllerSubagent[] = [
570
- {
571
- id: 'collaborator',
572
- name: 'Collaborator',
573
- description: 'Continues the conversation in a fork to try a different angle.',
574
- instructions: '...',
575
- forked: true,
576
- },
577
- ]
386
+ const category = controller.getToolCategory({ toolName: 'execute_command' })
578
387
  ```
579
388
 
580
- The model can also pass `forked: true` (or `forked: false`) per-invocation in the `subagent` tool input. The per-invocation value wins.
389
+ Returns: `ToolCategory | null`
581
390
 
582
- #### Semantics and constraints
391
+ ### Intervals
583
392
 
584
- - **Memory required.** Forked mode calls `memory.cloneThread` to create the fork, so the agentController must have `memory` configured and an active parent thread. Calls without those return a structured error rather than throwing.
585
- - **Parent agent reused.** The fork runs through the parent agent's `stream(...)` call. The parent's instructions, tools, model, `maxSteps`, and `stopWhen` apply. The subagent definition's `instructions`, `tools`, `allowedAgentControllerTools`, `allowedWorkspaceTools`, `defaultModelId`, `maxSteps`, and `stopWhen` are ignored in forked mode. This preserves the prompt-cache prefix.
586
- - **Toolsets inherited, recursive forks blocked at runtime.** Forks inherit the parent's toolsets verbatim (`ask_user`, `submit_plan`, user-configured agentController tools, _including the `subagent` tool itself_) so the LLM request prefix, system prompt + tool list + tool schemas + tool descriptions, stays byte-identical to the parent's. This is what preserves the prompt cache. The `subagent` entry is kept on the model side but its `execute` is replaced inside the fork with a stub that returns a non-error "tool unavailable inside a forked subagent" message: nested forks are blocked at the runtime layer without perturbing the cached prefix.
587
- - **Fork threads are tagged.** Each fork thread is created with `metadata.forkedSubagent === true` and `metadata.parentThreadId === <parent>`. By default, [`session.thread.list()`](https://mastra.ai/reference/agent-controller/session) hides these so they don't show up in user-facing thread pickers / startup flows. Pass `includeForkedSubagents: true` to see them in admin / debug tooling.
588
- - **Save-queue flushed before clone.** The agent stream batches message saves through a debounced `SaveQueueManager`, so the parent's latest user / assistant turn may not be on disk yet when the subagent tool call fires. The fork tool flushes pending saves first via the `flushMessages` callback on `AgentToolExecutionContext` before cloning, so the fork actually carries the latest turn. Flush failures are non-fatal: the clone still runs.
589
- - **Parent thread untouched.** All subagent activity (messages, OM writes) lands on the fork. The parent thread is never appended to during a forked subagent run.
393
+ #### `registerInterval(handler)`
590
394
 
591
- #### When to prefer non-forked mode
592
-
593
- Forked mode trades isolation for context inheritance. Use the default (non-forked) mode when the subagent needs a restricted toolset or a different system prompt. The same applies when using a cheaper model. Pass any required context explicitly in the `task` description.
594
-
595
- ### Events
596
-
597
- #### `subscribe(listener)`
598
-
599
- Register an event listener. Returns an unsubscribe function.
600
-
601
- Use this method for all consumers: UI, Server-Sent Events (SSE), terminal UI (TUI), bridge rendering, audit logs, debugging, analytics, and deterministic replay. For display rendering, watch for the `display_state_changed` event and read the latest snapshot from [`session.displayState.get()`](https://mastra.ai/reference/agent-controller/session). After every event the agentController emits `display_state_changed`, so high-frequency events such as `message_update`, `tool_update`, and `tool_input_delta` are coalesced into the next snapshot.
395
+ Start or replace a periodic handler.
602
396
 
603
397
  ```typescript
604
- // Render from the coalesced display-state snapshot:
605
- const unsubscribe = agentController.subscribe(event => {
606
- if (event.type === 'display_state_changed') {
607
- render(agentController.session.displayState.get())
608
- }
398
+ controller.registerInterval({
399
+ id: 'refresh',
400
+ intervalMs: 60_000,
401
+ handler: async () => refreshData(),
609
402
  })
610
-
611
- // Render an initial frame before the next agentController event:
612
- render(agentController.session.displayState.get())
613
403
  ```
614
404
 
615
- To handle raw events directly, switch on `event.type`:
405
+ #### `removeInterval({ id })`
616
406
 
617
- ```typescript
618
- const unsubscribe = agentController.subscribe(event => {
619
- switch (event.type) {
620
- case 'message_update':
621
- renderMessage(event.message)
622
- break
623
- case 'tool_approval_required':
624
- showApprovalPrompt(event.toolName)
625
- break
626
- case 'error':
627
- console.error(event.error)
628
- break
629
- }
630
- })
407
+ Stop one interval and run its optional shutdown callback.
631
408
 
632
- // Later:
633
- unsubscribe()
409
+ ```typescript
410
+ await controller.removeInterval({ id: 'refresh' })
634
411
  ```
635
412
 
636
- ## Events
637
-
638
- The agentController emits events through registered listeners. The following table lists the available event types:
639
-
640
- | Event type | Description |
641
- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
642
- | `mode_changed` | The active mode changed. |
643
- | `model_changed` | The active model changed. |
644
- | `thread_changed` | The active thread changed. |
645
- | `thread_created` | A new thread was created. |
646
- | `thread_deleted` | A thread was deleted. |
647
- | `state_changed` | AgentController state was updated. |
648
- | `agent_start` | The agent started processing. |
649
- | `agent_end` | The agent finished processing. |
650
- | `message_start` | A new message started streaming. |
651
- | `message_update` | A message was updated with new content. |
652
- | `message_end` | A message finished streaming. |
653
- | `tool_start` | A tool call started. |
654
- | `tool_approval_required` | A tool call requires user approval. |
655
- | `tool_suspended` | A tool paused via the native tool-suspension primitive (for example `ask_user`, `request_access`, or `submit_plan`). Includes `toolCallId`, `toolName`, and `suspendPayload`. Resume it with [`respondToToolSuspension`](#respondtotoolsuspension-resumedata-toolcallid-requestcontext-). |
656
- | `tool_update` | A tool call was updated with progress. |
657
- | `tool_end` | A tool call finished. |
658
- | `tool_input_start` | Tool input started streaming. |
659
- | `tool_input_delta` | Tool input received a streaming delta. |
660
- | `tool_input_end` | Tool input finished streaming. |
661
- | `usage_update` | Token usage was updated. |
662
- | `error` | An error occurred. |
663
- | `info` | An informational message was emitted. |
664
- | `system_reminder` | A system reminder was injected into the conversation. |
665
- | `state_signal` | A state signal was emitted (state-driven prompt injection). |
666
- | `reactive_signal` | A reactive signal fired in response to a state change. |
667
- | `notification` | A notification was delivered to the thread inbox. |
668
- | `notification_summary` | A summary of pending notifications was emitted. |
669
- | `follow_up_queued` | A follow-up message was queued. |
670
- | `workspace_status_changed` | The workspace status changed. |
671
- | `workspace_ready` | The workspace finished initializing. |
672
- | `workspace_error` | The workspace encountered an error. |
673
- | `om_status` | Observational Memory status update. |
674
- | `om_activation` | Observational Memory was activated for the thread. |
675
- | `om_model_changed` | An Observational Memory role model changed (`observer` or `reflector`). |
676
- | `om_observation_start` | An observation started. |
677
- | `om_observation_end` | An observation completed. |
678
- | `om_observation_failed` | An observation failed. |
679
- | `om_reflection_start` | A reflection started. |
680
- | `om_reflection_end` | A reflection completed. |
681
- | `om_reflection_failed` | A reflection failed. |
682
- | `om_buffering_start` | Observational Memory started buffering messages. |
683
- | `om_buffering_end` | Observational Memory finished buffering messages. |
684
- | `om_buffering_failed` | Observational Memory buffering failed. |
685
- | `om_thread_title_updated` | Observational Memory updated the thread title. |
686
- | `subagent_start` | A subagent started processing. |
687
- | `subagent_text_delta` | A subagent emitted a text delta. |
688
- | `subagent_tool_start` | A subagent started a tool call. |
689
- | `subagent_tool_end` | A subagent finished a tool call. |
690
- | `subagent_end` | A subagent finished processing. |
691
- | `subagent_model_changed` | A subagent's model changed. |
692
- | `task_updated` | A task list was updated. |
693
- | `goal_evaluation` | A goal evaluation completed (when native agent goals are configured). |
694
- | `shell_output` | A tool emitted shell output (stdout or stderr). |
695
- | `display_state_changed` | The canonical `AgentControllerDisplayState` snapshot changed. Read it from [`session.displayState.get()`](https://mastra.ai/reference/agent-controller/session). |
696
-
697
- The agentController also emits low-level streaming content chunks: `text`, `thinking`, `tool_call`, `tool_result`, `image`, and `file`. These are the raw pieces that get assembled into messages. Most UIs render from `message_update` (or read the [`session.displayState`](https://mastra.ai/reference/agent-controller/session) snapshot) rather than subscribing to them directly.
698
-
699
- ## Built-in tools
700
-
701
- The agentController provides built-in tools to agents in every mode:
702
-
703
- | Tool | Description |
704
- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
705
- | `ask_user` | Ask the user a question and wait for their response. Supports free text, single-select choices, and multi-select choices. |
706
- | `submit_plan` | Submit a plan for user review and approval. |
707
- | `task_write` | Create or replace a structured task list for tracking progress. Assigns task IDs when omitted and returns the structured task list snapshot. |
708
- | `task_update` | Update one tracked task by ID and return the structured task list snapshot. |
709
- | `task_complete` | Mark one tracked task completed by ID and return the structured task list snapshot. |
710
- | `task_check` | Check the completion status of the current task list and return `tasks`, `summary`, `incompleteTasks`, and `isError` fields. |
711
- | `subagent` | Spawn a focused subagent with constrained tools (only available when `subagents` is configured). Pass `forked: true` to inherit the parent conversation. See [Forked subagents](#forked-subagents). |
712
-
713
- ### `ask_user` selections
714
-
715
- The `ask_user` tool accepts `options` for choice prompts. Set `selectionMode` to `single_select` to let the user pick one option, or `multi_select` to let the user pick multiple options. When `options` are provided and `selectionMode` is omitted, the prompt defaults to `single_select`. Omit `options` for free-text questions.
716
-
717
- The following example demonstrates a multi-select response handler. The tool pauses through the `tool_suspended` event, the UI reads `selectionMode` from `event.suspendPayload`, lets the user choose multiple options, then returns a string array with `respondToToolSuspension()`.
413
+ #### `stopIntervals()`
414
+
415
+ Stop all intervals and run their optional shutdown callbacks.
718
416
 
719
417
  ```typescript
720
- agentController.subscribe(event => {
721
- if (event.type === 'tool_suspended' && event.toolName === 'ask_user') {
722
- const { selectionMode } = event.suspendPayload as { selectionMode?: string }
723
- if (selectionMode === 'multi_select') {
724
- agentController.respondToToolSuspension({
725
- toolCallId: event.toolCallId,
726
- resumeData: ['Add tests', 'Update docs'],
727
- })
728
- }
729
- }
730
- })
418
+ await controller.stopIntervals()
731
419
  ```
732
420
 
733
421
  ## Related
734
422
 
735
- - [Session class](https://mastra.ai/reference/agent-controller/session)
736
- - [AgentController overview](https://mastra.ai/docs/agent-controller/overview)
737
- - [Threads and state](https://mastra.ai/docs/agent-controller/threads-and-state)
738
- - [Tool approvals](https://mastra.ai/docs/agent-controller/tool-approvals)
423
+ - [AgentController guide](https://mastra.ai/docs/harness/agent-controller)
424
+ - [Session reference](https://mastra.ai/reference/agent-controller/session)
425
+ - [Agents](https://mastra.ai/docs/agents/overview)
426
+ - [Workspace](https://mastra.ai/docs/workspace/overview)
427
+ - [Channels](https://mastra.ai/docs/capabilities/channels/overview)