@mastra/mcp-docs-server 1.2.2-alpha.9 → 1.2.3-alpha.1

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 (39) hide show
  1. package/.docs/docs/{harness → agent-controller}/modes.md +19 -19
  2. package/.docs/docs/agent-controller/overview.md +128 -0
  3. package/.docs/docs/agent-controller/session.md +143 -0
  4. package/.docs/docs/{harness → agent-controller}/subagents.md +12 -12
  5. package/.docs/docs/agent-controller/threads-and-state.md +141 -0
  6. package/.docs/docs/{harness → agent-controller}/tool-approvals.md +23 -23
  7. package/.docs/docs/agents/channels.md +47 -0
  8. package/.docs/docs/server/auth/google.md +281 -0
  9. package/.docs/docs/server/auth.md +2 -1
  10. package/.docs/models/gateways/vercel.md +3 -1
  11. package/.docs/models/index.md +1 -1
  12. package/.docs/models/providers/baseten.md +1 -1
  13. package/.docs/models/providers/fireworks-ai.md +2 -1
  14. package/.docs/models/providers/friendli.md +3 -1
  15. package/.docs/models/providers/llmgateway.md +1 -2
  16. package/.docs/models/providers/nebius.md +3 -2
  17. package/.docs/models/providers/opencode-go.md +1 -1
  18. package/.docs/models/providers/ovhcloud.md +1 -2
  19. package/.docs/models/providers/scaleway.md +2 -1
  20. package/.docs/models/providers/tinfoil.md +77 -0
  21. package/.docs/models/providers/togetherai.md +3 -2
  22. package/.docs/models/providers/xiaomi-token-plan-ams.md +4 -6
  23. package/.docs/models/providers/xiaomi-token-plan-cn.md +4 -6
  24. package/.docs/models/providers/xiaomi-token-plan-sgp.md +4 -6
  25. package/.docs/models/providers/xiaomi.md +4 -7
  26. package/.docs/models/providers.md +1 -0
  27. package/.docs/reference/{harness/harness-class.md → agent-controller/agent-controller-class.md} +106 -106
  28. package/.docs/reference/{harness → agent-controller}/session.md +97 -91
  29. package/.docs/reference/agents/channels.md +3 -1
  30. package/.docs/reference/agents/durable-agent.md +30 -3
  31. package/.docs/reference/auth/google.md +355 -0
  32. package/.docs/reference/channels/channel-provider.md +65 -0
  33. package/.docs/reference/channels/slack-provider.md +226 -0
  34. package/.docs/reference/index.md +5 -2
  35. package/CHANGELOG.md +28 -0
  36. package/package.json +6 -6
  37. package/.docs/docs/harness/overview.md +0 -128
  38. package/.docs/docs/harness/session.md +0 -143
  39. package/.docs/docs/harness/threads-and-state.md +0 -141
@@ -1,23 +1,23 @@
1
- # Harness class
1
+ # AgentController class
2
2
 
3
- > **Beta:** The `Harness` feature is in beta stage and subject to breaking changes in minor versions until it graduates from its beta status.
3
+ > **Beta:** The `AgentController` feature is in beta stage and subject to breaking changes in minor versions until it graduates from its beta status.
4
4
 
5
- The `Harness` class orchestrates multiple agent modes, shared state, memory, and storage. It provides a control layer that a TUI or other UI can drive to manage threads, switch models and modes, send messages, handle tool approvals, and track events.
5
+ The `AgentController` class orchestrates multiple agent modes, shared state, memory, and storage. It provides a control layer that a TUI or other UI can drive to manage threads, switch models and modes, send messages, handle tool approvals, and track events.
6
6
 
7
- 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/harness/session), accessed through `harness.session`.
7
+ 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`.
8
8
 
9
- For a conceptual introduction, see the [Harness overview](https://mastra.ai/docs/harness/overview).
9
+ For a conceptual introduction, see the [AgentController overview](https://mastra.ai/docs/agent-controller/overview).
10
10
 
11
11
  ## Usage example
12
12
 
13
- Import the `Harness` class and create a new instance with your agent, storage backend, and modes:
13
+ Import the `AgentController` class and create a new instance with your agent, storage backend, and modes:
14
14
 
15
15
  ```typescript
16
- import { Harness } from '@mastra/core/harness'
16
+ import { AgentController } from '@mastra/core/agent-controller'
17
17
  import { LibSQLStore } from '@mastra/libsql'
18
18
  import { z } from 'zod'
19
19
 
