@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,30 +1,31 @@
1
1
  > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
2
 
3
- # Session class
3
+ # Session
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
- A `Session` owns all the state tied to a single conversation. The [`AgentController`](https://mastra.ai/reference/agent-controller/agent-controller-class) is the shared host (agents, storage, config, the thread lock, and the event bus) while the `Session` holds everything that's per-conversation: identity, the active thread binding and reads, mode and model selection, run and abort state, the live agent stream, tool suspensions, follow-ups, approvals, permission grants, token usage, and the display-state snapshot.
7
+ A `Session` is the isolated runtime for one resource and optional scope. It owns its event bus, thread binding, state, mode and model selections, run control, approvals, suspensions, follow-ups, and display state. The [`AgentController`](https://mastra.ai/reference/agent-controller/agent-controller-class) supplies shared agents, configuration, storage, workspaces, and services.
8
8
 
9
- Access the session through `agentController.session`.
9
+ Create sessions through `controller.createSession()`. Direct construction and controller wiring methods aren't application APIs.
10
10
 
11
- For a conceptual introduction, see the [AgentController overview](https://mastra.ai/docs/agent-controller/overview).
11
+ For a conceptual introduction, see the [AgentController overview](https://mastra.ai/docs/harness/agent-controller).
12
12
 
13
13
  ## Usage example
14
14
 
15
+ The following example uses the supported controller-to-session flow.
16
+
15
17
  ```typescript
16
- // Read per-conversation state through agentController.session
17
- const modeId = agentController.session.mode.get()
18
- const modelId = agentController.session.model.get()
19
- const threadId = agentController.session.thread.getId()
20
- const grants = agentController.session.getGrants()
18
+ await controller.init()
21
19
 
22
- // Render from the coalesced display-state snapshot
23
- agentController.subscribe(event => {
20
+ const session = await controller.createSession({ resourceId: 'project-42' })
21
+ const unsubscribe = session.subscribe(event => {
24
22
  if (event.type === 'display_state_changed') {
25
- render(agentController.session.displayState.get())
23
+ render(event.displayState)
26
24
  }
27
25
  })
26
+
27
+ await session.sendMessage({ content: 'Review the current project.' })
28
+ unsubscribe()
28
29
  ```
29
30
 
30
31
  ## Properties
@@ -39,6 +40,12 @@ The session is organized into sub-objects, each owning one domain of per-convers
39
40
 
40
41
  **model** (`SessionModel`): Active model selection, including per-mode persistence. See model methods below.
41
42
 
43
+ **om** (`SessionOM`): Observer and reflector model settings for observational memory.
44
+
45
+ **permissions** (`SessionPermissions`): Tool and category permission policies represented in session state.
46
+
47
+ **subagents** (`SessionSubagents`): Global and per-agent-type subagent model selection.
48
+
42
49
  **run** (`SessionRun`): Run and trace identity plus abort state for the in-flight run. See run methods below.
43
50
 
44
51
  **stream** (`SessionStream`): The live subscription to the agent thread stream. See stream methods below.
@@ -51,12 +58,85 @@ The session is organized into sub-objects, each owning one domain of per-convers
51
58
 
52
59
  **displayState** (`SessionDisplayState`): The canonical AgentControllerDisplayState snapshot a UI renders from. See display-state methods below.
53
60
 
54
- **state** (`SessionState<TState>`): The schema-validated, session-owned AgentController state. See state methods below.
61
+ **state** (`AgentControllerRequestState<TState>`): The schema-validated, session-owned AgentController state. See state methods below.
55
62
 
56
63
  **browser** (`MastraBrowser | undefined`): The browser automation instance for this session. Set at creation via createSession, or from the AgentController config default. Undefined when no browser is configured.
57
64
 
58
65
  ## Methods
59
66
 
67
+ ### Identity and events
68
+
69
+ #### `getTags()`
70
+
71
+ Return a copy of the tags supplied when the session was created.
72
+
73
+ ```typescript
74
+ const tags = session.getTags()
75
+ ```
76
+
77
+ Returns: `Record<string, string>`
78
+
79
+ #### `subscribe(listener)`
80
+
81
+ Subscribe to this session's isolated event bus. The method returns an unsubscribe function.
82
+
83
+ ```typescript
84
+ const unsubscribe = session.subscribe(event => {
85
+ console.log(event.type)
86
+ })
87
+
88
+ unsubscribe()
89
+ ```
90
+
91
+ Returns: `() => void`
92
+
93
+ ### Messages and run control
94
+
95
+ #### `sendMessage({ content, files?, requestContext? })`
96
+
97
+ Send a user message. The session creates a thread first when no thread is active.
98
+
99
+ ```typescript
100
+ await session.sendMessage({
101
+ content: 'Summarize this file.',
102
+ files: [{ data: fileContents, mediaType: 'text/plain', filename: 'notes.txt' }],
103
+ })
104
+ ```
105
+
106
+ #### `steer({ content, requestContext? })`
107
+
108
+ Queue steering content into an active run.
109
+
110
+ ```typescript
111
+ await session.steer({ content: 'Focus on the failing tests.' })
112
+ ```
113
+
114
+ #### `followUp({ content, requestContext? })`
115
+
116
+ Queue a follow-up while a run is active, or send it immediately while idle.
117
+
118
+ ```typescript
119
+ await session.followUp({ content: 'Then propose a fix.' })
120
+ ```
121
+
122
+ #### `getCurrentRunId()`
123
+
124
+ Return the active stream run identifier, the tracked run identifier, or `null` while idle.
125
+
126
+ ```typescript
127
+ const runId = session.getCurrentRunId()
128
+ ```
129
+
130
+ Returns: `string | null`
131
+
132
+ #### `abort()`
133
+
134
+ Abort the active run and clear pending suspension display state.
135
+
136
+ ```typescript
137
+ session.abort()
138
+ ```
139
+
60
140
  ### Workspace
61
141
 
62
142
  #### `getWorkspace()`
@@ -64,13 +144,13 @@ The session is organized into sub-objects, each owning one domain of per-convers
64
144
  Return the workspace resolved for this session. This preserves session-level overrides and workspaces selected from the session scope.
65
145
 
66
146
  ```typescript
67
- const workspace = agentController.session.getWorkspace()
147
+ const workspace = session.getWorkspace()
68
148
  const skill = await workspace.skills?.get('code-review')
69
149
  ```
70
150
 
71
151
  Returns: `Workspace`
72
152
 
73
- ### Permissions
153
+ ### Session grants
74
154
 
75
155
  Session-scoped grants auto-approve tools without prompting. Grants are ephemeral: they reset when the session restarts and are never persisted.
76
156
 
@@ -79,7 +159,7 @@ Session-scoped grants auto-approve tools without prompting. Grants are ephemeral
79
159
  Grant a tool category for the current session. Tools in this category are auto-approved.
80
160
 
81
161
  ```typescript
82
- agentController.session.grantCategory('edit')
162
+ session.grantCategory('edit')
83
163
  ```
84
164
 
85
165
  #### `grantTool(toolName)`
@@ -87,7 +167,7 @@ agentController.session.grantCategory('edit')
87
167
  Grant a specific tool for the current session.
88
168
 
89
169
  ```typescript
90
- agentController.session.grantTool('mastra_workspace_execute_command')
170
+ session.grantTool('mastra_workspace_execute_command')
91
171
  ```
92
172
 
93
173
  #### `getGrants()`
@@ -95,40 +175,65 @@ agentController.session.grantTool('mastra_workspace_execute_command')
95
175
  Return the currently granted categories and tools.
96
176
 
97
177
  ```typescript
98
- const grants = agentController.session.getGrants()
178
+ const grants = session.getGrants()
99
179
  // { categories: string[], tools: string[] }
100
180
  ```
101
181
 
182
+ #### `hasCategoryGrant(category)`
183
+
184
+ Return whether a category has an in-memory session grant.
185
+
186
+ ```typescript
187
+ const allowed = session.hasCategoryGrant('edit')
188
+ ```
189
+
190
+ Returns: `boolean`
191
+
192
+ #### `hasToolGrant(toolName)`
193
+
194
+ Return whether a tool has an in-memory session grant.
195
+
196
+ ```typescript
197
+ const allowed = session.hasToolGrant('write_file')
198
+ ```
199
+
200
+ Returns: `boolean`
201
+
102
202
  ### Tool approvals
103
203
 
104
- #### `respondToToolApproval({ decision, requestContext? })`
204
+ #### `resolveToolApproval(toolName)`
105
205
 
106
- Respond to a pending tool approval request, raised by a `tool_approval_required` event. Pass `always_allow_category` to also grant the tool's whole category for the rest of the session.
206
+ Return the effective policy after applying explicit tool rules, session grants, and category rules.
107
207
 
108
208
  ```typescript
109
- agentController.session.respondToToolApproval({ decision: 'approve' })
110
- agentController.session.respondToToolApproval({ decision: 'decline' })
111
- agentController.session.respondToToolApproval({ decision: 'always_allow_category' })
209
+ const policy = session.resolveToolApproval('execute_command')
112
210
  ```
113
211
 
114
- ### Run control
212
+ Returns: `PermissionPolicy`
115
213
 
116
- #### `getCurrentRunId()`
214
+ #### `respondToToolApproval({ decision, toolCallId?, requestContext?, declineContext? })`
117
215
 
118
- Return the run ID of the in-flight run, or `null` when idle. Prefers the live stream's active run, falling back to the last stored run ID.
216
+ Respond to a pending tool approval request, raised by a `tool_approval_required` event. Pass `always_allow_category` to also grant the tool's whole category for the rest of the session.
119
217
 
120
218
  ```typescript
121
- const runId = agentController.session.getCurrentRunId()
219
+ session.respondToToolApproval({ decision: 'approve' })
220
+ session.respondToToolApproval({ decision: 'decline' })
221
+ session.respondToToolApproval({ decision: 'always_allow_category' })
122
222
  ```
123
223
 
124
- #### `abortRun()`
224
+ #### `respondToToolSuspension({ resumeData, toolCallId?, requestContext? })`
125
225
 
126
- Abort the in-flight run: aborts the live stream and requests abort on the run. It also clears parked tool suspensions.
226
+ Resume a suspended tool with application-provided data. Supply `toolCallId` when several tool calls are suspended.
127
227
 
128
228
  ```typescript
129
- agentController.session.abortRun()
229
+ await session.respondToToolSuspension({
230
+ toolCallId: event.toolCallId,
231
+ resumeData: ['src'],
232
+ })
130
233
  ```
131
234
 
235
+ For `submit_plan`, pass `{ action: 'approved' }` or `{ action: 'rejected', feedback }`. Approval can switch to the mode configured by `transitionsTo` before the tool resumes.
236
+
132
237
  ### Token usage
133
238
 
134
239
  #### `getTokenUsage()`
@@ -136,7 +241,7 @@ agentController.session.abortRun()
136
241
  Return a copy of the running token-usage tally for the active thread.
137
242
 
138
243
  ```typescript
139
- const usage = agentController.session.getTokenUsage()
244
+ const usage = session.getTokenUsage()
140
245
  // { promptTokens, completionTokens, totalTokens, ... }
141
246
  ```
142
247
 
@@ -149,7 +254,7 @@ const usage = agentController.session.getTokenUsage()
149
254
  Return the stable session identifier.
150
255
 
151
256
  ```typescript
152
- const sessionId = agentController.session.identity.getId()
257
+ const sessionId = session.identity.getId()
153
258
  ```
154
259
 
155
260
  ### `session.identity.getOwnerId()`
@@ -157,7 +262,7 @@ const sessionId = agentController.session.identity.getId()
157
262
  Return the stable owner identifier for the session.
158
263
 
159
264
  ```typescript
160
- const ownerId = agentController.session.identity.getOwnerId()
265
+ const ownerId = session.identity.getOwnerId()
161
266
  ```
162
267
 
163
268
  ### `session.identity.getResourceId()`
@@ -165,7 +270,7 @@ const ownerId = agentController.session.identity.getOwnerId()
165
270
  Return the current resource ID.
166
271
 
167
272
  ```typescript
168
- const resourceId = agentController.session.identity.getResourceId()
273
+ const resourceId = session.identity.getResourceId()
169
274
  ```
170
275
 
171
276
  ### `session.identity.getDefaultResourceId()`
@@ -173,21 +278,71 @@ const resourceId = agentController.session.identity.getResourceId()
173
278
  Return the resource ID the session was created with.
174
279
 
175
280
  ```typescript
176
- const defaultResourceId = agentController.session.identity.getDefaultResourceId()
281
+ const defaultResourceId = session.identity.getDefaultResourceId()
177
282
  ```
178
283
 
179
- To change the resource ID, use [`agentController.setResourceId()`](https://mastra.ai/reference/agent-controller/agent-controller-class), which also tears down the active thread. The session `id` and `ownerId` aren't affected by resource switches.
284
+ To change the resource ID, use [`controller.setResourceId()`](https://mastra.ai/reference/agent-controller/agent-controller-class), which also clears the active thread. The session `id` and `ownerId` aren't affected by resource switches.
180
285
 
181
286
  ## Thread
182
287
 
183
- `session.thread` owns the active thread binding plus thread and message reads. Thread lifecycle (create, switch, clone, delete, rename) lives on the [`AgentController`](https://mastra.ai/reference/agent-controller/agent-controller-class) because it coordinates the shared thread lock and event bus.
288
+ `session.thread` owns the active thread binding and resource-scoped thread operations. Stored threads and messages can survive controller recreation when storage is configured. The live session and its event bus don't.
289
+
290
+ ### `session.thread.create({ title?, id? })`
291
+
292
+ Create a thread, bind the session to it, and open its event stream.
293
+
294
+ ```typescript
295
+ const thread = await session.thread.create({
296
+ id: 'thread-7',
297
+ title: 'Investigate login failure',
298
+ })
299
+ ```
300
+
301
+ Returns: `Promise<AgentControllerThread>`
302
+
303
+ ### `session.thread.rename({ title })`
304
+
305
+ Rename the active stored thread.
306
+
307
+ ```typescript
308
+ await session.thread.rename({ title: 'Fix login failure' })
309
+ ```
310
+
311
+ ### `session.thread.clone({ sourceThreadId?, title?, resourceId? })`
312
+
313
+ Clone an owned thread and its messages, then bind the session to the clone.
314
+
315
+ ```typescript
316
+ const clone = await session.thread.clone({
317
+ sourceThreadId: 'thread-7',
318
+ title: 'Alternative approach',
319
+ })
320
+ ```
321
+
322
+ Returns: `Promise<AgentControllerThread>`
323
+
324
+ ### `session.thread.switch({ threadId, emitEvent? })`
325
+
326
+ Switch to an owned stored thread and hydrate its mode, model, and observational memory settings.
327
+
328
+ ```typescript
329
+ await session.thread.switch({ threadId: 'thread-8' })
330
+ ```
331
+
332
+ ### `session.thread.delete({ threadId })`
333
+
334
+ Delete an owned thread. Deleting the active thread also clears the current binding.
335
+
336
+ ```typescript
337
+ await session.thread.delete({ threadId: 'thread-8' })
338
+ ```
184
339
 
185
340
  ### `session.thread.getId()`
186
341
 
187
342
  Return the active thread ID, or `null` when no thread is bound.
188
343
 
189
344
  ```typescript
190
- const threadId = agentController.session.thread.getId()
345
+ const threadId = session.thread.getId()
191
346
  ```
192
347
 
193
348
  ### `session.thread.list(options?)`
@@ -195,9 +350,9 @@ const threadId = agentController.session.thread.getId()
195
350
  List threads from storage. By default only threads for the current resource are returned, and transient forked subagent threads are hidden.
196
351
 
197
352
  ```typescript
198
- const threads = await agentController.session.thread.list()
199
- const allThreads = await agentController.session.thread.list({ allResources: true })
200
- const everything = await agentController.session.thread.list({ includeForkedSubagents: true })
353
+ const threads = await session.thread.list()
354
+ const allThreads = await session.thread.list({ allResources: true })
355
+ const everything = await session.thread.list({ includeForkedSubagents: true })
201
356
  ```
202
357
 
203
358
  ### `session.thread.getById({ threadId })`
@@ -205,7 +360,7 @@ const everything = await agentController.session.thread.list({ includeForkedSuba
205
360
  Return a single thread by ID, or `null` if it doesn't exist.
206
361
 
207
362
  ```typescript
208
- const thread = await agentController.session.thread.getById({ threadId: 'thread-abc123' })
363
+ const thread = await session.thread.getById({ threadId: 'thread-abc123' })
209
364
  ```
210
365
 
211
366
  ### `session.thread.listActiveMessages(options?)`
@@ -213,7 +368,7 @@ const thread = await agentController.session.thread.getById({ threadId: 'thread-
213
368
  Retrieve messages for the active thread. Returns an empty array when no thread is bound.
214
369
 
215
370
  ```typescript
216
- const messages = await agentController.session.thread.listActiveMessages({ limit: 50 })
371
+ const messages = await session.thread.listActiveMessages({ limit: 50 })
217
372
  ```
218
373
 
219
374
  ### `session.thread.listMessages({ threadId, limit? })`
@@ -221,7 +376,7 @@ const messages = await agentController.session.thread.listActiveMessages({ limit
221
376
  Retrieve messages for a specific thread.
222
377
 
223
378
  ```typescript
224
- const messages = await agentController.session.thread.listMessages({ threadId: 'thread-abc123' })
379
+ const messages = await session.thread.listMessages({ threadId: 'thread-abc123' })
225
380
  ```
226
381
 
227
382
  The message-reading methods `listActiveMessages`, `listMessages`, and `firstUserMessage` return `MastraDBMessage` objects, while `firstUserMessages` returns a `Map<string, MastraDBMessage>` keyed by thread ID. Each message has a `role`, an `id`, a `createdAt`, and a `content` object with `content.format` and a `content.parts` array. Read text, reasoning, tool calls, and attachments from `content.parts`. Signals such as system reminders and notifications are returned as separate messages with `role: 'signal'`.
@@ -231,7 +386,7 @@ The message-reading methods `listActiveMessages`, `listMessages`, and `firstUser
231
386
  Retrieve the first user message for a thread, or `null` if none.
232
387
 
233
388
  ```typescript
234
- const firstMsg = await agentController.session.thread.firstUserMessage({
389
+ const firstMsg = await session.thread.firstUserMessage({
235
390
  threadId: 'thread-abc123',
236
391
  })
237
392
  ```
@@ -241,19 +396,33 @@ const firstMsg = await agentController.session.thread.firstUserMessage({
241
396
  Retrieve the first user message for many threads at once, returned as a map.
242
397
 
243
398
  ```typescript
244
- const firstByThread = await agentController.session.thread.firstUserMessages({
399
+ const firstByThread = await session.thread.firstUserMessages({
245
400
  threadIds: ['thread-a', 'thread-b'],
246
401
  })
247
402
  ```
248
403
 
249
- ### `session.thread.getSetting({ key })` / `setSetting({ key, value })` / `deleteSetting({ key })`
404
+ ### `session.thread.getSetting({ key })`
250
405
 
251
- Read, write, and remove per-thread settings stored on the active thread's metadata.
406
+ Read a setting from the active thread metadata.
252
407
 
253
408
  ```typescript
254
- await agentController.session.thread.setSetting({ key: 'omThreshold', value: 0.8 })
255
- const value = await agentController.session.thread.getSetting({ key: 'omThreshold' })
256
- await agentController.session.thread.deleteSetting({ key: 'omThreshold' })
409
+ const value = await session.thread.getSetting({ key: 'omThreshold' })
410
+ ```
411
+
412
+ ### `session.thread.setSetting({ key, value })`
413
+
414
+ Write a setting to the active thread metadata.
415
+
416
+ ```typescript
417
+ await session.thread.setSetting({ key: 'omThreshold', value: 0.8 })
418
+ ```
419
+
420
+ ### `session.thread.deleteSetting({ key })`
421
+
422
+ Remove a setting from the active thread metadata.
423
+
424
+ ```typescript
425
+ await session.thread.deleteSetting({ key: 'omThreshold' })
257
426
  ```
258
427
 
259
428
  ## Mode
@@ -265,23 +434,23 @@ await agentController.session.thread.deleteSetting({ key: 'omThreshold' })
265
434
  Return the active mode ID.
266
435
 
267
436
  ```typescript
268
- const modeId = agentController.session.mode.get()
437
+ const modeId = session.mode.get()
269
438
  ```
270
439
 
271
440
  ### `session.mode.resolve()`
272
441
 
273
- Return the full `AgentControllerMode` object for the active mode, resolved against the agentController's configured modes.
442
+ Return the full `AgentControllerMode` object for the active mode, resolved against the controller's configured modes.
274
443
 
275
444
  ```typescript
276
- const mode = agentController.session.mode.resolve()
445
+ const mode = session.mode.resolve()
277
446
  ```
278
447
 
279
448
  ### `session.mode.switch({ modeId })`
280
449
 
281
- Switch to a different mode. Aborts any in-progress generation and saves the current model to the outgoing mode. It then loads the incoming mode's model and emits `mode_changed` and `model_changed` events.
450
+ Switch to another mode. The session saves the outgoing mode's model before persisting the new mode on the active thread. It then restores the incoming mode's selected or default model. The session emits `mode_changed` immediately and `model_changed` after model resolution.
282
451
 
283
452
  ```typescript
284
- await agentController.session.mode.switch({ modeId: 'build' })
453
+ await session.mode.switch({ modeId: 'build' })
285
454
  ```
286
455
 
287
456
  ## Model
@@ -293,15 +462,15 @@ await agentController.session.mode.switch({ modeId: 'build' })
293
462
  Return the active model ID.
294
463
 
295
464
  ```typescript
296
- const modelId = agentController.session.model.get()
465
+ const modelId = session.model.get()
297
466
  ```
298
467
 
299
468
  ### `session.model.displayName()`
300
469
 
301
- Return a short display name for the active model: the last segment of the model ID (for example, `claude-sonnet-4` from `anthropic/claude-sonnet-4`). Returns `'unknown'` when no model is selected.
470
+ Return the last segment of the active model ID as a short display name. Returns `'unknown'` when no model is selected.
302
471
 
303
472
  ```typescript
304
- const name = agentController.session.model.displayName()
473
+ const name = session.model.displayName()
305
474
  ```
306
475
 
307
476
  ### `session.model.hasSelection()`
@@ -309,37 +478,37 @@ const name = agentController.session.model.displayName()
309
478
  Check whether a model is currently selected.
310
479
 
311
480
  ```typescript
312
- if (agentController.session.model.hasSelection()) {
481
+ if (session.model.hasSelection()) {
313
482
  // Ready to send messages
314
483
  }
315
484
  ```
316
485
 
317
486
  ### `session.model.switch({ modelId, scope?, modeId? })`
318
487
 
319
- Switch the active model. When `scope` is `'thread'` (the default), the model ID is persisted as the per-mode model so it's restored when switching back. Reports the selection to the agentController's `modelUseCountTracker` and emits a `model_changed` event.
488
+ Switch the active model. When `scope` is `'thread'` (the default), the model ID is persisted as the per-mode model so it's restored when switching back. Reports the selection to the controller's `modelUseCountTracker` and emits a `model_changed` event.
320
489
 
321
490
  ```typescript
322
491
  // Set for the current session only
323
- await agentController.session.model.switch({
492
+ await session.model.switch({
324
493
  modelId: 'anthropic/claude-sonnet-4-6',
325
494
  scope: 'global',
326
495
  })
327
496
 
328
497
  // Persist to the current thread (default)
329
- await agentController.session.model.switch({ modelId: 'anthropic/claude-sonnet-4-6' })
498
+ await session.model.switch({ modelId: 'anthropic/claude-sonnet-4-6' })
330
499
  ```
331
500
 
332
501
  ## Observational Memory
333
502
 
334
- The observational-memory model selection, grouped by role under `session.om.observer` and `session.om.reflector`. Both roles expose the same methods. Reads return the value from session state when set, falling back to the agentController's `omConfig` defaults.
503
+ The observational-memory model selection, grouped by role under `session.om.observer` and `session.om.reflector`. Both roles expose the same methods. Reads return the value from session state when set, falling back to the controller's `omConfig` defaults.
335
504
 
336
505
  ### `session.om.observer.modelId()` / `session.om.reflector.modelId()`
337
506
 
338
507
  Return the role's model ID, or `undefined` when neither session state nor `omConfig` provides one.
339
508
 
340
509
  ```typescript
341
- const observer = agentController.session.om.observer.modelId()
342
- const reflector = agentController.session.om.reflector.modelId()
510
+ const observer = session.om.observer.modelId()
511
+ const reflector = session.om.reflector.modelId()
343
512
  ```
344
513
 
345
514
  ### `session.om.observer.threshold()` / `session.om.reflector.threshold()`
@@ -347,8 +516,8 @@ const reflector = agentController.session.om.reflector.modelId()
347
516
  Return the role's threshold in tokens (observation threshold for the observer, reflection threshold for the reflector), or `undefined` when unset.
348
517
 
349
518
  ```typescript
350
- const observationThreshold = agentController.session.om.observer.threshold()
351
- const reflectionThreshold = agentController.session.om.reflector.threshold()
519
+ const observationThreshold = session.om.observer.threshold()
520
+ const reflectionThreshold = session.om.reflector.threshold()
352
521
  ```
353
522
 
354
523
  ### `session.om.observer.switchModel({ modelId })` / `session.om.reflector.switchModel({ modelId })`
@@ -356,32 +525,33 @@ const reflectionThreshold = agentController.session.om.reflector.threshold()
356
525
  Switch the role's model. Persists the setting to thread metadata and emits an `om_model_changed` event.
357
526
 
358
527
  ```typescript
359
- await agentController.session.om.observer.switchModel({
528
+ await session.om.observer.switchModel({
360
529
  modelId: 'anthropic/claude-haiku-4-5',
361
530
  })
362
- await agentController.session.om.reflector.switchModel({
531
+ await session.om.reflector.switchModel({
363
532
  modelId: 'anthropic/claude-haiku-4-5',
364
533
  })
365
534
  ```
366
535
 
367
536
  ### `session.om.observer.resolvedModel()` / `session.om.reflector.resolvedModel()`
368
537
 
369
- Resolve the role's model ID to a model instance via the agentController's `resolveModel`, or `undefined` when no model ID is set or no resolver is configured.
538
+ Resolve the role's model ID to a model instance via the configured model gateways, or `undefined` when no model ID is set or no resolver is configured.
370
539
 
371
540
  ```typescript
372
- const observerModel = agentController.session.om.observer.resolvedModel()
541
+ const observerModel = session.om.observer.resolvedModel()
542
+ const reflectorModel = session.om.reflector.resolvedModel()
373
543
  ```
374
544
 
375
545
  ## Permissions
376
546
 
377
- `session.permissions` owns the persisted tool-approval _policy_: the per-category and per-tool rules consulted during approval resolution. These are distinct from the in-memory session _grants_ documented under [Methods → Permissions](#permissions); grants reset each session, whereas these rules are persisted in session state.
547
+ `session.permissions` owns the tool-approval policy represented in `session.state`: the per-category and per-tool rules consulted during approval resolution. These are distinct from the in-memory grants documented under [Session grants](#session-grants). Grants reset with the live session. Permission rules aren't durable unless the host restores the corresponding session state.
378
548
 
379
549
  ### `session.permissions.getRules()`
380
550
 
381
551
  Return the current permission rules, or empty rules (`{ categories: {}, tools: {} }`) when none are set.
382
552
 
383
553
  ```typescript
384
- const rules = agentController.session.permissions.getRules()
554
+ const rules = session.permissions.getRules()
385
555
  // { categories: { execute: 'ask' }, tools: { dangerous_tool: 'deny' } }
386
556
  ```
387
557
 
@@ -390,7 +560,7 @@ const rules = agentController.session.permissions.getRules()
390
560
  Set the approval policy (`'allow' | 'ask' | 'deny'`) for a tool category. Resolves once the change is persisted to session state.
391
561
 
392
562
  ```typescript
393
- await agentController.session.permissions.setForCategory({ category: 'execute', policy: 'ask' })
563
+ await session.permissions.setForCategory({ category: 'execute', policy: 'ask' })
394
564
  ```
395
565
 
396
566
  ### `session.permissions.setForTool({ toolName, policy })`
@@ -398,7 +568,7 @@ await agentController.session.permissions.setForCategory({ category: 'execute',
398
568
  Set the approval policy for a specific tool. Per-tool policies take precedence over category policies. Resolves once persisted.
399
569
 
400
570
  ```typescript
401
- await agentController.session.permissions.setForTool({ toolName: 'dangerous_tool', policy: 'deny' })
571
+ await session.permissions.setForTool({ toolName: 'dangerous_tool', policy: 'deny' })
402
572
  ```
403
573
 
404
574
  ## Subagents
@@ -410,7 +580,7 @@ await agentController.session.permissions.setForTool({ toolName: 'dangerous_tool
410
580
  Return the subagent model ID, preferring the per-`agentType` value when one is given, then the global subagent model, or `null` when neither is set.
411
581
 
412
582
  ```typescript
413
- const modelId = agentController.session.subagents.model.get({ agentType: 'explore' })
583
+ const modelId = session.subagents.model.get({ agentType: 'explore' })
414
584
  ```
415
585
 
416
586
  ### `session.subagents.model.set({ modelId, agentType? })`
@@ -419,10 +589,10 @@ Set the subagent model ID. Pass an `agentType` to set a per-type override, or om
419
589
 
420
590
  ```typescript
421
591
  // Set the global subagent model
422
- await agentController.session.subagents.model.set({ modelId: 'anthropic/claude-sonnet-4-6' })
592
+ await session.subagents.model.set({ modelId: 'anthropic/claude-sonnet-4-6' })
423
593
 
424
594
  // Set a per-type override
425
- await agentController.session.subagents.model.set({
595
+ await session.subagents.model.set({
426
596
  modelId: 'anthropic/claude-haiku-4-5',
427
597
  agentType: 'explore',
428
598
  })
@@ -437,8 +607,8 @@ await agentController.session.subagents.model.set({
437
607
  Return the stored run ID and trace ID for the current run, or `null` when idle.
438
608
 
439
609
  ```typescript
440
- const runId = agentController.session.run.getRunId()
441
- const traceId = agentController.session.run.getTraceId()
610
+ const runId = session.run.getRunId()
611
+ const traceId = session.run.getTraceId()
442
612
  ```
443
613
 
444
614
  ### `session.run.isRunning()`
@@ -446,7 +616,7 @@ const traceId = agentController.session.run.getTraceId()
446
616
  Return whether a run is currently in progress.
447
617
 
448
618
  ```typescript
449
- if (agentController.session.run.isRunning()) {
619
+ if (session.run.isRunning()) {
450
620
  // A run is active
451
621
  }
452
622
  ```
@@ -460,7 +630,7 @@ if (agentController.session.run.isRunning()) {
460
630
  Return the run ID active on the live stream, or `null` when no stream is open.
461
631
 
462
632
  ```typescript
463
- const runId = agentController.session.stream.activeRunId()
633
+ const runId = session.stream.activeRunId()
464
634
  ```
465
635
 
466
636
  ### `session.stream.isActive()`
@@ -468,7 +638,7 @@ const runId = agentController.session.stream.activeRunId()
468
638
  Return whether the stream currently has an active run.
469
639
 
470
640
  ```typescript
471
- if (agentController.session.stream.isActive()) {
641
+ if (session.stream.isActive()) {
472
642
  // The current thread's stream is producing output
473
643
  }
474
644
  ```
@@ -482,7 +652,7 @@ if (agentController.session.stream.isActive()) {
482
652
  Return whether any tool is currently suspended.
483
653
 
484
654
  ```typescript
485
- if (agentController.session.suspensions.hasPending()) {
655
+ if (session.suspensions.hasPending()) {
486
656
  // At least one interactive tool is waiting for a response
487
657
  }
488
658
  ```
@@ -492,10 +662,10 @@ if (agentController.session.suspensions.hasPending()) {
492
662
  Return whether a specific tool call is suspended.
493
663
 
494
664
  ```typescript
495
- const waiting = agentController.session.suspensions.has({ toolCallId: event.toolCallId })
665
+ const waiting = session.suspensions.has({ toolCallId: event.toolCallId })
496
666
  ```
497
667
 
498
- Resume a suspended tool with [`agentController.respondToToolSuspension()`](https://mastra.ai/reference/agent-controller/agent-controller-class).
668
+ Resume a suspended tool with [`session.respondToToolSuspension()`](#tool-approvals).
499
669
 
500
670
  ## Follow-ups
501
671
 
@@ -506,7 +676,7 @@ Resume a suspended tool with [`agentController.respondToToolSuspension()`](https
506
676
  Return the number of queued follow-ups.
507
677
 
508
678
  ```typescript
509
- const queued = agentController.session.followUps.count()
679
+ const queued = session.followUps.count()
510
680
  ```
511
681
 
512
682
  ### `session.followUps.isEmpty()`
@@ -514,7 +684,7 @@ const queued = agentController.session.followUps.count()
514
684
  Return whether the follow-up queue is empty.
515
685
 
516
686
  ```typescript
517
- if (!agentController.session.followUps.isEmpty()) {
687
+ if (!session.followUps.isEmpty()) {
518
688
  // Messages are waiting to be processed
519
689
  }
520
690
  ```
@@ -528,23 +698,23 @@ if (!agentController.session.followUps.isEmpty()) {
528
698
  Return whether a tool is currently awaiting an approval decision.
529
699
 
530
700
  ```typescript
531
- if (agentController.session.approval.isArmed()) {
701
+ if (session.approval.isArmed()) {
532
702
  // Show the approval prompt
533
703
  }
534
704
  ```
535
705
 
536
- Respond with [`session.respondToToolApproval()`](#respondtotoolapproval-decision-requestcontext-).
706
+ Respond with [`session.respondToToolApproval()`](#tool-approvals).
537
707
 
538
708
  ## Display state
539
709
 
540
- `session.displayState` owns the canonical `AgentControllerDisplayState` snapshot a UI renders from, and the reducer that keeps it in sync with every agentController event.
710
+ `session.displayState` owns the canonical `AgentControllerDisplayState` snapshot a UI renders from, and the reducer that keeps it in sync with every session event.
541
711
 
542
712
  ### `session.displayState.get()`
543
713
 
544
714
  Return the current `AgentControllerDisplayState` snapshot for UI rendering.
545
715
 
546
716
  ```typescript
547
- const displayState = agentController.session.displayState.get()
717
+ const displayState = session.displayState.get()
548
718
  ```
549
719
 
550
720
  ### `session.displayState.restoreTasks(tasks)`
@@ -552,10 +722,10 @@ const displayState = agentController.session.displayState.get()
552
722
  Restore the task portion of the snapshot after a UI replays persisted task tool history. This is a pure update of the snapshot and doesn't emit an event, so re-render explicitly after calling it.
553
723
 
554
724
  ```typescript
555
- agentController.session.displayState.restoreTasks(replayedTasks)
725
+ session.displayState.restoreTasks(replayedTasks)
556
726
  ```
557
727
 
558
- 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. Subscribe with [`agentController.subscribe()`](https://mastra.ai/reference/agent-controller/agent-controller-class) and read the latest snapshot from `session.displayState.get()`.
728
+ After every event, the session emits `display_state_changed` with the latest snapshot. Subscribe with [`session.subscribe()`](#identity-and-events) or read the current value from `session.displayState.get()`.
559
729
 
560
730
  ## State
561
731
 
@@ -566,7 +736,7 @@ After every event the agentController emits `display_state_changed`, so high-fre
566
736
  Return a readonly copy of the current state snapshot.
567
737
 
568
738
  ```typescript
569
- const state = agentController.session.state.get()
739
+ const state = session.state.get()
570
740
  ```
571
741
 
572
742
  ### `session.state.set(updates)`
@@ -574,7 +744,7 @@ const state = agentController.session.state.get()
574
744
  Merge a partial update into the state. Updates are queued so concurrent calls apply in order, validated against the schema, and emit `state_changed` with the changed keys.
575
745
 
576
746
  ```typescript
577
- await agentController.session.state.set({ yolo: true })
747
+ await session.state.set({ yolo: true })
578
748
  ```
579
749
 
580
750
  ### `session.state.update(updater)`
@@ -582,28 +752,21 @@ await agentController.session.state.set({ yolo: true })
582
752
  Run an updater against the current snapshot and apply its result atomically within the write queue. Use this for read-modify-write changes that must see the latest state. The updater returns `updates` to merge, optional `events` to emit, and a `result` value that `update()` resolves to.
583
753
 
584
754
  ```typescript
585
- const added = await agentController.session.state.update(current => ({
755
+ const added = await session.state.update(current => ({
586
756
  updates: { count: (current.count ?? 0) + 1 },
587
757
  result: (current.count ?? 0) + 1,
588
758
  }))
589
759
  ```
590
760
 
591
- ## Scoping tags
592
-
593
- Sessions carry scoping tags (e.g. `{ projectPath }`) seeded at creation and stamped onto every thread the session creates. Thread listings can be filtered back to the session's scope using these tags.
761
+ ## Persistence boundaries
594
762
 
595
- ### `getTags()`
763
+ A `Session` is a live runtime object. Its event bus, arbitrary `session.state`, permission rules, permission grants, pending approvals, suspensions, follow-ups, run state, and stream state don't automatically survive controller or process recreation. The host must restore any of this state when recreating a session.
596
764
 
597
- Return a copy of the session's scoping tags. Empty object when the session is unscoped.
598
-
599
- ```typescript
600
- const tags = agentController.session.getTags()
601
- // { projectPath: '/my/project' }
602
- ```
765
+ With configured storage, threads, messages, and token usage persist. Thread settings restore mode and model choices. They can also restore observational memory settings and subagent model selections, including per-agent-type overrides. A chat channel can map back to stored threads, but channel-to-session and auto-approval state held by `AgentControllerChannels` remains in memory.
603
766
 
604
767
  ## Related
605
768
 
606
769
  - [AgentController class](https://mastra.ai/reference/agent-controller/agent-controller-class)
607
- - [AgentController overview](https://mastra.ai/docs/agent-controller/overview)
608
- - [Threads and state](https://mastra.ai/docs/agent-controller/threads-and-state)
609
- - [Tool approvals](https://mastra.ai/docs/agent-controller/tool-approvals)
770
+ - [AgentController overview](https://mastra.ai/docs/harness/agent-controller)
771
+ - [Threads and state](https://mastra.ai/docs/harness/agent-controller)
772
+ - [Tool approvals](https://mastra.ai/docs/harness/agent-controller)