@mastra/mcp-docs-server 1.1.42-alpha.4 → 1.1.42-alpha.5

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 (32) hide show
  1. package/.docs/docs/agent-builder/memory.md +1 -1
  2. package/.docs/docs/agents/adding-voice.md +31 -0
  3. package/.docs/docs/agents/agent-approval.md +14 -0
  4. package/.docs/docs/agents/code-mode.md +163 -0
  5. package/.docs/docs/agents/signals.md +132 -71
  6. package/.docs/docs/getting-started/manual-install.md +1 -1
  7. package/.docs/docs/memory/semantic-recall.md +1 -1
  8. package/.docs/docs/observability/metrics/overview.md +1 -0
  9. package/.docs/docs/observability/metrics/querying.md +292 -0
  10. package/.docs/docs/server/auth/fga.md +2 -0
  11. package/.docs/docs/voice/overview.md +62 -0
  12. package/.docs/docs/voice/speech-to-speech.md +52 -1
  13. package/.docs/docs/workspace/sandbox.md +4 -2
  14. package/.docs/guides/guide/firecrawl.md +5 -5
  15. package/.docs/models/embeddings.md +2 -2
  16. package/.docs/reference/agents/agent.md +46 -17
  17. package/.docs/reference/index.md +3 -0
  18. package/.docs/reference/observability/metrics/automatic-metrics.md +7 -1
  19. package/.docs/reference/processors/tool-search-processor.md +31 -0
  20. package/.docs/reference/server/routes.md +81 -9
  21. package/.docs/reference/templates/overview.md +2 -2
  22. package/.docs/reference/tools/mcp-client.md +51 -0
  23. package/.docs/reference/vectors/pg.md +2 -0
  24. package/.docs/reference/voice/inworld-realtime.md +353 -0
  25. package/.docs/reference/voice/inworld.md +2 -0
  26. package/.docs/reference/workspace/agentcore-runtime-sandbox.md +202 -0
  27. package/.docs/reference/workspace/blaxel-sandbox.md +3 -0
  28. package/.docs/reference/workspace/docker-sandbox.md +3 -1
  29. package/.docs/reference/workspace/vercel-microvm-sandbox.md +199 -0
  30. package/.docs/reference/workspace/vercel.md +2 -0
  31. package/CHANGELOG.md +8 -0
  32. package/package.json +8 -6
