@mastra/core 1.15.0-alpha.0 → 1.15.0-alpha.2
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.
- package/CHANGELOG.md +33 -0
- package/dist/agent/index.cjs +8 -8
- package/dist/agent/index.js +1 -1
- package/dist/{chunk-JBYJDZT5.js → chunk-4YKZNIK6.js} +4 -4
- package/dist/{chunk-JBYJDZT5.js.map → chunk-4YKZNIK6.js.map} +1 -1
- package/dist/{chunk-I5ON7TPA.cjs → chunk-7BM5LQHF.cjs} +82 -82
- package/dist/{chunk-I5ON7TPA.cjs.map → chunk-7BM5LQHF.cjs.map} +1 -1
- package/dist/{chunk-IST54Q37.js → chunk-ASVFCNLS.js} +7 -7
- package/dist/{chunk-IST54Q37.js.map → chunk-ASVFCNLS.js.map} +1 -1
- package/dist/{chunk-DGSXFZGZ.js → chunk-CTJLKJMO.js} +10 -6
- package/dist/chunk-CTJLKJMO.js.map +1 -0
- package/dist/{chunk-4JBWS3Y6.js → chunk-EAWVRIHS.js} +3 -3
- package/dist/{chunk-4JBWS3Y6.js.map → chunk-EAWVRIHS.js.map} +1 -1
- package/dist/{chunk-7GXY5CDK.js → chunk-ECAVJWAH.js} +4 -4
- package/dist/{chunk-7GXY5CDK.js.map → chunk-ECAVJWAH.js.map} +1 -1
- package/dist/{chunk-EG3QZTQQ.cjs → chunk-EFYYAFWD.cjs} +19 -15
- package/dist/chunk-EFYYAFWD.cjs.map +1 -0
- package/dist/{chunk-ORYC6WMY.js → chunk-EYLPPZIF.js} +4 -2
- package/dist/chunk-EYLPPZIF.js.map +1 -0
- package/dist/{chunk-FIOAZZAM.js → chunk-FNOAF2SZ.js} +3 -3
- package/dist/{chunk-FIOAZZAM.js.map → chunk-FNOAF2SZ.js.map} +1 -1
- package/dist/{chunk-GMUEV4ML.cjs → chunk-FYQXIWRH.cjs} +4 -2
- package/dist/chunk-FYQXIWRH.cjs.map +1 -0
- package/dist/{chunk-KZLBDSIF.js → chunk-HIZDAENF.js} +3 -3
- package/dist/{chunk-KZLBDSIF.js.map → chunk-HIZDAENF.js.map} +1 -1
- package/dist/{chunk-7XPMIQIK.js → chunk-JIBMK2QP.js} +8 -8
- package/dist/{chunk-7XPMIQIK.js.map → chunk-JIBMK2QP.js.map} +1 -1
- package/dist/{chunk-CBLM3UY3.js → chunk-KCZ3R5SF.js} +3 -3
- package/dist/{chunk-CBLM3UY3.js.map → chunk-KCZ3R5SF.js.map} +1 -1
- package/dist/{chunk-Y2I3C7FR.cjs → chunk-M5BDH7B4.cjs} +6 -6
- package/dist/{chunk-Y2I3C7FR.cjs.map → chunk-M5BDH7B4.cjs.map} +1 -1
- package/dist/{chunk-4CC2ZV3B.js → chunk-MHTWFVXK.js} +3 -3
- package/dist/{chunk-4CC2ZV3B.js.map → chunk-MHTWFVXK.js.map} +1 -1
- package/dist/{chunk-REVBDBHI.cjs → chunk-NWPRZZ2K.cjs} +48 -48
- package/dist/{chunk-REVBDBHI.cjs.map → chunk-NWPRZZ2K.cjs.map} +1 -1
- package/dist/{chunk-PEKFBFE2.cjs → chunk-ORHPD25N.cjs} +7 -7
- package/dist/{chunk-PEKFBFE2.cjs.map → chunk-ORHPD25N.cjs.map} +1 -1
- package/dist/{chunk-SV6VG3XO.cjs → chunk-OX63O3QG.cjs} +5 -5
- package/dist/{chunk-SV6VG3XO.cjs.map → chunk-OX63O3QG.cjs.map} +1 -1
- package/dist/{chunk-NSJS72DA.cjs → chunk-Q64Z437G.cjs} +15 -15
- package/dist/{chunk-NSJS72DA.cjs.map → chunk-Q64Z437G.cjs.map} +1 -1
- package/dist/{chunk-W4R4TA4Z.cjs → chunk-RFZB2PQE.cjs} +9 -9
- package/dist/{chunk-W4R4TA4Z.cjs.map → chunk-RFZB2PQE.cjs.map} +1 -1
- package/dist/{chunk-J7UJLVIQ.cjs → chunk-TJB7IK7N.cjs} +19 -11
- package/dist/chunk-TJB7IK7N.cjs.map +1 -0
- package/dist/{chunk-OT7UVM2Z.cjs → chunk-X4RVX77L.cjs} +185 -185
- package/dist/{chunk-OT7UVM2Z.cjs.map → chunk-X4RVX77L.cjs.map} +1 -1
- package/dist/{chunk-XVOLOB5X.cjs → chunk-YV5UMIRV.cjs} +3 -3
- package/dist/{chunk-XVOLOB5X.cjs.map → chunk-YV5UMIRV.cjs.map} +1 -1
- package/dist/{chunk-SCTBRRU3.js → chunk-Z76WT6W3.js} +18 -10
- package/dist/chunk-Z76WT6W3.js.map +1 -0
- package/dist/datasets/index.cjs +11 -11
- package/dist/datasets/index.js +1 -1
- package/dist/docs/SKILL.md +10 -11
- package/dist/docs/assets/SOURCE_MAP.json +154 -154
- package/dist/docs/references/docs-agents-agent-approval.md +114 -193
- package/dist/docs/references/docs-agents-guardrails.md +120 -167
- package/dist/docs/references/docs-agents-networks.md +88 -205
- package/dist/docs/references/docs-agents-overview.md +47 -256
- package/dist/docs/references/docs-agents-processors.md +201 -297
- package/dist/docs/references/docs-agents-structured-output.md +13 -22
- package/dist/docs/references/docs-agents-supervisor-agents.md +24 -18
- package/dist/docs/references/docs-agents-using-tools.md +81 -104
- package/dist/docs/references/docs-memory-observational-memory.md +4 -2
- package/dist/docs/references/docs-memory-overview.md +219 -24
- package/dist/docs/references/docs-memory-semantic-recall.md +1 -1
- package/dist/docs/references/docs-memory-storage.md +4 -4
- package/dist/docs/references/docs-memory-working-memory.md +1 -1
- package/dist/docs/references/docs-observability-overview.md +1 -1
- package/dist/docs/references/docs-observability-tracing-exporters-arize.md +1 -1
- package/dist/docs/references/docs-server-request-context.md +1 -1
- package/dist/docs/references/docs-workflows-overview.md +1 -1
- package/dist/docs/references/docs-workspace-overview.md +1 -1
- package/dist/docs/references/guides-concepts-multi-agent-systems.md +75 -0
- package/dist/docs/references/reference-agents-agent.md +6 -8
- package/dist/docs/references/reference-agents-generate.md +74 -23
- package/dist/docs/references/reference-agents-getMemory.md +1 -1
- package/dist/docs/references/reference-agents-network.md +2 -2
- package/dist/docs/references/reference-ai-sdk-network-route.md +1 -1
- package/dist/docs/references/reference-ai-sdk-with-mastra.md +1 -1
- package/dist/docs/references/reference-core-getMemory.md +1 -2
- package/dist/docs/references/reference-core-listMemory.md +1 -2
- package/dist/docs/references/reference-harness-harness-class.md +2 -2
- package/dist/docs/references/reference-memory-observational-memory.md +3 -1
- package/dist/docs/references/reference-processors-processor-interface.md +2 -0
- package/dist/docs/references/reference-storage-overview.md +1 -1
- package/dist/docs/references/reference-templates-overview.md +1 -1
- package/dist/docs/references/reference-tools-create-tool.md +16 -4
- package/dist/evals/index.cjs +5 -5
- package/dist/evals/index.js +2 -2
- package/dist/evals/scoreTraces/index.cjs +3 -3
- package/dist/evals/scoreTraces/index.js +1 -1
- package/dist/harness/harness.d.ts +3 -0
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/index.cjs +48 -13
- package/dist/harness/index.cjs.map +1 -1
- package/dist/harness/index.js +46 -11
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/types.d.ts +11 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/llm/index.cjs +16 -16
- package/dist/llm/index.js +5 -5
- package/dist/llm/model/model.d.ts.map +1 -1
- package/dist/llm/model/provider-types.generated.d.ts +6 -2
- package/dist/loop/index.cjs +14 -14
- package/dist/loop/index.js +1 -1
- package/dist/mastra/index.cjs +2 -2
- package/dist/mastra/index.js +1 -1
- package/dist/memory/index.cjs +14 -14
- package/dist/memory/index.js +1 -1
- package/dist/memory/types.d.ts +7 -0
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/models-dev-E6FRPGHV.js +3 -0
- package/dist/{models-dev-5BT32JYX.js.map → models-dev-E6FRPGHV.js.map} +1 -1
- package/dist/models-dev-WIROJ2IM.cjs +12 -0
- package/dist/{models-dev-OTMJW4WK.cjs.map → models-dev-WIROJ2IM.cjs.map} +1 -1
- package/dist/netlify-7IRBQ2BY.cjs +12 -0
- package/dist/{netlify-DT2P2NQD.cjs.map → netlify-7IRBQ2BY.cjs.map} +1 -1
- package/dist/netlify-OAGRP6WY.js +3 -0
- package/dist/{netlify-FJCQU3OY.js.map → netlify-OAGRP6WY.js.map} +1 -1
- package/dist/processor-provider/index.cjs +10 -10
- package/dist/processor-provider/index.js +1 -1
- package/dist/processors/index.cjs +42 -42
- package/dist/processors/index.js +1 -1
- package/dist/provider-registry-2MHU2NP6.js +3 -0
- package/dist/{provider-registry-BCSAL2IQ.js.map → provider-registry-2MHU2NP6.js.map} +1 -1
- package/dist/provider-registry-FINEGQHE.cjs +40 -0
- package/dist/{provider-registry-65WCBR2K.cjs.map → provider-registry-FINEGQHE.cjs.map} +1 -1
- package/dist/provider-registry.json +14 -6
- package/dist/relevance/index.cjs +3 -3
- package/dist/relevance/index.js +1 -1
- package/dist/stream/index.cjs +8 -8
- package/dist/stream/index.js +1 -1
- package/dist/test-utils/llm-mock.cjs +4 -4
- package/dist/test-utils/llm-mock.js +1 -1
- package/dist/tool-loop-agent/index.cjs +4 -4
- package/dist/tool-loop-agent/index.js +1 -1
- package/dist/workflows/default.d.ts +2 -2
- package/dist/workflows/default.d.ts.map +1 -1
- package/dist/workflows/evented/index.cjs +10 -10
- package/dist/workflows/evented/index.js +1 -1
- package/dist/workflows/index.cjs +24 -24
- package/dist/workflows/index.js +1 -1
- package/package.json +7 -7
- package/src/llm/model/provider-types.generated.d.ts +6 -2
- package/dist/chunk-DGSXFZGZ.js.map +0 -1
- package/dist/chunk-EG3QZTQQ.cjs.map +0 -1
- package/dist/chunk-GMUEV4ML.cjs.map +0 -1
- package/dist/chunk-J7UJLVIQ.cjs.map +0 -1
- package/dist/chunk-ORYC6WMY.js.map +0 -1
- package/dist/chunk-SCTBRRU3.js.map +0 -1
- package/dist/docs/references/docs-agents-agent-memory.md +0 -209
- package/dist/docs/references/docs-agents-network-approval.md +0 -278
- package/dist/models-dev-5BT32JYX.js +0 -3
- package/dist/models-dev-OTMJW4WK.cjs +0 -12
- package/dist/netlify-DT2P2NQD.cjs +0 -12
- package/dist/netlify-FJCQU3OY.js +0 -3
- package/dist/provider-registry-65WCBR2K.cjs +0 -40
- package/dist/provider-registry-BCSAL2IQ.js +0 -3
|
@@ -7,7 +7,7 @@ Processors are configured as:
|
|
|
7
7
|
- **`inputProcessors`**: Run before messages reach the language model.
|
|
8
8
|
- **`outputProcessors`**: Run after the language model generates a response, but before it's returned to users.
|
|
9
9
|
|
|
10
|
-
You can use individual `Processor` objects or compose them into workflows using Mastra's workflow primitives. Workflows give you advanced control over processor execution order, parallel processing, and conditional logic.
|
|
10
|
+
You can use individual [`Processor`](https://mastra.ai/reference/processors/processor-interface) objects or compose them into workflows using Mastra's workflow primitives. Workflows give you advanced control over processor execution order, parallel processing, and conditional logic.
|
|
11
11
|
|
|
12
12
|
Some processors implement both input and output logic and can be used in either array depending on where the transformation should occur.
|
|
13
13
|
|
|
@@ -26,7 +26,7 @@ Use processors to:
|
|
|
26
26
|
|
|
27
27
|
Mastra includes several processors for common use cases. You can also create custom processors for application-specific requirements.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Quickstart
|
|
30
30
|
|
|
31
31
|
Import and instantiate the processor, then pass it to the agent's `inputProcessors` or `outputProcessors` array:
|
|
32
32
|
|
|
@@ -81,27 +81,20 @@ Your processors run first, then memory persists messages.
|
|
|
81
81
|
|
|
82
82
|
This ordering ensures that if your output guardrail calls `abort()`, memory processors are skipped and no messages are saved. See [Memory Processors](https://mastra.ai/docs/memory/memory-processors) for details.
|
|
83
83
|
|
|
84
|
-
##
|
|
84
|
+
## Create custom processors
|
|
85
85
|
|
|
86
86
|
Custom processors implement the `Processor` interface:
|
|
87
87
|
|
|
88
|
-
###
|
|
88
|
+
### Transform input messages
|
|
89
89
|
|
|
90
90
|
```typescript
|
|
91
|
-
import type { Processor,
|
|
91
|
+
import type { Processor, ProcessInputArgs } from '@mastra/core/processors'
|
|
92
|
+
import type { MastraDBMessage } from '@mastra/core/memory'
|
|
92
93
|
|
|
93
94
|
export class CustomInputProcessor implements Processor {
|
|
94
95
|
id = 'custom-input'
|
|
95
96
|
|
|
96
|
-
async processInput({
|
|
97
|
-
messages,
|
|
98
|
-
systemMessages,
|
|
99
|
-
context,
|
|
100
|
-
}: {
|
|
101
|
-
messages: MastraDBMessage[]
|
|
102
|
-
systemMessages: CoreMessage[]
|
|
103
|
-
context: RequestContext
|
|
104
|
-
}): Promise<MastraDBMessage[]> {
|
|
97
|
+
async processInput({ messages }: ProcessInputArgs): Promise<MastraDBMessage[]> {
|
|
105
98
|
// Transform messages before they reach the LLM
|
|
106
99
|
return messages.map(msg => ({
|
|
107
100
|
...msg,
|
|
@@ -114,58 +107,20 @@ export class CustomInputProcessor implements Processor {
|
|
|
114
107
|
}
|
|
115
108
|
```
|
|
116
109
|
|
|
117
|
-
The `processInput` method receives
|
|
110
|
+
The `processInput()` method receives `messages`, `systemMessages`, and an `abort()` function. Return a `MastraDBMessage[]` to replace messages, or `{ messages, systemMessages }` to also modify system messages.
|
|
118
111
|
|
|
119
|
-
|
|
120
|
-
- `systemMessages`: All system messages (agent instructions, memory context, user-provided system prompts)
|
|
121
|
-
- `messageList`: The full MessageList instance for advanced use cases
|
|
122
|
-
- `abort`: Function to stop processing and return early
|
|
123
|
-
- `requestContext`: Execution metadata like `threadId` and `resourceId`
|
|
112
|
+
See the [`Processor` reference](https://mastra.ai/reference/processors/processor-interface) for all available arguments and return types.
|
|
124
113
|
|
|
125
|
-
|
|
114
|
+
### Control each step
|
|
126
115
|
|
|
127
|
-
|
|
128
|
-
- `{ messages: MastraDBMessage[]; systemMessages: CoreMessage[] }` — Both messages and modified system messages
|
|
129
|
-
|
|
130
|
-
The framework handles both return formats, so modifying system messages is optional and existing processors continue to work.
|
|
131
|
-
|
|
132
|
-
### Modifying system messages
|
|
133
|
-
|
|
134
|
-
To modify system messages (e.g., trim verbose prompts for smaller models), return an object with both `messages` and `systemMessages`:
|
|
116
|
+
While `processInput()` runs once at the start of agent execution, `processInputStep()` runs at **each step** of the agentic loop (including tool call continuations). This enables per-step configuration changes like dynamic model switching or tool choice modifications.
|
|
135
117
|
|
|
136
118
|
```typescript
|
|
137
|
-
import type {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
async processInput({
|
|
143
|
-
messages,
|
|
144
|
-
systemMessages,
|
|
145
|
-
}): Promise<{ messages: MastraDBMessage[]; systemMessages: CoreMessage[] }> {
|
|
146
|
-
// Trim system messages for smaller models
|
|
147
|
-
const trimmedSystemMessages = systemMessages.map(msg => ({
|
|
148
|
-
...msg,
|
|
149
|
-
content: typeof msg.content === 'string' ? msg.content.substring(0, 500) : msg.content,
|
|
150
|
-
}))
|
|
151
|
-
|
|
152
|
-
return { messages, systemMessages: trimmedSystemMessages }
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
This is useful for:
|
|
158
|
-
|
|
159
|
-
- Trimming verbose system prompts for models with smaller context windows
|
|
160
|
-
- Filtering or modifying semantic recall content to prevent "prompt too long" errors
|
|
161
|
-
- Dynamically adjusting system instructions based on the conversation
|
|
162
|
-
|
|
163
|
-
### Per-step processing with `processInputStep`
|
|
164
|
-
|
|
165
|
-
While `processInput` runs once at the start of agent execution, `processInputStep` runs at **each step** of the agentic loop (including tool call continuations). This enables per-step configuration changes like dynamic model switching or tool choice modifications.
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
import type { Processor, ProcessInputStepArgs, ProcessInputStepResult } from '@mastra/core'
|
|
119
|
+
import type {
|
|
120
|
+
Processor,
|
|
121
|
+
ProcessInputStepArgs,
|
|
122
|
+
ProcessInputStepResult,
|
|
123
|
+
} from '@mastra/core/processors'
|
|
169
124
|
|
|
170
125
|
export class DynamicModelProcessor implements Processor {
|
|
171
126
|
id = 'dynamic-model'
|
|
@@ -192,100 +147,13 @@ export class DynamicModelProcessor implements Processor {
|
|
|
192
147
|
}
|
|
193
148
|
```
|
|
194
149
|
|
|
195
|
-
The `
|
|
196
|
-
|
|
197
|
-
- `stepNumber`: Current step in the agentic loop (0-indexed)
|
|
198
|
-
- `steps`: Results from previous steps
|
|
199
|
-
- `messages`: Current messages snapshot (read-only)
|
|
200
|
-
- `systemMessages`: Current system messages (read-only)
|
|
201
|
-
- `messageList`: The full MessageList instance for mutations
|
|
202
|
-
- `model`: Current model being used
|
|
203
|
-
- `tools`: Current tools available for this step
|
|
204
|
-
- `toolChoice`: Current tool choice setting
|
|
205
|
-
- `activeTools`: Currently active tools
|
|
206
|
-
- `providerOptions`: Provider-specific options
|
|
207
|
-
- `modelSettings`: Model settings like temperature
|
|
208
|
-
- `structuredOutput`: Structured output configuration
|
|
209
|
-
|
|
210
|
-
The method can return any combination of:
|
|
211
|
-
|
|
212
|
-
- `model`: Change the model for this step
|
|
213
|
-
- `tools`: Replace or add tools (use spread to merge: `{ tools: { ...tools, newTool } }`)
|
|
214
|
-
- `toolChoice`: Change tool selection behavior
|
|
215
|
-
- `activeTools`: Filter which tools are available
|
|
216
|
-
- `messages`: Replace messages (applied to messageList)
|
|
217
|
-
- `systemMessages`: Replace all system messages
|
|
218
|
-
- `providerOptions`: Modify provider options
|
|
219
|
-
- `modelSettings`: Modify model settings
|
|
220
|
-
- `structuredOutput`: Modify structured output configuration
|
|
221
|
-
|
|
222
|
-
#### Ensuring a final response with `maxSteps`
|
|
223
|
-
|
|
224
|
-
When using `maxSteps` to limit agent execution, the agent may return an empty response if it attempts a tool call on the final step. Use `processInputStep` to force a text response on the last step:
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
import { Processor, ProcessInputStepArgs, ProcessInputStepResult } from '@mastra/core/processors'
|
|
150
|
+
The method receives the current `stepNumber`, `model`, `tools`, `toolChoice`, `messages`, and more. Return an object with any properties you want to override for that step, for example `{ model, toolChoice, tools, systemMessages }`.
|
|
228
151
|
|
|
229
|
-
|
|
230
|
-
readonly id = 'ensure-final-response'
|
|
152
|
+
See the [`Processor` reference](https://mastra.ai/reference/processors/processor-interface) for all available arguments and return types.
|
|
231
153
|
|
|
232
|
-
|
|
154
|
+
### Use the `prepareStep()` callback
|
|
233
155
|
|
|
234
|
-
|
|
235
|
-
this.maxSteps = maxSteps
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async processInputStep({
|
|
239
|
-
stepNumber,
|
|
240
|
-
systemMessages,
|
|
241
|
-
}: ProcessInputStepArgs): Promise<ProcessInputStepResult> {
|
|
242
|
-
// On the last step, prevent tool calls and instruct the LLM to summarize
|
|
243
|
-
if (stepNumber === this.maxSteps - 1) {
|
|
244
|
-
return {
|
|
245
|
-
tools: {},
|
|
246
|
-
toolChoice: 'none',
|
|
247
|
-
systemMessages: [
|
|
248
|
-
...systemMessages,
|
|
249
|
-
{
|
|
250
|
-
role: 'system',
|
|
251
|
-
content:
|
|
252
|
-
'You have reached the maximum number of steps. Summarize your progress so far and provide a best-effort response. If the task is incomplete, clearly indicate what remains to be done.',
|
|
253
|
-
},
|
|
254
|
-
],
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return {}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
Use it with your agent:
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
import { Agent } from '@mastra/core/agent'
|
|
266
|
-
import { EnsureFinalResponseProcessor } from '../processors/ensure-final-response'
|
|
267
|
-
|
|
268
|
-
const MAX_STEPS = 5
|
|
269
|
-
|
|
270
|
-
const agent = new Agent({
|
|
271
|
-
id: 'bounded-agent',
|
|
272
|
-
name: 'Bounded Agent',
|
|
273
|
-
model: 'openai/gpt-5-mini',
|
|
274
|
-
tools: {
|
|
275
|
-
/* your tools */
|
|
276
|
-
},
|
|
277
|
-
inputProcessors: [new EnsureFinalResponseProcessor(MAX_STEPS)],
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
// Pass maxSteps when calling generate/stream
|
|
281
|
-
const result = await agent.generate('Your prompt', { maxSteps: MAX_STEPS })
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
This ensures that on the final allowed step (step 4 when `maxSteps` is 5, since steps are 0-indexed), the LLM generates a summary instead of attempting another tool call, and clearly indicates if the task is incomplete.
|
|
285
|
-
|
|
286
|
-
#### Using `prepareStep` callback
|
|
287
|
-
|
|
288
|
-
For simpler per-step logic, you can use the `prepareStep` callback on `generate()` or `stream()` instead of creating a full processor:
|
|
156
|
+
The `prepareStep()` callback on `generate()` or `stream()` is a shorthand for `processInputStep()`. Internally, Mastra wraps it in a processor that calls your function at each step. It accepts the same arguments and return type as `processInputStep()`, but doesn't require creating a class:
|
|
289
157
|
|
|
290
158
|
```typescript
|
|
291
159
|
await agent.generate('Complex task', {
|
|
@@ -300,10 +168,11 @@ await agent.generate('Complex task', {
|
|
|
300
168
|
})
|
|
301
169
|
```
|
|
302
170
|
|
|
303
|
-
###
|
|
171
|
+
### Transform output messages
|
|
304
172
|
|
|
305
173
|
```typescript
|
|
306
|
-
import type { Processor
|
|
174
|
+
import type { Processor } from '@mastra/core/processors'
|
|
175
|
+
import type { MastraDBMessage } from '@mastra/core/memory'
|
|
307
176
|
|
|
308
177
|
export class CustomOutputProcessor implements Processor {
|
|
309
178
|
id = 'custom-output'
|
|
@@ -312,6 +181,35 @@ export class CustomOutputProcessor implements Processor {
|
|
|
312
181
|
// Transform messages after the LLM generates them
|
|
313
182
|
return messages.filter(msg => msg.role !== 'system')
|
|
314
183
|
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The method also receives a `result` object with the full generation data — `text`, `usage` (token counts), `finishReason`, and `steps` (each containing `toolCalls`, `toolResults`, etc.). Use it to track usage or inspect tool calls:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import type { Processor } from '@mastra/core/processors'
|
|
191
|
+
|
|
192
|
+
export class UsageTracker implements Processor {
|
|
193
|
+
id = 'usage-tracker'
|
|
194
|
+
|
|
195
|
+
async processOutputResult({ messages, result }) {
|
|
196
|
+
console.log(`Tokens: ${result.usage.inputTokens} in, ${result.usage.outputTokens} out`)
|
|
197
|
+
console.log(`Finish reason: ${result.finishReason}`)
|
|
198
|
+
return messages
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Filter streamed output
|
|
204
|
+
|
|
205
|
+
The `processOutputStream()` method transforms or filters streaming chunks before they reach the client:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import type { Processor } from '@mastra/core/processors'
|
|
209
|
+
import type { ChunkType } from '@mastra/core/stream'
|
|
210
|
+
|
|
211
|
+
export class StreamFilter implements Processor {
|
|
212
|
+
id = 'stream-filter'
|
|
315
213
|
|
|
316
214
|
async processOutputStream({ part }): Promise<ChunkType | null> {
|
|
317
215
|
// Transform or filter streaming chunks
|
|
@@ -320,42 +218,132 @@ export class CustomOutputProcessor implements Processor {
|
|
|
320
218
|
}
|
|
321
219
|
```
|
|
322
220
|
|
|
323
|
-
|
|
221
|
+
To also receive custom `data-*` chunks emitted by tools via `writer.custom()`, set `processDataParts = true` on your processor. This lets you inspect, modify, or block tool-emitted data chunks before they reach the client.
|
|
324
222
|
|
|
325
|
-
|
|
223
|
+
### Validate each response
|
|
326
224
|
|
|
327
|
-
The `
|
|
225
|
+
The `processOutputStep()` method runs after each LLM step, allowing you to validate the response and optionally request a retry:
|
|
328
226
|
|
|
329
227
|
```typescript
|
|
330
|
-
import type { Processor } from '@mastra/core'
|
|
228
|
+
import type { Processor } from '@mastra/core/processors'
|
|
331
229
|
|
|
332
|
-
export class
|
|
333
|
-
id = '
|
|
230
|
+
export class ResponseValidator implements Processor {
|
|
231
|
+
id = 'response-validator'
|
|
334
232
|
|
|
335
|
-
async
|
|
336
|
-
|
|
337
|
-
console.log(`Tokens: ${result.usage.inputTokens} in, ${result.usage.outputTokens} out`)
|
|
338
|
-
console.log(`Finish reason: ${result.finishReason}`)
|
|
339
|
-
console.log(`Steps: ${result.steps.length}`)
|
|
233
|
+
async processOutputStep({ text, abort, retryCount }) {
|
|
234
|
+
const isValid = await validateResponse(text)
|
|
340
235
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if (step.toolCalls?.length) {
|
|
344
|
-
console.log(`Step used ${step.toolCalls.length} tool calls`)
|
|
345
|
-
}
|
|
236
|
+
if (!isValid && retryCount < 3) {
|
|
237
|
+
abort('Response did not meet requirements. Try again.', { retry: true })
|
|
346
238
|
}
|
|
347
239
|
|
|
348
|
-
return
|
|
240
|
+
return []
|
|
349
241
|
}
|
|
350
242
|
}
|
|
351
243
|
```
|
|
352
244
|
|
|
353
|
-
|
|
245
|
+
For more on retry behavior, see [Retry mechanism](#retry-mechanism) in Advanced patterns.
|
|
246
|
+
|
|
247
|
+
## Built-in utility processors
|
|
248
|
+
|
|
249
|
+
Mastra provides utility processors for common tasks:
|
|
250
|
+
|
|
251
|
+
**For security and validation processors**, see the [Guardrails](https://mastra.ai/docs/agents/guardrails) page for input/output guardrails and moderation processors. **For memory-specific processors**, see the [Memory Processors](https://mastra.ai/docs/memory/memory-processors) page for processors that handle message history, semantic recall, and working memory.
|
|
252
|
+
|
|
253
|
+
### `TokenLimiter`
|
|
254
|
+
|
|
255
|
+
Prevents context window overflow by removing older messages when the total token count exceeds a specified limit. Prioritizes recent messages and preserves system messages.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { Agent } from '@mastra/core/agent'
|
|
259
|
+
import { TokenLimiter } from '@mastra/core/processors'
|
|
260
|
+
|
|
261
|
+
const agent = new Agent({
|
|
262
|
+
name: 'my-agent',
|
|
263
|
+
model: 'openai/gpt-5.4',
|
|
264
|
+
inputProcessors: [new TokenLimiter(127000)],
|
|
265
|
+
})
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
See the [`TokenLimiterProcessor` reference](https://mastra.ai/reference/processors/token-limiter-processor) for custom encoding, strategy, and count mode options.
|
|
269
|
+
|
|
270
|
+
### `ToolCallFilter`
|
|
271
|
+
|
|
272
|
+
Removes tool calls and results from messages sent to the LLM, saving tokens on verbose tool interactions. Optionally exclude only specific tools. This filter only affects the LLM input, filtered messages are still saved to memory.
|
|
273
|
+
|
|
274
|
+
See the [`ToolCallFilter` reference](https://mastra.ai/reference/processors/tool-call-filter) for configuration options and the [Memory Processors](https://mastra.ai/docs/memory/memory-processors) page for pre-memory filtering.
|
|
275
|
+
|
|
276
|
+
### `ToolSearchProcessor`
|
|
277
|
+
|
|
278
|
+
Enables dynamic tool discovery for agents with large tool libraries. Instead of providing all tools upfront, the processor gives the agent `search_tools` and `load_tool` meta-tools to find and load tools by keyword on demand, reducing context token usage.
|
|
279
|
+
|
|
280
|
+
See the [`ToolSearchProcessor` reference](https://mastra.ai/reference/processors/tool-search-processor) for configuration options and usage examples.
|
|
281
|
+
|
|
282
|
+
## Advanced patterns
|
|
283
|
+
|
|
284
|
+
### Ensure a final response with `maxSteps`
|
|
285
|
+
|
|
286
|
+
When using `maxSteps` to limit agent execution, the agent may return an empty response if it attempts a tool call on the final step. Use `processInputStep()` to force a text response on the last step:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import type {
|
|
290
|
+
Processor,
|
|
291
|
+
ProcessInputStepArgs,
|
|
292
|
+
ProcessInputStepResult,
|
|
293
|
+
} from '@mastra/core/processors'
|
|
294
|
+
|
|
295
|
+
export class EnsureFinalResponseProcessor implements Processor {
|
|
296
|
+
readonly id = 'ensure-final-response'
|
|
297
|
+
|
|
298
|
+
private maxSteps: number
|
|
299
|
+
|
|
300
|
+
constructor(maxSteps: number) {
|
|
301
|
+
this.maxSteps = maxSteps
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async processInputStep({
|
|
305
|
+
stepNumber,
|
|
306
|
+
systemMessages,
|
|
307
|
+
}: ProcessInputStepArgs): Promise<ProcessInputStepResult> {
|
|
308
|
+
// On the last step, prevent tool calls and instruct the LLM to summarize
|
|
309
|
+
if (stepNumber === this.maxSteps - 1) {
|
|
310
|
+
return {
|
|
311
|
+
tools: {},
|
|
312
|
+
toolChoice: 'none',
|
|
313
|
+
systemMessages: [
|
|
314
|
+
...systemMessages,
|
|
315
|
+
{
|
|
316
|
+
role: 'system',
|
|
317
|
+
content:
|
|
318
|
+
'You have reached the maximum number of steps. Summarize your progress so far and provide a best-effort response. If the task is incomplete, clearly indicate what remains to be done.',
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return {}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Add it to `inputProcessors` and pass the same `maxSteps` value to `generate()` or `stream()`:
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
const MAX_STEPS = 5
|
|
332
|
+
|
|
333
|
+
const agent = new Agent({
|
|
334
|
+
inputProcessors: [new EnsureFinalResponseProcessor(MAX_STEPS)],
|
|
335
|
+
// ...
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
await agent.generate('Your prompt', { maxSteps: MAX_STEPS })
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Emit custom stream events
|
|
354
342
|
|
|
355
343
|
Output processors receive a `writer` object that lets you emit custom data chunks back to the client during streaming. This is useful for use cases like streaming moderation results or sending UI update signals without blocking the original stream.
|
|
356
344
|
|
|
357
345
|
```typescript
|
|
358
|
-
import type { Processor
|
|
346
|
+
import type { Processor } from '@mastra/core/processors'
|
|
359
347
|
|
|
360
348
|
export class ModerationProcessor implements Processor {
|
|
361
349
|
id = 'moderation'
|
|
@@ -402,12 +390,13 @@ for await (const chunk of stream.fullStream) {
|
|
|
402
390
|
|
|
403
391
|
Custom chunk types must use the `data-` prefix (e.g., `data-moderation-update`, `data-status`).
|
|
404
392
|
|
|
405
|
-
|
|
393
|
+
### Add metadata to messages
|
|
406
394
|
|
|
407
395
|
You can add custom metadata to messages in `processOutputResult`. This metadata is accessible via the response object:
|
|
408
396
|
|
|
409
397
|
```typescript
|
|
410
|
-
import type { Processor
|
|
398
|
+
import type { Processor } from '@mastra/core/processors'
|
|
399
|
+
import type { MastraDBMessage } from '@mastra/core/memory'
|
|
411
400
|
|
|
412
401
|
export class MetadataProcessor implements Processor {
|
|
413
402
|
id = 'metadata-processor'
|
|
@@ -447,124 +436,20 @@ const assistantMessage = result.response?.uiMessages?.find(m => m.role === 'assi
|
|
|
447
436
|
console.log(assistantMessage?.metadata?.customData)
|
|
448
437
|
```
|
|
449
438
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
const stream = await agent.stream('Hello')
|
|
454
|
-
|
|
455
|
-
for await (const chunk of stream.fullStream) {
|
|
456
|
-
if (chunk.type === 'finish') {
|
|
457
|
-
// Access response with processor-added metadata from the finish chunk
|
|
458
|
-
const uiMessages = chunk.payload.response?.uiMessages
|
|
459
|
-
const assistantMessage = uiMessages?.find(m => m.role === 'assistant')
|
|
460
|
-
console.log(assistantMessage?.metadata?.customData)
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Or via the response promise after consuming the stream
|
|
465
|
-
const response = await stream.response
|
|
466
|
-
console.log(response.uiMessages)
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
## Built-in utility processors
|
|
470
|
-
|
|
471
|
-
Mastra provides utility processors for common tasks:
|
|
472
|
-
|
|
473
|
-
**For security and validation processors**, see the [Guardrails](https://mastra.ai/docs/agents/guardrails) page for input/output guardrails and moderation processors. **For memory-specific processors**, see the [Memory Processors](https://mastra.ai/docs/memory/memory-processors) page for processors that handle message history, semantic recall, and working memory.
|
|
474
|
-
|
|
475
|
-
### `TokenLimiter`
|
|
476
|
-
|
|
477
|
-
Prevents context window overflow by removing older messages when the total token count exceeds a specified limit.
|
|
478
|
-
|
|
479
|
-
```typescript
|
|
480
|
-
import { Agent } from '@mastra/core/agent'
|
|
481
|
-
import { TokenLimiter } from '@mastra/core/processors'
|
|
482
|
-
|
|
483
|
-
const agent = new Agent({
|
|
484
|
-
name: 'my-agent',
|
|
485
|
-
model: 'openai/gpt-5.4',
|
|
486
|
-
inputProcessors: [
|
|
487
|
-
// Ensure the total tokens don't exceed ~127k
|
|
488
|
-
new TokenLimiter(127000),
|
|
489
|
-
],
|
|
490
|
-
})
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
The `TokenLimiter` uses the `o200k_base` encoding by default. You can specify other encodings for different models:
|
|
494
|
-
|
|
495
|
-
```typescript
|
|
496
|
-
import cl100k_base from 'js-tiktoken/ranks/cl100k_base'
|
|
497
|
-
|
|
498
|
-
const agent = new Agent({
|
|
499
|
-
name: 'my-agent',
|
|
500
|
-
inputProcessors: [
|
|
501
|
-
new TokenLimiter({
|
|
502
|
-
limit: 16000, // Example limit for a 16k context model
|
|
503
|
-
encoding: cl100k_base,
|
|
504
|
-
}),
|
|
505
|
-
],
|
|
506
|
-
})
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
### `ToolCallFilter`
|
|
510
|
-
|
|
511
|
-
Removes tool calls from messages sent to the LLM, saving tokens by excluding potentially verbose tool interactions.
|
|
512
|
-
|
|
513
|
-
```typescript
|
|
514
|
-
import { Agent } from '@mastra/core/agent'
|
|
515
|
-
import { ToolCallFilter, TokenLimiter } from '@mastra/core/processors'
|
|
516
|
-
|
|
517
|
-
const agent = new Agent({
|
|
518
|
-
name: 'my-agent',
|
|
519
|
-
model: 'openai/gpt-5.4',
|
|
520
|
-
inputProcessors: [
|
|
521
|
-
// Example 1: Remove all tool calls/results
|
|
522
|
-
new ToolCallFilter(),
|
|
523
|
-
|
|
524
|
-
// Example 2: Remove only specific tool calls
|
|
525
|
-
new ToolCallFilter({ exclude: ['generateImageTool'] }),
|
|
526
|
-
|
|
527
|
-
// Always place TokenLimiter last
|
|
528
|
-
new TokenLimiter(127000),
|
|
529
|
-
],
|
|
530
|
-
})
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
> **Note:** The example above filters tool calls and limits tokens for the LLM, but these filtered messages will still be saved to memory. To also filter messages before they're saved to memory, manually add memory processors before utility processors. See [Memory Processors](https://mastra.ai/docs/memory/memory-processors) for details.
|
|
534
|
-
|
|
535
|
-
### `ToolSearchProcessor`
|
|
536
|
-
|
|
537
|
-
Enables dynamic tool discovery and loading for agents with large tool libraries. Instead of providing all tools upfront, the agent searches for tools by keyword and loads them on demand, reducing context token usage.
|
|
538
|
-
|
|
539
|
-
```typescript
|
|
540
|
-
import { Agent } from '@mastra/core/agent'
|
|
541
|
-
import { ToolSearchProcessor } from '@mastra/core/processors'
|
|
542
|
-
|
|
543
|
-
const agent = new Agent({
|
|
544
|
-
name: 'my-agent',
|
|
545
|
-
model: 'openai/gpt-5.4',
|
|
546
|
-
inputProcessors: [
|
|
547
|
-
new ToolSearchProcessor({
|
|
548
|
-
tools: {
|
|
549
|
-
createIssue: githubTools.createIssue,
|
|
550
|
-
sendEmail: emailTools.send,
|
|
551
|
-
// ... hundreds of tools
|
|
552
|
-
},
|
|
553
|
-
search: { topK: 5, minScore: 0.1 },
|
|
554
|
-
}),
|
|
555
|
-
],
|
|
556
|
-
})
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
The processor gives the agent two meta-tools: `search_tools` to find tools by keyword and `load_tool` to add a tool to the conversation. Loaded tools persist within the thread. See the [ToolSearchProcessor reference](https://mastra.ai/reference/processors/tool-search-processor) for full configuration options.
|
|
439
|
+
For streaming, access metadata from the `finish` chunk payload or the `stream.response` promise.
|
|
560
440
|
|
|
561
|
-
|
|
441
|
+
### Use workflows as processors
|
|
562
442
|
|
|
563
443
|
You can use Mastra workflows as processors to create complex processing pipelines with parallel execution, conditional branching, and error handling:
|
|
564
444
|
|
|
565
445
|
```typescript
|
|
566
446
|
import { createWorkflow, createStep } from '@mastra/core/workflows'
|
|
567
|
-
import {
|
|
447
|
+
import {
|
|
448
|
+
ProcessorStepSchema,
|
|
449
|
+
PromptInjectionDetector,
|
|
450
|
+
PIIDetector,
|
|
451
|
+
ModerationProcessor,
|
|
452
|
+
} from '@mastra/core/processors'
|
|
568
453
|
import { Agent } from '@mastra/core/agent'
|
|
569
454
|
|
|
570
455
|
// Create a workflow that runs multiple checks in parallel
|
|
@@ -573,11 +458,26 @@ const moderationWorkflow = createWorkflow({
|
|
|
573
458
|
inputSchema: ProcessorStepSchema,
|
|
574
459
|
outputSchema: ProcessorStepSchema,
|
|
575
460
|
})
|
|
576
|
-
.then(createStep(new LengthValidator({ maxLength: 10000 })))
|
|
577
461
|
.parallel([
|
|
578
|
-
createStep(
|
|
579
|
-
|
|
462
|
+
createStep(
|
|
463
|
+
new PIIDetector({
|
|
464
|
+
strategy: 'redact',
|
|
465
|
+
}),
|
|
466
|
+
),
|
|
467
|
+
createStep(
|
|
468
|
+
new PromptInjectionDetector({
|
|
469
|
+
strategy: 'block',
|
|
470
|
+
}),
|
|
471
|
+
),
|
|
472
|
+
createStep(
|
|
473
|
+
new ModerationProcessor({
|
|
474
|
+
strategy: 'block',
|
|
475
|
+
}),
|
|
476
|
+
),
|
|
580
477
|
])
|
|
478
|
+
.map(async ({ inputData }) => {
|
|
479
|
+
return inputData['processor:pii-detector']
|
|
480
|
+
})
|
|
581
481
|
.commit()
|
|
582
482
|
|
|
583
483
|
// Use the workflow as an input processor
|
|
@@ -589,14 +489,18 @@ const agent = new Agent({
|
|
|
589
489
|
})
|
|
590
490
|
```
|
|
591
491
|
|
|
492
|
+
After a `.parallel()` step, each branch result is keyed by its processor ID (e.g. `processor:pii-detector`). Use `.map()` to select the branch whose output the next step should receive.
|
|
493
|
+
|
|
494
|
+
If a branch uses a mutating strategy like `redact`, map to that branch so its transformed messages carry forward. If all branches only `block`, any branch works. Pick any one since none of them modify the messages.
|
|
495
|
+
|
|
592
496
|
When an agent is registered with Mastra, processor workflows are automatically registered as workflows, allowing you to view and debug them in the [Studio](https://mastra.ai/docs/getting-started/studio).
|
|
593
497
|
|
|
594
|
-
|
|
498
|
+
### Retry mechanism
|
|
595
499
|
|
|
596
500
|
Processors can request that the LLM retry its response with feedback. This is useful for implementing quality checks, output validation, or iterative refinement:
|
|
597
501
|
|
|
598
502
|
```typescript
|
|
599
|
-
import type { Processor } from '@mastra/core'
|
|
503
|
+
import type { Processor } from '@mastra/core/processors'
|
|
600
504
|
|
|
601
505
|
export class QualityChecker implements Processor {
|
|
602
506
|
id = 'quality-checker'
|
|
@@ -627,14 +531,14 @@ const agent = new Agent({
|
|
|
627
531
|
|
|
628
532
|
The retry mechanism:
|
|
629
533
|
|
|
630
|
-
- Only works in `processOutputStep` and `processInputStep` methods
|
|
534
|
+
- Only works in `processOutputStep()` and `processInputStep()` methods
|
|
631
535
|
- Replays the step with the abort reason added as context for the LLM
|
|
632
536
|
- Tracks retry count via the `retryCount` parameter
|
|
633
537
|
- Respects `maxProcessorRetries` limit on the agent
|
|
634
538
|
|
|
635
539
|
## Related documentation
|
|
636
540
|
|
|
637
|
-
- [Guardrails](https://mastra.ai/docs/agents/guardrails)
|
|
638
|
-
- [Memory Processors](https://mastra.ai/docs/memory/memory-processors)
|
|
639
|
-
- [Processor Interface](https://mastra.ai/reference/processors/processor-interface)
|
|
640
|
-
- [ToolSearchProcessor Reference](https://mastra.ai/reference/processors/tool-search-processor)
|
|
541
|
+
- [Guardrails](https://mastra.ai/docs/agents/guardrails): Security and validation processors
|
|
542
|
+
- [Memory Processors](https://mastra.ai/docs/memory/memory-processors): Memory-specific processors and automatic integration
|
|
543
|
+
- [Processor Interface](https://mastra.ai/reference/processors/processor-interface): Full API reference for processors
|
|
544
|
+
- [ToolSearchProcessor Reference](https://mastra.ai/reference/processors/tool-search-processor): API reference for dynamic tool search
|