20
- const harness = new Harness({
20
+ const agentController = new AgentController({
21
21
  id: 'my-coding-agent',
22
22
  agent: myAgent,
23
23
  storage: new LibSQLStore({ url: 'file:./data.db' }),
@@ -35,20 +35,20 @@ const harness = new Harness({
35
35
  ],
36
36
  })
37
37
 
38
- harness.subscribe(event => {
38
+ agentController.subscribe(event => {
39
39
  if (event.type === 'message_update') {
40
40
  renderMessage(event.message)
41
41
  }
42
42
  })
43
43
 
44
- await harness.init()
45
- await harness.selectOrCreateThread()
46
- await harness.sendMessage({ content: 'Hello!' })
44
+ await agentController.init()
45
+ await agentController.selectOrCreateThread()
46
+ await agentController.sendMessage({ content: 'Hello!' })
47
47
  ```
48
48
 
49
49
  ## Constructor parameters
50
50
 
51
- **id** (`string`): Unique identifier for this harness instance.
51
+ **id** (`string`): Unique identifier for this agentController instance.
52
52
 
53
53
  **resourceId** (`string`): Resource ID for grouping threads (e.g., project identifier). Threads are scoped to this resource ID. Defaults to \`id\`.
54
54
 
@@ -60,13 +60,13 @@ await harness.sendMessage({ content: 'Hello!' })
60
60
 
61
61
  **memory** (`MastraMemory`): Memory configuration shared across all modes. Propagated to mode agents that don't have their own memory.
62
62
 
63
- **modes** (`HarnessMode[]`): 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.
63
+ **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.
64
64
 
65
65
  **modes.id** (`string`): Unique identifier for this mode (e.g., \`"plan"\`, \`"build"\`).
66
66
 
67
67
  **modes.name** (`string`): Human-readable name for display.
68
68
 
69
- **modes.default** (`boolean`): Whether this is the default mode when the harness starts. Deprecated in favor of \`metadata.default\` or the top-level \`defaultModeId\`.
69
+ **modes.default** (`boolean`): Whether this is the default mode when the agentController starts. Deprecated in favor of \`metadata.default\` or the top-level \`defaultModeId\`.
70
70
 
71
71
  **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.
72
72
 
@@ -98,7 +98,7 @@ await harness.sendMessage({ content: 'Hello!' })
98
98
 
99
99
  **browser** (`MastraBrowser | ((ctx) => MastraBrowser)`): Browser automation instance or a dynamic factory function. When omitted, each session created via createSession can provide its own browser.
100
100
 
101
- **subagents** (`HarnessSubagent[]`): Subagent definitions. When provided, the harness creates a built-in \`subagent\` tool that parent agents can call to spawn focused subagents.
101
+ **subagents** (`AgentControllerSubagent[]`): Subagent definitions. When provided, the agentController creates a built-in \`subagent\` tool that parent agents can call to spawn focused subagents.
102
102
 
103
103
  **subagents.id** (`string`): Unique identifier for this subagent type (e.g., \`"explore"\`, \`"execute"\`).
104
104
 
@@ -110,7 +110,7 @@ await harness.sendMessage({ content: 'Hello!' })
110
110
 
111
111
  **subagents.tools** (`ToolsInput`): Tools this subagent has direct access to.
112
112
 
113
- **subagents.allowedHarnessTools** (`string[]`): Tool IDs from the harness's shared \`tools\` config. Merged with \`tools\` above to let subagents use a subset of harness tools.
113
+ **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.
114
114
 
115
115
  **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.
116
116
 
@@ -120,17 +120,17 @@ await harness.sendMessage({ content: 'Hello!' })
120
120
 
121
121
  **subagents.stopWhen** (`LoopOptions['stopWhen']`): Optional stop condition for the spawned subagent.
122
122
 
123
- **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\`, \`allowedHarnessTools\`, \`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]\(#forked-subagents) section below for full semantics.
123
+ **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]\(#forked-subagents) section below for full semantics.
124
124
 
125
125
  **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.
126
126
 
127
- **omConfig** (`HarnessOMConfig`): Default configuration for observational memory (observer/reflector model IDs and thresholds).
127
+ **omConfig** (`AgentControllerOMConfig`): Default configuration for observational memory (observer/reflector model IDs and thresholds).
128
128
 
129
- **disableBuiltinTools** (`BuiltinToolId[]`): Built-in harness tool IDs to remove from the \`harnessBuiltIn\` toolset. Valid values are \`ask\_user\`, \`submit\_plan\`, \`task\_write\`, \`task\_update\`, \`task\_complete\`, \`task\_check\`, and \`subagent\`.
129
+ **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\`.
130
130
 
131
131
  **heartbeatHandlers** (`HeartbeatHandler[]`): Periodic background tasks started during \`init()\`. Use for gateway sync, cache refresh, and similar tasks.
132
132
 
133
- **idGenerator** (`() => string`): Custom ID generator for Harness-managed IDs such as threads and mode-run identifiers. (Default: `timestamp + random string`)
133
+ **idGenerator** (`() => string`): Custom ID generator for AgentController-managed IDs such as threads and mode-run identifiers. (Default: `timestamp + random string`)
134
134
 
135
135
  **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.
136
136
 
@@ -152,7 +152,7 @@ await harness.sendMessage({ content: 'Hello!' })
152
152
 
153
153
  ## Properties
154
154
 
155
- **id** (`string`): Harness identifier, set at construction.
155
+ **id** (`string`): AgentController identifier, set at construction.
156
156
 
157
157
  **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.
158
158
 
@@ -162,24 +162,24 @@ await harness.sendMessage({ content: 'Hello!' })
162
162
 
163
163
  #### `init()`
164
164
 
165
- Initialize the harness. Loads storage, initializes a static workspace (dynamic factory workspaces are resolved per-session during `createSession`), propagates memory and workspace to mode agents, and starts heartbeat handlers. Call this before using the harness.
165
+ Initialize the agentController. Loads storage, initializes a static workspace (dynamic factory workspaces are resolved per-session during `createSession`), propagates memory and workspace to mode agents, and starts heartbeat handlers. Call this before using the agentController.
166
166
 
167
167
  ```typescript
168
- await harness.init()
168
+ await agentController.init()
169
169
  ```
170
170
 
171
171
  #### `createSession({ id, ownerId, resourceId?, tags?, workspace?, browser?, requestContext? })`
172
172
 
173
- Create a new, fully-wired `Session` and bring it online. The session starts in the default mode with the seeded model, connects to the Harness'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.
173
+ 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.
174
174
 
175
- The Harness owns no session of its own — every consumer creates its own session and drives all work through it. In a server or multiplayer setting, each request, thread, or user gets its own session, isolated from every other: independent event bus, mode, model, state, and current thread.
175
+ The AgentController owns no session of its own — every consumer creates its own session and drives all work through it. In a server or multiplayer setting, each request, thread, or user gets its own session, isolated from every other: independent event bus, mode, model, state, and current thread.
176
176
 
177
177
  `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`.
178
178
 
179
- Each session owns its own `Workspace` and `Browser` instance. When `workspace` is omitted, the Harness resolves its configured workspace (a static instance or a dynamic factory) and passes it to the session. Pass a `workspace` override to give a specific session a different workspace than the Harness 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.
179
+ Each session owns its own `Workspace` and `Browser` instance. When `workspace` is omitted, the AgentController resolves its configured workspace (a static instance or a dynamic 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.
180
180
 
181
181
  ```typescript
182
- const session = await harness.createSession({
182
+ const session = await agentController.createSession({
183
183
  id: 'session-xyz',
184
184
  ownerId: 'user-123',
185
185
  })
@@ -188,7 +188,7 @@ const session = await harness.createSession({
188
188
  You can also override the resource:
189
189
 
190
190
  ```typescript
191
- const session = await harness.createSession({
191
+ const session = await agentController.createSession({
192
192
  id: 'session-xyz',
193
193
  ownerId: 'user-123',
194
194
  resourceId: 'project-abc',
@@ -198,7 +198,7 @@ const session = await harness.createSession({
198
198
  Override the workspace and browser for a specific session:
199
199
 
200
200
  ```typescript
201
- const session = await harness.createSession({
201
+ const session = await agentController.createSession({
202
202
  id: 'session-xyz',
203
203
  ownerId: 'user-123',
204
204
  workspace: myWorkspace,
@@ -208,14 +208,14 @@ const session = await harness.createSession({
208
208
 
209
209
  `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).
210
210
 
211
- Switching the resource ID via `harness.setResourceId()` changes only the resource ID, not `id` or `ownerId`. Read them through `session.identity.getId()` and `session.identity.getOwnerId()`.
211
+ 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()`.
212
212
 
213
213
  #### `selectOrCreateThread()`
214
214
 
215
215
  Select the most recent thread for the current resource, or create one if none exist. Loads thread metadata and acquires a thread lock.
216
216
 
217
217
  ```typescript
218
- const thread = await harness.selectOrCreateThread()
218
+ const thread = await agentController.selectOrCreateThread()
219
219
  ```
220
220
 
221
221
  #### `destroy()`
@@ -223,7 +223,7 @@ const thread = await harness.selectOrCreateThread()
223
223
  Stop all heartbeat handlers and clean up resources.
224
224
 
225
225
  ```typescript
226
- await harness.destroy()
226
+ await agentController.destroy()
227
227
  ```
228
228
 
229
229
  #### `removeHeartbeat({ id })`
@@ -231,7 +231,7 @@ await harness.destroy()
231
231
  Remove a specific heartbeat handler by ID. Calls the handler's `shutdown()` callback if defined.
232
232
 
233
233
  ```typescript
234
- await harness.removeHeartbeat({ id: 'gateway-sync' })
234
+ await agentController.removeHeartbeat({ id: 'gateway-sync' })
235
235
  ```
236
236
 
237
237
  #### `stopHeartbeats()`
@@ -239,7 +239,7 @@ await harness.removeHeartbeat({ id: 'gateway-sync' })
239
239
  Stop and remove all heartbeat handlers.
240
240
 
241
241
  ```typescript
242
- await harness.stopHeartbeats()
242
+ await agentController.stopHeartbeats()
243
243
  ```
244
244
 
245
245
  #### `getCurrentAgent()`
@@ -247,7 +247,7 @@ await harness.stopHeartbeats()
247
247
  Return the fully-configured Agent for the current mode with runtime services (storage, memory, workspace, pubsub, telemetry) propagated.
248
248
 
249
249
  ```typescript
250
- const agent = harness.getCurrentAgent()
250
+ const agent = agentController.getCurrentAgent()
251
251
  ```
252
252
 
253
253
  #### `getResolvedMemory()`
@@ -255,7 +255,7 @@ const agent = harness.getCurrentAgent()
255
255
  Return the resolved memory instance, or `null` if no memory is configured.
256
256
 
257
257
  ```typescript
258
- const memory = await harness.getResolvedMemory()
258
+ const memory = await agentController.getResolvedMemory()
259
259
  ```
260
260
 
261
261
  #### `getMastra()`
@@ -263,15 +263,15 @@ const memory = await harness.getResolvedMemory()
263
263
  Return the internal `Mastra` instance, or `undefined` before `init()`. Useful for scorer registration, observability access, and eval tooling.
264
264
 
265
265
  ```typescript
266
- const mastra = harness.getMastra()
266
+ const mastra = agentController.getMastra()
267
267
  ```
268
268
 
269
269
  #### `getWorkspace()`
270
270
 
271
- Return the Harness-level workspace if it is a static `Workspace` instance. Dynamic factory workspaces are not resolved here — use [`resolveWorkspace()`](#resolveworkspace-session-requestcontext-) to resolve a factory against a session's request context.
271
+ Return the AgentController-level workspace if it is a static `Workspace` instance. Dynamic factory workspaces are not resolved here — use [`resolveWorkspace()`](#resolveworkspace-session-requestcontext-) to resolve a factory against a session's request context.
272
272
 
273
273
  ```typescript
274
- const workspace = harness.getWorkspace()
274
+ const workspace = agentController.getWorkspace()
275
275
  ```
276
276
 
277
277
  #### `resolveWorkspace({ session, requestContext? })`
@@ -279,31 +279,31 @@ const workspace = harness.getWorkspace()
279
279
  Eagerly resolve and cache the workspace. For dynamic workspaces (factory function), this triggers the factory against the given session's request context and caches the result so `getWorkspace()` returns it. Returns the resolved workspace or `undefined` if none is configured.
280
280
 
281
281
  ```typescript
282
- const workspace = await harness.resolveWorkspace({ session })
282
+ const workspace = await agentController.resolveWorkspace({ session })
283
283
  ```
284
284
 
285
285
  ```typescript
286
286
  // With an explicit request context
287
287
  const requestContext = new RequestContext()
288
- const workspace = await harness.resolveWorkspace({ session, requestContext })
288
+ const workspace = await agentController.resolveWorkspace({ session, requestContext })
289
289
  ```
290
290
 
291
291
  #### `hasWorkspace()`
292
292
 
293
- Whether a workspace is configured on this Harness (static instance or dynamic factory). Sessions without an explicit workspace override fall back to this.
293
+ Whether a workspace is configured on this AgentController (static instance or dynamic factory). Sessions without an explicit workspace override fall back to this.
294
294
 
295
295
  ```typescript
296
- if (harness.hasWorkspace()) {
296
+ if (agentController.hasWorkspace()) {
297
297
  // ...
298
298
  }
299
299
  ```
300
300
 
301
301
  #### `isWorkspaceReady()`
302
302
 
303
- Whether the Harness-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.
303
+ 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.
304
304
 
305
305
  ```typescript
306
- if (harness.isWorkspaceReady()) {
306
+ if (agentController.isWorkspaceReady()) {
307
307
  // ...
308
308
  }
309
309
  ```
@@ -312,24 +312,24 @@ if (harness.isWorkspaceReady()) {
312
312
 
313
313
  #### `listModes()`
314
314
 
315
- Return all configured `HarnessMode` instances.
315
+ Return all configured `AgentControllerMode` instances.
316
316
 
317
317
  ```typescript
318
- const modes = harness.listModes()
318
+ const modes = agentController.listModes()
319
319
  ```
320
320
 
321
- To read the active mode, use [`session.mode.get()`](https://mastra.ai/reference/harness/session); to resolve it to a full `HarnessMode`, use [`session.mode.resolve()`](https://mastra.ai/reference/harness/session).
321
+ 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).
322
322
 
323
323
  ### Models
324
324
 
325
- To read the active model ID, use [`session.model.get()`](https://mastra.ai/reference/harness/session); for a short display name, use [`session.model.displayName()`](https://mastra.ai/reference/harness/session); to check whether a model is selected, use [`session.model.hasSelection()`](https://mastra.ai/reference/harness/session).
325
+ 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).
326
326
 
327
327
  #### `getCurrentModelAuthStatus()`
328
328
 
329
329
  Check if the current model's provider has authentication configured. Uses `modelAuthChecker` if provided, falling back to environment variable checks from the provider registry.
330
330
 
331
331
  ```typescript
332
- const status = await harness.getCurrentModelAuthStatus()
332
+ const status = await agentController.getCurrentModelAuthStatus()
333
333
  // { hasAuth: true, apiKeyEnvVar: 'ANTHROPIC_API_KEY' }
334
334
  ```
335
335
 
@@ -338,20 +338,20 @@ const status = await harness.getCurrentModelAuthStatus()
338
338
  Retrieve all available models from the provider registry, including their authentication status and use counts.
339
339
 
340
340
  ```typescript
341
- const models = await harness.listAvailableModels()
341
+ const models = await agentController.listAvailableModels()
342
342
  // [{ id, provider, modelName, hasApiKey, apiKeyEnvVar, useCount }]
343
343
  ```
344
344
 
345
345
  ### Threads
346
346
 
347
- The harness 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/harness/session).
347
+ 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).
348
348
 
349
349
  #### `createThread({ title? })`
350
350
 
351
351
  Create a new thread. Initializes thread metadata, saves it to storage, acquires a thread lock, and emits a `thread_created` event.
352
352
 
353
353
  ```typescript
354
- const thread = await harness.createThread({ title: 'New conversation' })
354
+ const thread = await agentController.createThread({ title: 'New conversation' })
355
355
  ```
356
356
 
357
357
  #### `switchThread({ threadId })`
@@ -359,17 +359,17 @@ const thread = await harness.createThread({ title: 'New conversation' })
359
359
  Switch to a different thread. Aborts any in-progress operations, acquires a lock on the new thread, releases the lock on the previous thread, loads the thread's metadata, and emits a `thread_changed` event.
360
360
 
361
361
  ```typescript
362
- await harness.switchThread({ threadId: 'thread-abc123' })
362
+ await agentController.switchThread({ threadId: 'thread-abc123' })
363
363
  ```
364
364
 
365
- To list threads from storage, use [`session.thread.list()`](https://mastra.ai/reference/harness/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.
365
+ 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.
366
366
 
367
367
  #### `renameThread({ title })`
368
368
 
369
369
  Update the title of the current thread.
370
370
 
371
371
  ```typescript
372
- await harness.renameThread({ title: 'Updated title' })
372
+ await agentController.renameThread({ title: 'Updated title' })
373
373
  ```
374
374
 
375
375
  #### `cloneThread({ sourceThreadId?, title?, resourceId? })`
@@ -378,10 +378,10 @@ Clone an existing thread and switch to the clone. Copies all messages, acquires
378
378
 
379
379
  ```typescript
380
380
  // Clone the current thread
381
- const cloned = await harness.cloneThread()
381
+ const cloned = await agentController.cloneThread()
382
382
 
383
383
  // Clone a specific thread with a custom title
384
- const cloned = await harness.cloneThread({
384
+ const cloned = await agentController.cloneThread({
385
385
  sourceThreadId: 'thread-abc123',
386
386
  title: 'Alternative approach',
387
387
  })
@@ -389,14 +389,14 @@ const cloned = await harness.cloneThread({
389
389
 
390
390
  See [`Memory.cloneThread()`](https://mastra.ai/reference/memory/cloneThread) for details on what gets cloned.
391
391
 
392
- To read the current resource ID, use [`session.identity.getResourceId()`](https://mastra.ai/reference/harness/session).
392
+ To read the current resource ID, use [`session.identity.getResourceId()`](https://mastra.ai/reference/agent-controller/session).
393
393
 
394
394
  #### `setResourceId({ resourceId })`
395
395
 
396
396
  Set the resource ID and clear the current thread.
397
397
 
398
398
  ```typescript
399
- harness.setResourceId({ resourceId: 'project-xyz' })
399
+ agentController.setResourceId({ resourceId: 'project-xyz' })
400
400
  ```
401
401
 
402
402
  #### `getKnownResourceIds()`
@@ -404,7 +404,7 @@ harness.setResourceId({ resourceId: 'project-xyz' })
404
404
  Return the distinct resource IDs that have threads in storage.
405
405
 
406
406
  ```typescript
407
- const resourceIds = await harness.getKnownResourceIds()
407
+ const resourceIds = await agentController.getKnownResourceIds()
408
408
  ```
409
409
 
410
410
  #### `getSession()`
@@ -412,7 +412,7 @@ const resourceIds = await harness.getKnownResourceIds()
412
412
  Return current session information including thread ID, mode ID, and the list of threads.
413
413
 
414
414
  ```typescript
415
- const session = await harness.getSession()
415
+ const session = await agentController.getSession()
416
416
  // { currentThreadId, currentModeId, threads }
417
417
  ```
418
418
 
@@ -420,24 +420,24 @@ const session = await harness.getSession()
420
420
 
421
421
  #### `sendMessage({ content, files?, requestContext? })`
422
422
 
423
- 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 harness forwards it to tools and subagents during the run.
423
+ 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.
424
424
 
425
425
  ```typescript
426
- await harness.sendMessage({ content: 'Explain the authentication flow' })
426
+ await agentController.sendMessage({ content: 'Explain the authentication flow' })
427
427
  ```
428
428
 
429
- Reading messages is owned by [`session.thread`](https://mastra.ai/reference/harness/session): use `listActiveMessages()` for the active thread, `listMessages({ threadId })` for a specific thread, and `firstUserMessage({ threadId })` / `firstUserMessages({ threadIds })` for thread previews.
429
+ 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.
430
430
 
431
431
  ### Memory
432
432
 
433
- The `memory` property bundles thread management operations into a single namespace. `memory.createThread`, `memory.switchThread`, and `memory.renameThread` delegate to the corresponding Harness lifecycle methods documented above; `memory.listThreads` delegates to [`session.thread.list()`](https://mastra.ai/reference/harness/session).
433
+ 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).
434
434
 
435
435
  #### `memory.deleteThread({ threadId })`
436
436
 
437
- 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 harness clears its active thread. Emits a `thread_deleted` event.
437
+ 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.
438
438
 
439
439
  ```typescript
440
- await harness.memory.deleteThread({ threadId: 'thread-abc123' })
440
+ await agentController.memory.deleteThread({ threadId: 'thread-abc123' })
441
441
  ```
442
442
 
443
443
  ### Flow control
@@ -447,7 +447,7 @@ await harness.memory.deleteThread({ threadId: 'thread-abc123' })
447
447
  Abort any in-progress generation.
448
448
 
449
449
  ```typescript
450
- harness.abort()
450
+ agentController.abort()
451
451
  ```
452
452
 
453
453
  #### `steer({ content, requestContext? })`
@@ -455,7 +455,7 @@ harness.abort()
455
455
  Steer the agent mid-stream by injecting an instruction into the current generation.
456
456
 
457
457
  ```typescript
458
- harness.steer({ content: 'Focus on security implications' })
458
+ agentController.steer({ content: 'Focus on security implications' })
459
459
  ```
460
460
 
461
461
  #### `followUp({ content, requestContext? })`
@@ -463,12 +463,12 @@ harness.steer({ content: 'Focus on security implications' })
463
463
  Queue a follow-up message to be sent after the current generation completes. If no operation is running, sends the message immediately.
464
464
 
465
465
  ```typescript
466
- harness.followUp({ content: 'Now apply those changes' })
466
+ agentController.followUp({ content: 'Now apply those changes' })
467
467
  ```
468
468
 
469
469
  ### Tool approvals
470
470
 
471
- Responding to a pending tool approval is owned by the session — see [`session.respondToToolApproval()`](https://mastra.ai/reference/harness/session). The harness owns the permission _policy_ that decides when approval is required, documented under [Permissions](#permissions) below.
471
+ 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.
472
472
 
473
473
  ### Tool suspensions and plans
474
474
 
@@ -479,11 +479,11 @@ Respond to a pending tool suspension. Interactive built-in tools such as `ask_us
479
479
  Provide `toolCallId` to select which suspension to resume. It is required when more than one tool is suspended at the same time (for example, parallel `ask_user` calls). When omitted, it resolves to the sole pending suspension.
480
480
 
481
481
  ```typescript
482
- harness.subscribe(event => {
482
+ agentController.subscribe(event => {
483
483
  if (event.type === 'tool_suspended' && event.toolName === 'ask_user') {
484
484
  const { question } = event.suspendPayload as { question: string }
485
485
  // Show `question` to the user, then resume the tool with their answer.
486
- harness.respondToToolSuspension({
486
+ agentController.respondToToolSuspension({
487
487
  toolCallId: event.toolCallId,
488
488
  resumeData: 'Yes, proceed with the refactor',
489
489
  })
@@ -494,7 +494,7 @@ harness.subscribe(event => {
494
494
  For multi-select questions, pass the selected option labels as a string array.
495
495
 
496
496
  ```typescript
497
- harness.respondToToolSuspension({
497
+ agentController.respondToToolSuspension({
498
498
  toolCallId: event.toolCallId,
499
499
  resumeData: ['Add tests', 'Update docs'],
500
500
  })
@@ -504,14 +504,14 @@ harness.respondToToolSuspension({
504
504
 
505
505
  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.
506
506
 
507
- On approval, the Harness automatically switches to its default (execution) mode. On rejection, the plan-mode run resumes so the agent can revise and submit again.
507
+ 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.
508
508
 
509
509
  ```typescript
510
- harness.respondToToolSuspension({
510
+ agentController.respondToToolSuspension({
511
511
  toolCallId: event.toolCallId,
512
512
  resumeData: { action: 'approved' },
513
513
  })
514
- harness.respondToToolSuspension({
514
+ agentController.respondToToolSuspension({
515
515
  toolCallId: event.toolCallId,
516
516
  resumeData: { action: 'rejected', feedback: 'Needs more detail' },
517
517
  })
@@ -524,7 +524,7 @@ harness.respondToToolSuspension({
524
524
  Resolve a tool's category using the configured `toolCategoryResolver`.
525
525
 
526
526
  ```typescript
527
- const category = harness.getToolCategory({ toolName: 'mastra_workspace_write_file' })
527
+ const category = agentController.getToolCategory({ toolName: 'mastra_workspace_write_file' })
528
528
  // 'edit'
529
529
  ```
530
530
 
@@ -535,7 +535,7 @@ const category = harness.getToolCategory({ toolName: 'mastra_workspace_write_fil
535
535
  Load observational memory records for the current thread and emit an `om_status` event with reconstructed progress.
536
536
 
537
537
  ```typescript
538
- await harness.loadOMProgress()
538
+ await agentController.loadOMProgress()
539
539
  ```
540
540
 
541
541
  #### `getObservationalMemoryRecord()`
@@ -543,7 +543,7 @@ await harness.loadOMProgress()
543
543
  Return the full `ObservationalMemoryRecord` for the current thread and resource, or `null` if no thread is selected or no record exists.
544
544
 
545
545
  ```typescript
546
- const record = await harness.getObservationalMemoryRecord()
546
+ const record = await agentController.getObservationalMemoryRecord()
547
547
 
548
548
  if (record) {
549
549
  console.log(record.activeObservations)
@@ -552,7 +552,7 @@ if (record) {
552
552
  }
553
553
  ```
554
554
 
555
- The observer/reflector model selection and observation/reflection thresholds live on the Session under [`session.om`](https://mastra.ai/reference/harness/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()`.
555
+ 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()`.
556
556
 
557
557
  ### Forked subagents
558
558
 
@@ -560,11 +560,11 @@ By default, a subagent runs with a fresh context — it doesn't see the parent c
560
560
 
561
561
  #### Enabling forked mode
562
562
 
563
- Set `forked: true` either on the `HarnessSubagent` definition (per-type default) or on each `subagent` tool call (per-invocation override):
563
+ Set `forked: true` either on the `AgentControllerSubagent` definition (per-type default) or on each `subagent` tool call (per-invocation override):
564
564
 
565
565
  ```typescript
566
566
  // Per-type default — every call to this subagent forks unless overridden.
567
- const subagents: HarnessSubagent[] = [
567
+ const subagents: AgentControllerSubagent[] = [
568
568
  {
569
569
  id: 'collaborator',
570
570
  name: 'Collaborator',
@@ -579,10 +579,10 @@ The model can also pass `forked: true` (or `forked: false`) per-invocation in th
579
579
 
580
580
  #### Semantics and constraints
581
581
 
582
- - **Memory required.** Forked mode calls `memory.cloneThread` to create the fork, so the harness must have `memory` configured and an active parent thread. Calls without those return a structured error rather than throwing.
583
- - **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`, `allowedHarnessTools`, `allowedWorkspaceTools`, `defaultModelId`, `maxSteps`, and `stopWhen` are ignored in forked mode — this is what preserves the prompt-cache prefix.
584
- - **Toolsets inherited, recursive forks blocked at runtime.** Forks inherit the parent's toolsets verbatim (`ask_user`, `submit_plan`, user-configured harness 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.
585
- - **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/harness/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.
582
+ - **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.
583
+ - **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 is what preserves the prompt-cache prefix.
584
+ - **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.
585
+ - **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.
586
586
  - **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.
587
587
  - **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.
588
588
 
@@ -596,24 +596,24 @@ Forked mode trades isolation for context inheritance. If the subagent should run
596
596
 
597
597
  Register an event listener. Returns an unsubscribe function.
598
598
 
599
- 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/harness/session). After every event the harness emits `display_state_changed`, so high-frequency events such as `message_update`, `tool_update`, and `tool_input_delta` are coalesced into the next snapshot.
599
+ 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.
600
600
 
601
601
  ```typescript
602
602
  // Render from the coalesced display-state snapshot:
603
- const unsubscribe = harness.subscribe(event => {
603
+ const unsubscribe = agentController.subscribe(event => {
604
604
  if (event.type === 'display_state_changed') {
605
- render(harness.session.displayState.get())
605
+ render(agentController.session.displayState.get())
606
606
  }
607
607
  })
608
608
 
609
- // Render an initial frame before the next harness event:
610
- render(harness.session.displayState.get())
609
+ // Render an initial frame before the next agentController event:
610
+ render(agentController.session.displayState.get())
611
611
  ```
612
612
 
613
613
  To handle raw events directly, switch on `event.type`:
614
614
 
615
615
  ```typescript
616
- const unsubscribe = harness.subscribe(event => {
616
+ const unsubscribe = agentController.subscribe(event => {
617
617
  switch (event.type) {
618
618
  case 'message_update':
619
619
  renderMessage(event.message)
@@ -633,7 +633,7 @@ unsubscribe()
633
633
 
634
634
  ## Events
635
635
 
636
- The harness emits events through registered listeners. The following table lists the available event types:
636
+ The agentController emits events through registered listeners. The following table lists the available event types:
637
637
 
638
638
  | Event type | Description |
639
639
  | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -642,7 +642,7 @@ The harness emits events through registered listeners. The following table lists
642
642
  | `thread_changed` | The active thread changed. |
643
643
  | `thread_created` | A new thread was created. |
644
644
  | `thread_deleted` | A thread was deleted. |
645
- | `state_changed` | Harness state was updated. |
645
+ | `state_changed` | AgentController state was updated. |
646
646
  | `agent_start` | The agent started processing. |
647
647
  | `agent_end` | The agent finished processing. |
648
648
  | `message_start` | A new message started streaming. |
@@ -690,13 +690,13 @@ The harness emits events through registered listeners. The following table lists
690
690
  | `task_updated` | A task list was updated. |
691
691
  | `goal_evaluation` | A goal evaluation completed (when native agent goals are configured). |
692
692
  | `shell_output` | A tool emitted shell output (stdout or stderr). |
693
- | `display_state_changed` | The canonical `HarnessDisplayState` snapshot changed. Read it from [`session.displayState.get()`](https://mastra.ai/reference/harness/session). |
693
+ | `display_state_changed` | The canonical `AgentControllerDisplayState` snapshot changed. Read it from [`session.displayState.get()`](https://mastra.ai/reference/agent-controller/session). |
694
694
 
695
- The harness 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/harness/session) snapshot) rather than subscribing to them directly.
695
+ 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.
696
696
 
697
697
  ## Built-in tools
698
698
 
699
- The harness provides built-in tools to agents in every mode:
699
+ The agentController provides built-in tools to agents in every mode:
700
700
 
701
701
  | Tool | Description |
702
702
  | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -715,11 +715,11 @@ The `ask_user` tool accepts `options` for choice prompts. Set `selectionMode` to
715
715
  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()`.
716
716
 
717
717
  ```typescript
718
- harness.subscribe(event => {
718
+ agentController.subscribe(event => {
719
719
  if (event.type === 'tool_suspended' && event.toolName === 'ask_user') {
720
720
  const { selectionMode } = event.suspendPayload as { selectionMode?: string }
721
721
  if (selectionMode === 'multi_select') {
722
- harness.respondToToolSuspension({
722
+ agentController.respondToToolSuspension({
723
723
  toolCallId: event.toolCallId,
724
724
  resumeData: ['Add tests', 'Update docs'],
725
725
  })
@@ -730,7 +730,7 @@ harness.subscribe(event => {
730
730
 
731
731
  ## Related
732
732
 
733
- - [Session class](https://mastra.ai/reference/harness/session)
734
- - [Harness overview](https://mastra.ai/docs/harness/overview)
735
- - [Threads and state](https://mastra.ai/docs/harness/threads-and-state)
736
- - [Tool approvals](https://mastra.ai/docs/harness/tool-approvals)
733
+ - [Session class](https://mastra.ai/reference/agent-controller/session)
734
+ - [AgentController overview](https://mastra.ai/docs/agent-controller/overview)
735
+ - [Threads and state](https://mastra.ai/docs/agent-controller/threads-and-state)
736
+ - [Tool approvals](https://mastra.ai/docs/agent-controller/tool-approvals)