@@ -0,0 +1,292 @@
1
+ # Querying metrics
2
+
3
+ Mastra exposes the same five OLAP queries (`getMetricAggregate`, `getMetricBreakdown`, `getMetricTimeSeries`, `getMetricPercentiles`, and discovery helpers) through three surfaces: an in-process store accessor, the runtime HTTP API, and the `mastra api metric` CLI. All three accept the same Zod-validated input shapes, so you can move from a one-off CLI investigation to a programmatic dashboard tool without re-learning the API.
4
+
5
+ ## When to use this
6
+
7
+ - Build a custom dashboard or KPI tile alongside Studio.
8
+ - Power a scheduled alert that fires when token cost or latency crosses a threshold.
9
+ - Give an agent a tool that reads its own performance metrics and explains them in chat.
10
+ - Run one-off investigations from a terminal with `mastra api metric ...`.
11
+
12
+ For setup of the observability store itself, see the [Metrics overview](https://mastra.ai/docs/observability/metrics/overview). For the list of metric names you can query, see the [Automatic metrics reference](https://mastra.ai/reference/observability/metrics/automatic-metrics).
13
+
14
+ > **Note:** Metric queries are served by the observability domain, which requires an OLAP-capable store (DuckDB locally, ClickHouse in production). See [Metrics overview](https://mastra.ai/docs/observability/metrics/overview) for setup. If the observability store is not configured, `getStore('observability')` returns `null`.
15
+
16
+ ## Surfaces
17
+
18
+ ### In-process
19
+
20
+ Inside a tool, server route, or workflow step, get the observability store from the Mastra storage:
21
+
22
+ ```typescript
23
+ import { createTool } from '@mastra/core/tools'
24
+ import { z } from 'zod'
25
+
26
+ export const agentLatencyTool = createTool({
27
+ id: 'agentLatency',
28
+ description: 'Average agent latency over the last hour.',
29
+ inputSchema: z.object({}),
30
+ execute: async (_input, context) => {
31
+ const observability = await context.mastra!.getStorage()!.getStore('observability')
32
+ if (!observability) {
33
+ throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
34
+ }
35
+
36
+ const result = await observability.getMetricAggregate({
37
+ name: ['mastra_agent_duration_ms'],
38
+ aggregation: 'avg',
39
+ filters: {
40
+ timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
41
+ },
42
+ })
43
+
44
+ return { averageMs: result.value }
45
+ },
46
+ })
47
+ ```
48
+
49
+ `getStore('observability')` returns `null` when the configured backend does not support OLAP queries.
50
+
51
+ ### HTTP
52
+
53
+ The `mastra dev` server (and any deployed Mastra runtime) exposes the same queries under `/api/observability/metrics/*`. Aggregate, breakdown, time series, and percentile endpoints take a JSON body with `POST`. Discovery endpoints use `GET` with query parameters.
54
+
55
+ ```bash
56
+ curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
57
+ -H "content-type: application/json" \
58
+ -d '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}'
59
+ ```
60
+
61
+ Available routes:
62
+
63
+ - `POST /api/observability/metrics/aggregate`
64
+ - `POST /api/observability/metrics/breakdown`
65
+ - `POST /api/observability/metrics/timeseries`
66
+ - `POST /api/observability/metrics/percentiles`
67
+ - `GET /api/observability/metrics` (raw rows, paginated)
68
+ - `GET /api/observability/discovery/metric-names`
69
+ - `GET /api/observability/discovery/metric-label-keys`
70
+ - `GET /api/observability/discovery/metric-label-values`
71
+
72
+ The `@mastra/client-js` SDK wraps the same routes as `mastraClient.getMetricAggregate(...)`, `getMetricBreakdown(...)`, and so on.
73
+
74
+ ### CLI
75
+
76
+ `mastra api metric ...` calls the same endpoints with a single JSON argument, so an agent or shell script can fetch metrics without writing any code:
77
+
78
+ ```bash
79
+ mastra api metric aggregate \
80
+ '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
81
+ --url http://localhost:4111 --pretty
82
+ ```
83
+
84
+ By default the CLI targets hosted Mastra observability (`https://observability.mastra.ai`). Pass `--url http://localhost:4111` to query a local `mastra dev` server. See [`mastra api metric aggregate`](https://mastra.ai/reference/cli/mastra) and the surrounding entries for the full command list.
85
+
86
+ ## Queries
87
+
88
+ ### `getMetricAggregate`
89
+
90
+ Returns a single scalar — the building block for KPI cards.
91
+
92
+ Inputs:
93
+
94
+ - `name`: Array of one or more metric names.
95
+ - `aggregation`: One of `'sum' | 'avg' | 'min' | 'max' | 'count' | 'count_distinct' | 'last'`.
96
+ - `filters`: Optional [filter object](#filtering).
97
+ - `comparePeriod`: Optional `'previous_period' | 'previous_day' | 'previous_week'` for period-over-period comparison.
98
+
99
+ Response:
100
+
101
+ - `value`, `previousValue`, `changePercent`.
102
+ - `estimatedCost`, `costUnit`, `previousEstimatedCost`, `costChangePercent` for token metrics.
103
+
104
+ ```typescript
105
+ const observability = await mastra.getStorage()!.getStore('observability')
106
+
107
+ const cost = await observability!.getMetricAggregate({
108
+ name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],
109
+ aggregation: 'sum',
110
+ comparePeriod: 'previous_day',
111
+ })
112
+
113
+ console.log(cost.value, cost.estimatedCost, cost.costUnit, cost.changePercent)
114
+ ```
115
+
116
+ ### `getMetricBreakdown`
117
+
118
+ Groups rows by one or more dimensions and aggregates each group — the building block for top-N tables (e.g. "tokens by agent").
119
+
120
+ Inputs:
121
+
122
+ - `name`: Array of metric names.
123
+ - `groupBy`: Array of fields to group by (for example `['entityName']`).
124
+ - `aggregation`: Same enum as above.
125
+ - `limit`: Server-side top-K cap. Required for high-cardinality `groupBy`.
126
+ - `orderDirection`: `'ASC' | 'DESC'` (defaults to `DESC`).
127
+ - `filters`: Optional.
128
+
129
+ Response: `groups[]`, each with `dimensions` (record of group keys to values), `value`, and `estimatedCost`.
130
+
131
+ ```typescript
132
+ const byAgent = await observability!.getMetricBreakdown({
133
+ name: ['mastra_model_total_input_tokens'],
134
+ groupBy: ['entityName'],
135
+ aggregation: 'sum',
136
+ limit: 10,
137
+ orderDirection: 'DESC',
138
+ })
139
+ ```
140
+
141
+ ### `getMetricTimeSeries`
142
+
143
+ Buckets values by a fixed interval — the building block for line and bar charts.
144
+
145
+ Inputs:
146
+
147
+ - `name`: Array of metric names.
148
+ - `interval`: One of `'1m' | '5m' | '15m' | '1h' | '1d'`.
149
+ - `aggregation`: Same enum.
150
+ - `groupBy`: Optional. When omitted, multiple metric names are summed into one series; use one call per metric to keep them separate.
151
+ - `filters`: Optional.
152
+
153
+ Response: `series[]`, each with `name`, `costUnit`, and `points[]` of `{ timestamp, value, estimatedCost }`.
154
+
155
+ ```typescript
156
+ const inputTokens = await observability!.getMetricTimeSeries({
157
+ name: ['mastra_model_total_input_tokens'],
158
+ aggregation: 'sum',
159
+ interval: '1h',
160
+ filters: {
161
+ timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
162
+ },
163
+ })
164
+ ```
165
+
166
+ ### `getMetricPercentiles`
167
+
168
+ Returns percentile values bucketed by time — the building block for latency charts.
169
+
170
+ Inputs:
171
+
172
+ - `name`: Single metric name (string, not array).
173
+ - `percentiles`: Array of numbers between `0` and `1`, for example `[0.5, 0.95, 0.99]`.
174
+ - `interval`: Same enum as `getMetricTimeSeries`.
175
+ - `filters`: Optional.
176
+
177
+ Response: `series[]`, each with `percentile` and `points[]` of `{ timestamp, value }`.
178
+
179
+ ```typescript
180
+ const latency = await observability!.getMetricPercentiles({
181
+ name: 'mastra_agent_duration_ms',
182
+ percentiles: [0.5, 0.95],
183
+ interval: '1h',
184
+ })
185
+ ```
186
+
187
+ ### Discovery
188
+
189
+ Use these endpoints to populate dropdowns or to give an agent the menu of values it can filter by. All discovery routes are `GET` and live under `/api/observability/discovery/`.
190
+
191
+ **Metric-specific** (also exposed as `mastra api metric` subcommands):
192
+
193
+ | Method | Args | Path suffix | CLI |
194
+ | ---------------------- | ------------------------------------------- | --------------------- | -------------------------------- |
195
+ | `getMetricNames` | `{ prefix?, limit? }` | `metric-names` | `mastra api metric names` |
196
+ | `getMetricLabelKeys` | `{ metricName }` | `metric-label-keys` | `mastra api metric label-keys` |
197
+ | `getMetricLabelValues` | `{ metricName, labelKey, prefix?, limit? }` | `metric-label-values` | `mastra api metric label-values` |
198
+
199
+ **Shared with traces and logs** (HTTP-only, no dedicated CLI subcommand):
200
+
201
+ | Method | Args | Path suffix |
202
+ | ----------------- | ----------------- | --------------- |
203
+ | `getEntityTypes` | `{}` | `entity-types` |
204
+ | `getEntityNames` | `{ entityType? }` | `entity-names` |
205
+ | `getServiceNames` | `{}` | `service-names` |
206
+ | `getEnvironments` | `{}` | `environments` |
207
+ | `getTags` | `{ entityType? }` | `tags` |
208
+
209
+ ## Filtering
210
+
211
+ Every query accepts the same `filters` object. The most useful fields:
212
+
213
+ - `name`: Restrict to specific metric names. (Top-level `name` already does this for aggregate/breakdown/timeseries; use `filters.name` when you want to mix multiple metrics under a single query.)
214
+ - `timestamp`: `{ start, end, startExclusive, endExclusive }`. Both bounds are optional; omit `end` for "until now".
215
+ - `provider`, `model`, `costUnit`: For token and cost metrics.
216
+ - `labels`: Exact key-value match on metric labels, for example `{ status: 'error' }` for duration metrics.
217
+ - Correlation fields: `entityType`, `entityName`, `parentEntityName`, `rootEntityName`, `userId`, `organizationId`, `resourceId`, `runId`, `sessionId`, `threadId`, `requestId`, `executionSource`, `environment`, `serviceName`, `experimentId`, `tags`.
218
+
219
+ The same `filters` shape works across all three surfaces:
220
+
221
+ ```typescript
222
+ // In-process
223
+ await observability!.getMetricAggregate({
224
+ name: ['mastra_tool_duration_ms'],
225
+ aggregation: 'avg',
226
+ filters: { entityName: 'weatherTool', labels: { status: 'error' } },
227
+ })
228
+ ```
229
+
230
+ ```bash
231
+ # CLI
232
+ mastra api metric aggregate \
233
+ '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}' \
234
+ --url http://localhost:4111
235
+ ```
236
+
237
+ ```bash
238
+ # HTTP
239
+ curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
240
+ -H "content-type: application/json" \
241
+ -d '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}'
242
+ ```
243
+
244
+ ## Example: build a custom KPI tile
245
+
246
+ The following tool returns input-token volume and estimated cost for the last hour. An agent or a dashboard can call it as `structuredContent` without re-implementing the query.
247
+
248
+ ```typescript
249
+ import { createTool } from '@mastra/core/tools'
250
+ import { z } from 'zod'
251
+
252
+ export const tokenKpiTool = createTool({
253
+ id: 'tokenKpi',
254
+ description: 'Returns input-token volume and estimated cost for the last hour.',
255
+ inputSchema: z.object({}),
256
+ outputSchema: z.object({
257
+ inputTokens: z.number().nullable(),
258
+ estimatedCost: z.number().nullable(),
259
+ costUnit: z.string().nullable(),
260
+ changePercent: z.number().nullable(),
261
+ }),
262
+ execute: async (_input, context) => {
263
+ const observability = await context.mastra!.getStorage()!.getStore('observability')
264
+ if (!observability) {
265
+ throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
266
+ }
267
+
268
+ const result = await observability.getMetricAggregate({
269
+ name: ['mastra_model_total_input_tokens'],
270
+ aggregation: 'sum',
271
+ filters: {
272
+ timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
273
+ },
274
+ comparePeriod: 'previous_period',
275
+ })
276
+
277
+ return {
278
+ inputTokens: result.value,
279
+ estimatedCost: result.estimatedCost ?? null,
280
+ costUnit: result.costUnit ?? null,
281
+ changePercent: result.changePercent ?? null,
282
+ }
283
+ },
284
+ })
285
+ ```
286
+
287
+ ## Related
288
+
289
+ - [Metrics overview](https://mastra.ai/docs/observability/metrics/overview)
290
+ - [Automatic metrics reference](https://mastra.ai/reference/observability/metrics/automatic-metrics)
291
+ - [CLI: `mastra api metric ...`](https://mastra.ai/reference/cli/mastra)
292
+ - [Studio observability](https://mastra.ai/docs/studio/observability)
@@ -1,5 +1,7 @@
1
1
  # Fine-Grained Authorization (FGA)
2
2
 
3
+ > **Note:** Fine-Grained Authorization is part of the Mastra Enterprise Edition. Production deployments require a valid EE license. [Contact sales](https://mastra.ai/contact) for more information.
4
+
3
5
  Fine-Grained Authorization (FGA) adds resource-level permission checks to your Mastra application. While RBAC answers "can this role do this action?", FGA answers **"can this user do this action on this specific resource?"**
4
6
 
5
7
  ## When to use FGA
@@ -686,6 +686,48 @@ await voiceAgent.voice.send(micStream)
686
686
 
687
687
  Visit the [AWS Nova Sonic Reference](https://mastra.ai/reference/voice/aws-nova-sonic) for more information on the AWS Nova Sonic voice provider.
688
688
 
689
+ **Inworld Realtime**:
690
+
691
+ ```typescript
692
+ import { Agent } from '@mastra/core/agent'
693
+ import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
694
+ import { InworldRealtimeVoice } from '@mastra/voice-inworld'
695
+
696
+ const voiceAgent = new Agent({
697
+ id: 'voice-agent',
698
+ name: 'Voice Agent',
699
+ instructions: 'You are a voice assistant that can help users with their tasks.',
700
+ model: 'openai/gpt-5.4',
701
+ voice: new InworldRealtimeVoice({
702
+ apiKey: process.env.INWORLD_API_KEY,
703
+ model: 'inworld/models/gemma-4-26b-a4b-it',
704
+ speaker: 'Sarah',
705
+ }),
706
+ })
707
+
708
+ // Connect before using speak/send
709
+ await voiceAgent.voice.connect()
710
+
711
+ // Listen for agent audio (PCM stream)
712
+ voiceAgent.voice.on('speaker', stream => {
713
+ playAudio(stream)
714
+ })
715
+
716
+ // Listen for text responses and transcriptions
717
+ voiceAgent.voice.on('writing', ({ text, role }) => {
718
+ console.log(`${role}: ${text}`)
719
+ })
720
+
721
+ // Initiate the conversation
722
+ await voiceAgent.voice.speak('How can I help you today?')
723
+
724
+ // Send continuous audio from the microphone
725
+ const micStream = getMicrophoneStream()
726
+ await voiceAgent.voice.send(micStream)
727
+ ```
728
+
729
+ Visit the [Inworld Realtime Reference](https://mastra.ai/reference/voice/inworld-realtime) for more information on the Inworld Realtime voice provider.
730
+
689
731
  **xAI**:
690
732
 
691
733
  ```typescript
@@ -1051,6 +1093,26 @@ const voice = new NovaSonicVoice({
1051
1093
 
1052
1094
  Visit the [AWS Nova Sonic Reference](https://mastra.ai/reference/voice/aws-nova-sonic) for more information on the AWS Nova Sonic voice provider.
1053
1095
 
1096
+ **Inworld Realtime**:
1097
+
1098
+ ```typescript
1099
+ // Inworld Realtime Voice Configuration
1100
+ const voice = new InworldRealtimeVoice({
1101
+ apiKey: process.env.INWORLD_API_KEY,
1102
+ model: 'inworld/models/gemma-4-26b-a4b-it',
1103
+ speaker: 'Sarah',
1104
+ // Typed Inworld realtime knobs (semantic VAD, playback speed, MCP tool routing, ...)
1105
+ session: {
1106
+ audio: {
1107
+ output: { speed: 1.1 },
1108
+ input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
1109
+ },
1110
+ },
1111
+ })
1112
+ ```
1113
+
1114
+ Visit the [Inworld Realtime Reference](https://mastra.ai/reference/voice/inworld-realtime) for more information on the Inworld Realtime voice provider.
1115
+
1054
1116
  **AI SDK**:
1055
1117
 
1056
1118
  ```typescript
@@ -143,4 +143,55 @@ Note:
143
143
 
144
144
  - Available regions: `us-east-1`, `us-west-2`, and `ap-northeast-1`.
145
145
  - Authenticates through the standard AWS credential provider chain. Pass `credentials` to override.
146
- - Events: `speaking` (Int16Array audio), `writing` (text with `generationStage`), `toolCall`, `interrupt`, `turnComplete`, `usage`, `session`, and `error`.
146
+ - Events: `speaking` (Int16Array audio), `writing` (text with `generationStage`), `toolCall`, `interrupt`, `turnComplete`, `usage`, `session`, and `error`.
147
+
148
+ ## Inworld Realtime
149
+
150
+ ```typescript
151
+ import { Agent } from '@mastra/core/agent'
152
+ import { InworldRealtimeVoice } from '@mastra/voice-inworld'
153
+ import { playAudio, getMicrophoneStream } from '@mastra/node-audio'
154
+
155
+ const agent = new Agent({
156
+ id: 'agent',
157
+ name: 'Inworld Realtime Agent',
158
+ instructions: 'You are a helpful assistant with real-time voice capabilities.',
159
+ // Model used for text generation; voice provider handles realtime audio
160
+ model: 'openai/gpt-5.4',
161
+ voice: new InworldRealtimeVoice({
162
+ apiKey: process.env.INWORLD_API_KEY,
163
+ model: 'inworld/models/gemma-4-26b-a4b-it',
164
+ speaker: 'Sarah',
165
+ // Typed Inworld realtime knobs (semantic VAD, playback speed, etc.)
166
+ // session: {
167
+ // audio: {
168
+ // output: { speed: 1.1 },
169
+ // input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
170
+ // },
171
+ // },
172
+ }),
173
+ })
174
+
175
+ await agent.voice.connect()
176
+
177
+ agent.voice.on('speaker', stream => {
178
+ playAudio(stream)
179
+ })
180
+
181
+ agent.voice.on('writing', ({ role, text }) => {
182
+ console.log(`${role}: ${text}`)
183
+ })
184
+
185
+ await agent.voice.speak('How can I help you today?')
186
+
187
+ const micStream = getMicrophoneStream()
188
+ await agent.voice.send(micStream)
189
+ ```
190
+
191
+ Note:
192
+
193
+ - Requires `INWORLD_API_KEY`. Inworld API keys ship pre-Basic-encoded — paste them verbatim.
194
+ - The WebSocket URL appends a client-generated `?key=...&protocol=realtime`. The model is configured via the initial `session.update`, not in the URL.
195
+ - Inworld's wire protocol is the OpenAI Realtime GA spec, so event names match `@mastra/voice-openai-realtime`.
196
+ - Typed Inworld realtime knobs (MCP tool routing, semantic VAD eagerness, playback speed, transcription model, output modalities, …) are exposed through the `session` constructor field; an untyped `providerData` escape hatch is also deep-merged for forward compatibility with new Inworld features.
197
+ - Events: `speaker` (PCM audio stream), `speaking` (audio Buffer per delta), `writing` (text), `conversation.item.added`, `conversation.item.done`, `function_call.arguments`, `tool-call-start`, `tool-call-result`, and `error`.
@@ -16,6 +16,7 @@ A sandbox provider executes commands in a controlled environment:
16
16
  ## Supported providers
17
17
 
18
18
  - [`LocalSandbox`](https://mastra.ai/reference/workspace/local-sandbox): Executes commands on the local machine
19
+ - [`AgentCoreRuntimeSandbox`](https://mastra.ai/reference/workspace/agentcore-runtime-sandbox): Executes commands in AWS Bedrock AgentCore Runtime sessions
19
20
  - [`BlaxelSandbox`](https://mastra.ai/reference/workspace/blaxel-sandbox): Executes commands in isolated Blaxel cloud sandboxes
20
21
  - [`DaytonaSandbox`](https://mastra.ai/reference/workspace/daytona-sandbox): Executes commands in isolated Daytona cloud sandboxes
21
22
  - [`E2BSandbox`](https://mastra.ai/reference/workspace/e2b-sandbox): Executes commands in isolated E2B cloud sandboxes
@@ -118,9 +119,10 @@ Use `null` or `false` for cloud sandboxes (for example, E2B, Daytona, or Modal)
118
119
  ## Related
119
120
 
120
121
  - [`SandboxProcessManager` reference](https://mastra.ai/reference/workspace/process-manager)
121
- - [`LocalSandbox` reference](https://mastra.ai/reference/workspace/local-sandbox)
122
- - [`ModalSandbox` reference](https://mastra.ai/reference/workspace/modal-sandbox)
122
+ - [`AgentCoreRuntimeSandbox` reference](https://mastra.ai/reference/workspace/agentcore-runtime-sandbox)
123
123
  - [`DaytonaSandbox` reference](https://mastra.ai/reference/workspace/daytona-sandbox)
124
124
  - [`E2BSandbox` reference](https://mastra.ai/reference/workspace/e2b-sandbox)
125
+ - [`LocalSandbox` reference](https://mastra.ai/reference/workspace/local-sandbox)
126
+ - [`ModalSandbox` reference](https://mastra.ai/reference/workspace/modal-sandbox)
125
127
  - [Workspace overview](https://mastra.ai/docs/workspace/overview)
126
128
  - [Filesystem](https://mastra.ai/docs/workspace/filesystem)
@@ -16,25 +16,25 @@ Install the Firecrawl SDK:
16
16
  **npm**:
17
17
 
18
18
  ```bash
19
- npm install @mendable/firecrawl-js
19
+ npm install firecrawl
20
20
  ```
21
21
 
22
22
  **pnpm**:
23
23
 
24
24
  ```bash
25
- pnpm add @mendable/firecrawl-js
25
+ pnpm add firecrawl
26
26
  ```
27
27
 
28
28
  **Yarn**:
29
29
 
30
30
  ```bash
31
- yarn add @mendable/firecrawl-js
31
+ yarn add firecrawl
32
32
  ```
33
33
 
34
34
  **Bun**:
35
35
 
36
36
  ```bash
37
- bun add @mendable/firecrawl-js
37
+ bun add firecrawl
38
38
  ```
39
39
 
40
40
  ## Configure environment variables
@@ -53,7 +53,7 @@ Create a tool file that exposes Firecrawl search and scrape to Mastra.
53
53
  1. Create `src/mastra/tools/firecrawl.ts` and set up Firecrawl:
54
54
 
55
55
  ```ts
56
- import Firecrawl from '@mendable/firecrawl-js'
56
+ import { Firecrawl } from 'firecrawl'
57
57
  import { createTool } from '@mastra/core/tools'
58
58
  import { z } from 'zod'
59
59
 
@@ -40,12 +40,12 @@ const embedder = new ModelRouterEmbeddingModel("google/gemini-embedding-001");
40
40
  The model router automatically detects API keys from environment variables:
41
41
 
42
42
  - **OpenAI**: `OPENAI_API_KEY`
43
- - **Google**: `GOOGLE_GENERATIVE_AI_API_KEY`
43
+ - **Google**: `GOOGLE_API_KEY` (falls back to `GOOGLE_GENERATIVE_AI_API_KEY`)
44
44
 
45
45
  ```bash
46
46
  # .env
47
47
  OPENAI_API_KEY=sk-...
48
- GOOGLE_GENERATIVE_AI_API_KEY=...
48
+ GOOGLE_API_KEY=...
49
49
  ```
50
50
 
51
51
  ## Custom Providers
@@ -96,9 +96,9 @@ export const agent = new Agent({
96
96
 
97
97
  ## Thread signals
98
98
 
99
- Use Agent signals to send real-time context into a memory thread. Signals are useful when a user adds input while an agent is already streaming, or when another process needs to add structured context to the thread.
99
+ Use Agent signals to send real-time input and context into a memory thread. Message APIs are for user-authored input. `sendSignal()` is the lower-level API for system-generated context.
100
100
 
101
- A `user-message` signal represents user input. When the target thread is running, Mastra delivers the signal into the active agent loop. When the thread is idle, Mastra starts a stream with the signal as the first input by default.
101
+ When the target thread is running, `sendMessage()` delivers the message into the active agent loop. When the thread is idle, Mastra starts a stream with the message as the first input by default.
102
102
 
103
103
  ```typescript
104
104
  const subscription = await agent.subscribeToThread({
@@ -112,26 +112,22 @@ void (async () => {
112
112
  }
113
113
  })()
114
114
 
115
- agent.sendSignal(
116
- { type: 'user-message', contents: 'Use the latest customer note too.' },
117
- {
118
- resourceId: 'user-123',
119
- threadId: 'thread-abc',
120
- ifIdle: {
121
- streamOptions: {
122
- maxSteps: 3,
123
- },
115
+ agent.sendMessage('Use the latest customer note too.', {
116
+ resourceId: 'user-123',
117
+ threadId: 'thread-abc',
118
+ ifIdle: {
119
+ streamOptions: {
120
+ maxSteps: 3,
124
121
  },
125
122
  },
126
- )
123
+ })
127
124
  ```
128
125
 
129
- Use `attributes` to identify different users in a shared thread. The signal type and attributes are rendered as XML so the model can distinguish who said what:
126
+ Use `attributes` to identify different users in a shared thread. The attributes are rendered as XML so the model can distinguish who said what:
130
127
 
131
128
  ```typescript
132
- agent.sendSignal(
129
+ agent.sendMessage(
133
130
  {
134
- type: 'user',
135
131
  contents: 'Can we simplify the API surface?',
136
132
  attributes: { name: 'Devin', from: 'slack' },
137
133
  },
@@ -147,11 +143,44 @@ The model receives this as:
147
143
 
148
144
  The UI sees just the message contents but can also read `attributes` and `metadata` off the signal message for custom rendering (e.g. showing user names, avatars, or platform badges).
149
145
 
146
+ ### `sendMessage(message, options)`
147
+
148
+ Sends a user message to an active run or memory thread. Use this when the active agent should receive the message immediately.
149
+
150
+ **message** (`string | Array<TextPart | FilePart> | { contents: string | Array<TextPart | FilePart>; attributes?: Record<string, JSONValue>; metadata?: Record<string, unknown>; providerOptions?: ProviderMetadata }`): User-authored input. Bare strings and parts without attributes are sent to the model as normal user input. When \`attributes\` are present, Mastra renders the message as a \`\<user>\` XML element with the attributes included.
151
+
152
+ **options.runId** (`string`): Run ID to target directly. Use this when you already know the active run ID.
153
+
154
+ **options.resourceId** (`string`): Resource ID for the memory thread. Required with \`threadId\` for thread-targeted messages.
155
+
156
+ **options.threadId** (`string`): Thread ID to target. Required with \`resourceId\` for thread-targeted messages.
157
+
158
+ **options.ifActive.behavior** (`'deliver' | 'persist' | 'discard'`): Controls what happens when the target thread is active. Defaults to \`deliver\`.
159
+
160
+ **options.ifIdle.behavior** (`'wake' | 'persist' | 'discard'`): Controls what happens when the target thread is idle. Defaults to \`wake\`.
161
+
162
+ **options.ifIdle.streamOptions** (`AgentExecutionOptions`): Options for the stream that starts when \`ifIdle.behavior\` is \`wake\`. Mastra uses the top-level \`resourceId\` and \`threadId\` for memory context.
163
+
164
+ Returns `{ accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void> }`. `persisted` is only present for `persist` behavior and resolves when Mastra finishes writing the message to memory.
165
+
166
+ ### `queueMessage(message, options)`
167
+
168
+ Queues a user message for the next turn on a thread. If the thread is active, Mastra waits for the active run to finish, then starts a new run with the queued message. If the thread is idle, Mastra starts a run immediately.
169
+
170
+ ```typescript
171
+ agent.queueMessage('Also check whether the tests need updates.', {
172
+ resourceId: 'user-123',
173
+ threadId: 'thread-abc',
174
+ })
175
+ ```
176
+
177
+ `queueMessage()` accepts the same `message` and `options` shape as `sendMessage()` and returns `{ accepted: true, runId: string, signal: CreatedAgentSignal, persisted?: Promise<void> }`.
178
+
150
179
  ### `sendSignal(signal, options)`
151
180
 
152
181
  Sends a signal to an active run or memory thread.
153
182
 
154
- **signal** (`{ type: 'user-message' | 'system-reminder' | string; contents: string | Array<TextPart | FilePart>; attributes?: Record<string, JSONValue>; metadata?: Record<string, unknown>; providerOptions?: ProviderMetadata }`): \`user-message\` signals without attributes are treated as plain user input. All other signals including \`user-message\` with \`attributes\`, \`system-reminder\`, and custom types are wrapped in an XML element named after the signal type with \`attributes\` rendered as XML attributes (e.g. \`\<user name="Devin" from="slack">message\</user>\`). The model sees the XML; the UI sees the raw contents and can read \`attributes\` for custom rendering. \`providerOptions\` is attached to the resulting prompt turn and persisted on the stored signal message.
183
+ **signal** (`{ type: 'user' | 'state' | 'reactive' | 'notification' | 'user-message' | 'system-reminder'; tagName?: string; contents: string | Array<TextPart | FilePart>; attributes?: Record<string, JSONValue>; metadata?: Record<string, unknown>; providerOptions?: ProviderMetadata }`): Signal context to send to the thread. \`type\` is the semantic signal category. \`tagName\` controls the XML tag the model sees. For example, \`{ type: 'notification', tagName: 'github-review' }\` renders as \`\<github-review>...\</github-review>\`. Legacy \`user-message\` and \`system-reminder\` payloads are still accepted and normalized. Unknown \`type\` values are rejected; use \`tagName\` for custom XML tags.
155
184
 
156
185
  **options.runId** (`string`): Run ID to target directly. Use this when you already know the active run ID.
157
186
 
@@ -169,7 +198,7 @@ Returns `{ accepted: true, runId: string, signal: CreatedAgentSignal, persisted?
169
198
 
170
199
  ### `subscribeToThread(options)`
171
200
 
172
- Subscribes to raw stream chunks for a memory thread. Use this before calling `sendSignal()` when you need to render stream output, observe signal echoes, or abort the active run.
201
+ Subscribes to raw stream chunks for a memory thread. Use this before calling `sendMessage()`, `queueMessage()`, or `sendSignal()` when you need to render stream output, observe signal echoes, or abort the active run.
173
202
 
174
203
  **options.resourceId** (`string`): Resource ID for the memory thread.
175
204
 
@@ -274,6 +274,7 @@ The Reference section provides documentation of Mastra's API, including paramete
274
274
  - [Google](https://mastra.ai/reference/voice/google)
275
275
  - [Google Gemini Live](https://mastra.ai/reference/voice/google-gemini-live)
276
276
  - [Inworld](https://mastra.ai/reference/voice/inworld)
277
+ - [Inworld Realtime](https://mastra.ai/reference/voice/inworld-realtime)
277
278
  - [Mastra Voice](https://mastra.ai/reference/voice/mastra-voice)
278
279
  - [Murf](https://mastra.ai/reference/voice/murf)
279
280
  - [OpenAI](https://mastra.ai/reference/voice/openai)
@@ -315,6 +316,7 @@ The Reference section provides documentation of Mastra's API, including paramete
315
316
  - [.start()](https://mastra.ai/reference/workflows/run-methods/start)
316
317
  - [.startAsync()](https://mastra.ai/reference/workflows/run-methods/startAsync)
317
318
  - [.timeTravel()](https://mastra.ai/reference/workflows/run-methods/timeTravel)
319
+ - [AgentCoreRuntimeSandbox](https://mastra.ai/reference/workspace/agentcore-runtime-sandbox)
318
320
  - [AgentFSFilesystem](https://mastra.ai/reference/workspace/agentfs-filesystem)
319
321
  - [AzureBlobFilesystem](https://mastra.ai/reference/workspace/azure-blob-filesystem)
320
322
  - [BlaxelSandbox](https://mastra.ai/reference/workspace/blaxel-sandbox)
@@ -329,6 +331,7 @@ The Reference section provides documentation of Mastra's API, including paramete
329
331
  - [ModalSandbox](https://mastra.ai/reference/workspace/modal-sandbox)
330
332
  - [S3Filesystem](https://mastra.ai/reference/workspace/s3-filesystem)
331
333
  - [SandboxProcessManager](https://mastra.ai/reference/workspace/process-manager)
334
+ - [VercelMicroVMSandbox](https://mastra.ai/reference/workspace/vercel-microvm-sandbox)
332
335
  - [VercelSandbox](https://mastra.ai/reference/workspace/vercel)
333
336
  - [Workspace Class](https://mastra.ai/reference/workspace/workspace-class)
334
337
  - [WorkspaceFilesystem](https://mastra.ai/reference/workspace/filesystem)
@@ -127,4 +127,10 @@ When you spot a spike in latency or token usage on the Metrics dashboard, correl
127
127
  ### Token metrics are missing
128
128
 
129
129
  - **Span is a model generation**: Token metrics are only emitted from `MODEL_GENERATION` spans.
130
- - **Provider reports usage**: The model provider must include `usage` data in its response. If usage is absent, no token metrics are emitted.
130
+ - **Provider reports usage**: The model provider must include `usage` data in its response. If usage is absent, no token metrics are emitted.
131
+
132
+ ## Related
133
+
134
+ - [Metrics overview](https://mastra.ai/docs/observability/metrics/overview)
135
+ - [Querying metrics](https://mastra.ai/docs/observability/metrics/querying)
136
+ - [Studio observability](https://mastra.ai/docs/studio/observability)