@mastra/mcp-docs-server 0.13.11 → 0.13.12-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/changelogs/%40internal%2Fstorage-test-utils.md +19 -19
- package/.docs/organized/changelogs/%40internal%2Ftypes-builder.md +2 -0
- package/.docs/organized/changelogs/%40mastra%2Fchroma.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +42 -42
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fcore.md +45 -45
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +53 -53
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +49 -49
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +49 -49
- package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +54 -54
- package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +20 -20
- package/.docs/organized/changelogs/%40mastra%2Fevals.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Ffirecrawl.md +21 -21
- package/.docs/organized/changelogs/%40mastra%2Flance.md +22 -22
- package/.docs/organized/changelogs/%40mastra%2Flibsql.md +34 -34
- package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +41 -41
- package/.docs/organized/changelogs/%40mastra%2Fmcp.md +33 -33
- package/.docs/organized/changelogs/%40mastra%2Fmemory.md +23 -23
- package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +20 -20
- package/.docs/organized/changelogs/%40mastra%2Fpg.md +37 -37
- package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +49 -49
- package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +21 -21
- package/.docs/organized/changelogs/%40mastra%2Frag.md +20 -20
- package/.docs/organized/changelogs/%40mastra%2Fschema-compat.md +8 -0
- package/.docs/organized/changelogs/%40mastra%2Fserver.md +44 -44
- package/.docs/organized/changelogs/%40mastra%2Fvoice-google-gemini-live.md +14 -0
- package/.docs/organized/changelogs/create-mastra.md +26 -26
- package/.docs/organized/changelogs/mastra.md +63 -63
- package/.docs/organized/code-examples/agent.md +292 -275
- package/.docs/raw/agents/input-processors.mdx +25 -19
- package/.docs/raw/agents/output-processors.mdx +376 -0
- package/.docs/raw/agents/overview.mdx +165 -188
- package/.docs/raw/agents/streaming.mdx +11 -5
- package/.docs/raw/community/contributing-templates.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/amazon-ec2.mdx +9 -9
- package/.docs/raw/deployment/cloud-providers/aws-lambda.mdx +27 -33
- package/.docs/raw/deployment/cloud-providers/azure-app-services.mdx +12 -12
- package/.docs/raw/deployment/cloud-providers/digital-ocean.mdx +17 -17
- package/.docs/raw/getting-started/templates.mdx +1 -1
- package/.docs/raw/rag/vector-databases.mdx +9 -1
- package/.docs/raw/reference/agents/agent.mdx +9 -3
- package/.docs/raw/reference/agents/generate.mdx +80 -3
- package/.docs/raw/reference/agents/getDefaultGenerateOptions.mdx +1 -1
- package/.docs/raw/reference/agents/getDefaultStreamOptions.mdx +1 -1
- package/.docs/raw/reference/agents/getDefaultVNextStreamOptions.mdx +1 -1
- package/.docs/raw/reference/agents/getLLM.mdx +1 -1
- package/.docs/raw/reference/agents/streamVNext.mdx +88 -5
- package/.docs/raw/reference/cli/scorers.mdx +160 -0
- package/.docs/raw/reference/rag/chroma.mdx +158 -17
- package/.docs/raw/reference/templates.mdx +3 -3
- package/.docs/raw/reference/tools/create-tool.mdx +2 -2
- package/.docs/raw/reference/tools/mcp-client.mdx +9 -9
- package/.docs/raw/reference/tools/mcp-server.mdx +5 -5
- package/.docs/raw/reference/workflows/branch.mdx +1 -1
- package/.docs/raw/reference/workflows/create-run.mdx +4 -4
- package/.docs/raw/reference/workflows/execute.mdx +2 -2
- package/.docs/raw/reference/workflows/foreach.mdx +1 -1
- package/.docs/raw/reference/workflows/run-methods/cancel.mdx +58 -0
- package/.docs/raw/reference/workflows/{resume.mdx → run-methods/resume.mdx} +7 -5
- package/.docs/raw/reference/workflows/{start.mdx → run-methods/start.mdx} +5 -5
- package/.docs/raw/reference/workflows/{stream.mdx → run-methods/stream.mdx} +6 -3
- package/.docs/raw/reference/workflows/{streamVNext.mdx → run-methods/streamVNext.mdx} +14 -9
- package/.docs/raw/reference/workflows/{watch.mdx → run-methods/watch.mdx} +12 -12
- package/.docs/raw/reference/workflows/run.mdx +104 -0
- package/.docs/raw/reference/workflows/step.mdx +0 -1
- package/.docs/raw/reference/workflows/workflow.mdx +3 -2
- package/.docs/raw/{reference/workflows → server-db}/snapshots.mdx +2 -2
- package/.docs/raw/voice/overview.mdx +81 -2
- package/.docs/raw/voice/speech-to-speech.mdx +45 -0
- package/.docs/raw/workflows/overview.mdx +11 -4
- package/.docs/raw/workflows-legacy/overview.mdx +8 -8
- package/package.json +4 -4
|
@@ -19,7 +19,7 @@ This processor normalizes Unicode text to ensure consistent formatting and remov
|
|
|
19
19
|
|
|
20
20
|
```typescript copy showLineNumbers {9-11}
|
|
21
21
|
import { Agent } from "@mastra/core/agent";
|
|
22
|
-
import { UnicodeNormalizer } from "@mastra/core/
|
|
22
|
+
import { UnicodeNormalizer } from "@mastra/core/processors";
|
|
23
23
|
import { openai } from "@ai-sdk/openai";
|
|
24
24
|
|
|
25
25
|
const agent = new Agent({
|
|
@@ -41,16 +41,16 @@ Available options:
|
|
|
41
41
|
- `collapseWhitespace`: Collapse multiple spaces/newlines (default: true)
|
|
42
42
|
- `trim`: Remove leading/trailing whitespace (default: true)
|
|
43
43
|
|
|
44
|
-
### `
|
|
44
|
+
### `ModerationProcessor`
|
|
45
45
|
|
|
46
46
|
This processor provides content moderation using an LLM to detect inappropriate content across multiple categories.
|
|
47
47
|
|
|
48
48
|
```typescript copy showLineNumbers {5-13}
|
|
49
|
-
import {
|
|
49
|
+
import { ModerationProcessor } from "@mastra/core/processors";
|
|
50
50
|
|
|
51
51
|
const agent = new Agent({
|
|
52
52
|
inputProcessors: [
|
|
53
|
-
new
|
|
53
|
+
new ModerationProcessor({
|
|
54
54
|
model: openai("gpt-4.1-nano"), // Use a fast, cost-effective model
|
|
55
55
|
threshold: 0.7, // Confidence threshold for flagging
|
|
56
56
|
strategy: 'block', // Block flagged content
|
|
@@ -77,7 +77,7 @@ Strategies available:
|
|
|
77
77
|
This processor detects and prevents prompt injection attacks, jailbreaks, and system manipulation attempts.
|
|
78
78
|
|
|
79
79
|
```typescript copy showLineNumbers {5-12}
|
|
80
|
-
import { PromptInjectionDetector } from "@mastra/core/
|
|
80
|
+
import { PromptInjectionDetector } from "@mastra/core/processors";
|
|
81
81
|
|
|
82
82
|
const agent = new Agent({
|
|
83
83
|
inputProcessors: [
|
|
@@ -110,7 +110,7 @@ Strategies available:
|
|
|
110
110
|
This processor detects and optionally redacts personally identifiable information (PII) from messages.
|
|
111
111
|
|
|
112
112
|
```typescript copy showLineNumbers {5-14}
|
|
113
|
-
import { PIIDetector } from "@mastra/core/
|
|
113
|
+
import { PIIDetector } from "@mastra/core/processors";
|
|
114
114
|
|
|
115
115
|
const agent = new Agent({
|
|
116
116
|
inputProcessors: [
|
|
@@ -148,7 +148,7 @@ Strategies available:
|
|
|
148
148
|
This processor detects the language of incoming messages and can automatically translate them to a target language.
|
|
149
149
|
|
|
150
150
|
```typescript copy showLineNumbers {5-12}
|
|
151
|
-
import { LanguageDetector } from "@mastra/core/
|
|
151
|
+
import { LanguageDetector } from "@mastra/core/processors";
|
|
152
152
|
|
|
153
153
|
const agent = new Agent({
|
|
154
154
|
inputProcessors: [
|
|
@@ -186,10 +186,10 @@ You can chain multiple processors. They execute sequentially in the order they a
|
|
|
186
186
|
import { Agent } from "@mastra/core/agent";
|
|
187
187
|
import {
|
|
188
188
|
UnicodeNormalizer,
|
|
189
|
-
|
|
189
|
+
ModerationProcessor,
|
|
190
190
|
PromptInjectionDetector,
|
|
191
191
|
PIIDetector
|
|
192
|
-
} from "@mastra/core/
|
|
192
|
+
} from "@mastra/core/processors";
|
|
193
193
|
|
|
194
194
|
const secureAgent = new Agent({
|
|
195
195
|
inputProcessors: [
|
|
@@ -198,7 +198,7 @@ const secureAgent = new Agent({
|
|
|
198
198
|
// 2. Check for security threats
|
|
199
199
|
new PromptInjectionDetector({ model: openai("gpt-4.1-nano") }),
|
|
200
200
|
// 3. Moderate content
|
|
201
|
-
new
|
|
201
|
+
new ModerationProcessor({ model: openai("gpt-4.1-nano") }),
|
|
202
202
|
// 4. Handle PII last
|
|
203
203
|
new PIIDetector({ model: openai("gpt-4.1-nano"), strategy: 'redact' }),
|
|
204
204
|
],
|
|
@@ -207,17 +207,17 @@ const secureAgent = new Agent({
|
|
|
207
207
|
|
|
208
208
|
## Creating Custom Processors
|
|
209
209
|
|
|
210
|
-
You can create custom processors by implementing the `
|
|
210
|
+
You can create custom processors by implementing the `Processor` interface. A Processor can be used for input processing when it implements the `processInput` method.
|
|
211
211
|
|
|
212
212
|
```typescript copy showLineNumbers {4-19,23-26}
|
|
213
|
-
import type {
|
|
213
|
+
import type { Processor, MastraMessageV2, TripWire } from "@mastra/core/processors";
|
|
214
214
|
|
|
215
|
-
class MessageLengthLimiter implements
|
|
215
|
+
class MessageLengthLimiter implements Processor {
|
|
216
216
|
readonly name = 'message-length-limiter';
|
|
217
217
|
|
|
218
218
|
constructor(private maxLength: number = 1000) {}
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
processInput({ messages, abort }: {
|
|
221
221
|
messages: MastraMessageV2[];
|
|
222
222
|
abort: (reason?: string) => never
|
|
223
223
|
}): MastraMessageV2[] {
|
|
@@ -260,17 +260,23 @@ When creating custom processors:
|
|
|
260
260
|
|
|
261
261
|
## Integration with Agent Methods
|
|
262
262
|
|
|
263
|
-
Input processors work with
|
|
263
|
+
Input processors work with the `generate()`, `stream()`, and `streamVNext()` methods. The entire processor pipeline completes before the agent begins generating or streaming a response.
|
|
264
264
|
|
|
265
265
|
```typescript copy showLineNumbers
|
|
266
266
|
// Processors run before generate()
|
|
267
267
|
const result = await agent.generate('Hello');
|
|
268
268
|
|
|
269
|
-
// Processors also run before
|
|
270
|
-
const stream = await agent.
|
|
271
|
-
for await (const chunk of stream
|
|
269
|
+
// Processors also run before streamVNext()
|
|
270
|
+
const stream = await agent.streamVNext('Hello');
|
|
271
|
+
for await (const chunk of stream) {
|
|
272
272
|
console.log(chunk);
|
|
273
273
|
}
|
|
274
274
|
```
|
|
275
275
|
|
|
276
|
-
If any processor calls `abort()`, the request terminates immediately and subsequent processors are not executed. The agent returns a 200 response with details (`result.tripwireReason`) about why the request was blocked.
|
|
276
|
+
If any processor calls `abort()`, the request terminates immediately and subsequent processors are not executed. The agent returns a 200 response with details (`result.tripwireReason`) about why the request was blocked.
|
|
277
|
+
|
|
278
|
+
## Output Processors
|
|
279
|
+
|
|
280
|
+
While input processors handle user messages before they reach the language model, **output processors** handle the LLM's responses after generation but before they're returned to the user. This is useful for response validation, content filtering, and safety controls on LLM-generated content.
|
|
281
|
+
|
|
282
|
+
See the [Output Processors documentation](/docs/agents/output-processors) for details on processing LLM responses.
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Output Processors"
|
|
3
|
+
description: "Learn how to use output processors to intercept and modify AI responses before they are returned to users."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Output Processors
|
|
7
|
+
|
|
8
|
+
Output Processors allow you to intercept, modify, validate, or filter AI responses _after_ they are generated by the language model but _before_ they are returned to users. This is useful for implementing response validation, content moderation, response transformation, and safety controls on AI-generated content.
|
|
9
|
+
|
|
10
|
+
Processors operate on the AI's response messages in your conversation thread. They can modify, filter, or validate content, and even abort the response entirely if certain conditions are met.
|
|
11
|
+
|
|
12
|
+
## Built-in Processors
|
|
13
|
+
|
|
14
|
+
Mastra provides several built-in output processors for common use cases:
|
|
15
|
+
|
|
16
|
+
### `ModerationProcessor`
|
|
17
|
+
|
|
18
|
+
This processor provides content moderation using an LLM to detect inappropriate content across multiple categories.
|
|
19
|
+
|
|
20
|
+
```typescript copy showLineNumbers {5-13}
|
|
21
|
+
import { ModerationProcessor } from "@mastra/core/processors";
|
|
22
|
+
|
|
23
|
+
const agent = new Agent({
|
|
24
|
+
outputProcessors: [
|
|
25
|
+
new ModerationProcessor({
|
|
26
|
+
model: openai("gpt-4.1-nano"), // Use a fast, cost-effective model
|
|
27
|
+
threshold: 0.7, // Confidence threshold for flagging
|
|
28
|
+
strategy: 'block', // Block flagged content
|
|
29
|
+
categories: ['hate', 'harassment', 'violence'], // Custom categories
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Available options:
|
|
36
|
+
- `model`: Language model for moderation analysis (required)
|
|
37
|
+
- `categories`: Array of categories to check (default: ['hate','hate/threatening','harassment','harassment/threatening','self-harm','self-harm/intent','self-harm/instructions','sexual','sexual/minors','violence','violence/graphic'])
|
|
38
|
+
- `threshold`: Confidence threshold for flagging (0-1, default: 0.5)
|
|
39
|
+
- `strategy`: Action when content is flagged (default: 'block')
|
|
40
|
+
- `customInstructions`: Custom instructions for the moderation agent
|
|
41
|
+
|
|
42
|
+
Strategies available:
|
|
43
|
+
- `block`: Reject the response with an error (default)
|
|
44
|
+
- `warn`: Log warning but allow content through
|
|
45
|
+
- `filter`: Remove flagged messages but continue processing
|
|
46
|
+
|
|
47
|
+
### `PIIDetector`
|
|
48
|
+
|
|
49
|
+
This processor detects and optionally redacts personally identifiable information (PII) from AI responses.
|
|
50
|
+
|
|
51
|
+
```typescript copy showLineNumbers {5-14}
|
|
52
|
+
import { PIIDetector } from "@mastra/core/processors";
|
|
53
|
+
|
|
54
|
+
const agent = new Agent({
|
|
55
|
+
outputProcessors: [
|
|
56
|
+
new PIIDetector({
|
|
57
|
+
model: openai("gpt-4.1-nano"),
|
|
58
|
+
threshold: 0.6,
|
|
59
|
+
strategy: 'redact', // Automatically redact detected PII
|
|
60
|
+
detectionTypes: ['email', 'phone', 'credit-card', 'ssn', 'api-key', 'crypto-wallet', 'iban'],
|
|
61
|
+
redactionMethod: 'mask', // Preserve format while masking
|
|
62
|
+
preserveFormat: true, // Keep original structure in redacted values
|
|
63
|
+
includeDetections: true, // Log details for compliance auditing
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Available options:
|
|
70
|
+
- `model`: Language model for PII detection (required)
|
|
71
|
+
- `detectionTypes`: Array of PII types to detect (default: ['email', 'phone', 'credit-card', 'ssn', 'api-key', 'ip-address', 'name', 'address', 'date-of-birth', 'url', 'uuid', 'crypto-wallet', 'iban'])
|
|
72
|
+
- `threshold`: Confidence threshold for flagging (0-1, default: 0.6)
|
|
73
|
+
- `strategy`: Action when PII is detected (default: 'block')
|
|
74
|
+
- `redactionMethod`: How to redact PII ('mask', 'hash', 'remove', 'placeholder', default: 'mask')
|
|
75
|
+
- `preserveFormat`: Maintain PII structure during redaction (default: true)
|
|
76
|
+
- `includeDetections`: Include detection details in logs for compliance (default: false)
|
|
77
|
+
- `instructions`: Custom detection instructions for the agent
|
|
78
|
+
|
|
79
|
+
Strategies available:
|
|
80
|
+
- `block`: Reject responses containing PII (default)
|
|
81
|
+
- `warn`: Log warning but allow through
|
|
82
|
+
- `filter`: Remove messages containing PII
|
|
83
|
+
- `redact`: Replace PII with placeholder values
|
|
84
|
+
|
|
85
|
+
### `StructuredOutputProcessor`
|
|
86
|
+
|
|
87
|
+
This processor converts unstructured LLM text responses into structured data using an internal agent. It preserves the original text while adding structured data to the response metadata as well as to result.object.
|
|
88
|
+
|
|
89
|
+
```typescript copy showLineNumbers {5-15}
|
|
90
|
+
import { StructuredOutputProcessor } from "@mastra/core/processors";
|
|
91
|
+
import { z } from "zod";
|
|
92
|
+
|
|
93
|
+
const agent = new Agent({
|
|
94
|
+
outputProcessors: [
|
|
95
|
+
new StructuredOutputProcessor({
|
|
96
|
+
schema: z.object({
|
|
97
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
98
|
+
confidence: z.number().min(0).max(1),
|
|
99
|
+
topics: z.array(z.string()),
|
|
100
|
+
}),
|
|
101
|
+
model: openai("gpt-4o-mini"),
|
|
102
|
+
errorStrategy: 'warn', // Log warnings but continue on errors
|
|
103
|
+
instructions: 'Analyze the sentiment and extract key topics from the response',
|
|
104
|
+
}),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = await agent.generate("Some conversational text")
|
|
109
|
+
|
|
110
|
+
console.log(result.object) // { sentiment: "positive", confidence: 0.6, topics: ["foo", "bar"] }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Available options:
|
|
114
|
+
- `schema`: Zod schema defining the expected structured output (required)
|
|
115
|
+
- `model`: Language model for the internal structuring agent (required)
|
|
116
|
+
- `errorStrategy`: Strategy when parsing or validation fails ('strict' | 'warn' | 'fallback', default: 'strict')
|
|
117
|
+
- `fallbackValue`: Fallback value when errorStrategy is 'fallback'
|
|
118
|
+
- `instructions`: Custom instructions for the structuring agent
|
|
119
|
+
|
|
120
|
+
The structured data is stored in `result.object` and the original text is preserved in `result.text`.
|
|
121
|
+
|
|
122
|
+
### `BatchPartsProcessor`
|
|
123
|
+
|
|
124
|
+
This processor batches multiple stream parts together to reduce the frequency of emissions, useful for reducing network overhead or improving user experience.
|
|
125
|
+
|
|
126
|
+
```typescript copy showLineNumbers {5-12}
|
|
127
|
+
import { BatchPartsProcessor } from "@mastra/core/processors";
|
|
128
|
+
|
|
129
|
+
const agent = new Agent({
|
|
130
|
+
outputProcessors: [
|
|
131
|
+
new BatchPartsProcessor({
|
|
132
|
+
maxBatchSize: 5, // Maximum parts to batch together
|
|
133
|
+
maxWaitTime: 100, // Maximum time to wait before emitting (ms)
|
|
134
|
+
emitOnNonText: true, // Emit immediately on non-text parts
|
|
135
|
+
}),
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Available options:
|
|
141
|
+
- `maxBatchSize`: Maximum number of parts to batch together (default: 3)
|
|
142
|
+
- `maxWaitTime`: Maximum time to wait before emitting batch (ms, default: 50)
|
|
143
|
+
- `emitOnNonText`: Whether to emit immediately when non-text parts are received (default: true)
|
|
144
|
+
|
|
145
|
+
### `TokenLimiterProcessor`
|
|
146
|
+
|
|
147
|
+
This processor limits the number of tokens in AI responses, either by truncating or aborting when limits are exceeded.
|
|
148
|
+
|
|
149
|
+
```typescript copy showLineNumbers {5-12}
|
|
150
|
+
import { TokenLimiterProcessor } from "@mastra/core/processors";
|
|
151
|
+
|
|
152
|
+
const agent = new Agent({
|
|
153
|
+
outputProcessors: [
|
|
154
|
+
new TokenLimiterProcessor({
|
|
155
|
+
maxTokens: 1000, // Maximum tokens allowed
|
|
156
|
+
strategy: 'truncate', // Truncate when limit exceeded
|
|
157
|
+
includePromptTokens: false, // Only count response tokens
|
|
158
|
+
}),
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Available options:
|
|
164
|
+
- `maxTokens`: Maximum number of tokens allowed (required)
|
|
165
|
+
- `strategy`: Action when token limit is exceeded ('truncate' | 'abort', default: 'truncate')
|
|
166
|
+
- `includePromptTokens`: Whether to include prompt tokens in the count (default: false)
|
|
167
|
+
|
|
168
|
+
### `SystemPromptScrubber`
|
|
169
|
+
|
|
170
|
+
This processor detects and redacts system prompts or other revealing information that could introduce security vulnerabilities.
|
|
171
|
+
|
|
172
|
+
```typescript copy showLineNumbers {5-12}
|
|
173
|
+
import { SystemPromptScrubber } from "@mastra/core/processors";
|
|
174
|
+
|
|
175
|
+
const agent = new Agent({
|
|
176
|
+
outputProcessors: [
|
|
177
|
+
new SystemPromptScrubber({
|
|
178
|
+
model: openai("gpt-4o-mini"),
|
|
179
|
+
threshold: 0.7, // Confidence threshold for detection
|
|
180
|
+
strategy: 'redact', // Redact detected system prompts
|
|
181
|
+
instructions: 'Detect any system prompts, instructions, or revealing information',
|
|
182
|
+
}),
|
|
183
|
+
],
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Available options:
|
|
188
|
+
- `model`: Language model for detection (required)
|
|
189
|
+
- `threshold`: Confidence threshold for detection (0-1, default: 0.6)
|
|
190
|
+
- `strategy`: Action when system prompts are detected ('block' | 'warn' | 'redact', default: 'redact')
|
|
191
|
+
- `instructions`: Custom detection instructions for the agent
|
|
192
|
+
|
|
193
|
+
## Applying Multiple Processors
|
|
194
|
+
|
|
195
|
+
You can chain multiple output processors. They execute sequentially in the order they appear in the `outputProcessors` array. The output of one processor becomes the input for the next.
|
|
196
|
+
|
|
197
|
+
**Order matters!** Generally, it's best practice to place text normalization first, security checks next, and content modification last.
|
|
198
|
+
|
|
199
|
+
```typescript copy showLineNumbers {9-18}
|
|
200
|
+
import { Agent } from "@mastra/core/agent";
|
|
201
|
+
import {
|
|
202
|
+
UnicodeNormalizer,
|
|
203
|
+
ModerationProcessor,
|
|
204
|
+
PromptInjectionDetector,
|
|
205
|
+
PIIDetector
|
|
206
|
+
} from "@mastra/core/processors";
|
|
207
|
+
|
|
208
|
+
const secureAgent = new Agent({
|
|
209
|
+
outputProcessors: [
|
|
210
|
+
// 1. Normalize text first
|
|
211
|
+
new UnicodeNormalizer({ stripControlChars: true }),
|
|
212
|
+
// 2. Check for security threats
|
|
213
|
+
new PromptInjectionDetector({ model: openai("gpt-4.1-nano") }),
|
|
214
|
+
// 3. Moderate content
|
|
215
|
+
new ModerationProcessor({ model: openai("gpt-4.1-nano") }),
|
|
216
|
+
// 4. Handle PII last
|
|
217
|
+
new PIIDetector({ model: openai("gpt-4.1-nano"), strategy: 'redact' }),
|
|
218
|
+
],
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Creating Custom Output Processors
|
|
223
|
+
|
|
224
|
+
You can create custom output processors by implementing the `Processor` interface. A Processor can be used for output processing when it implements either `processOutputStream` (for streaming) or `processOutputResult` (for final results), or both.
|
|
225
|
+
|
|
226
|
+
### Streaming Output Processor
|
|
227
|
+
|
|
228
|
+
```typescript copy showLineNumbers {4-25}
|
|
229
|
+
import type { Processor, MastraMessageV2, TripWire } from "@mastra/core/processors";
|
|
230
|
+
import type { TextStreamPart, ObjectStreamPart } from 'ai';
|
|
231
|
+
|
|
232
|
+
class ResponseLengthLimiter implements Processor {
|
|
233
|
+
readonly name = 'response-length-limiter-and-lower-case-results';
|
|
234
|
+
|
|
235
|
+
constructor(private maxLength: number = 1000) {}
|
|
236
|
+
|
|
237
|
+
async processOutputStream({ chunk, streamParts, state, abort }: { // will run on every stream part emitted from the LLM
|
|
238
|
+
chunk: TextStreamPart<any> | ObjectStreamPart<any>;
|
|
239
|
+
streamParts: (TextStreamPart<any> | ObjectStreamPart<any>)[];
|
|
240
|
+
state: Record<string, any>;
|
|
241
|
+
abort: (reason?: string) => never;
|
|
242
|
+
}): Promise<TextStreamPart<any> | ObjectStreamPart<any> | null> {
|
|
243
|
+
// Track cumulative length in state, each processor gets its own state
|
|
244
|
+
if (!state.cumulativeLength) {
|
|
245
|
+
state.cumulativeLength = 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const shouldEmitChunk = chunk?.textDelta?.includes('foo');
|
|
249
|
+
|
|
250
|
+
if (chunk.type === 'text-delta') {
|
|
251
|
+
state.cumulativeLength += chunk.textDelta.length;
|
|
252
|
+
|
|
253
|
+
if (state.cumulativeLength > this.maxLength) {
|
|
254
|
+
abort(`Response too long: ${state.cumulativeLength} characters (max: ${this.maxLength})`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (shouldEmitChunk) {
|
|
259
|
+
return chunk; // Emit the chunk
|
|
260
|
+
} else {
|
|
261
|
+
return null; // Emit nothing
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Final Result Processor
|
|
268
|
+
|
|
269
|
+
```typescript copy showLineNumbers {4-19}
|
|
270
|
+
import type { Processor, MastraMessageV2, TripWire } from "@mastra/core/processors";
|
|
271
|
+
|
|
272
|
+
class ResponseValidator implements Processor {
|
|
273
|
+
readonly name = 'response-validator';
|
|
274
|
+
|
|
275
|
+
constructor(private requiredKeywords: string[] = []) {}
|
|
276
|
+
|
|
277
|
+
processOutputResult({ messages, abort }: {
|
|
278
|
+
messages: MastraMessageV2[];
|
|
279
|
+
abort: (reason?: string) => never
|
|
280
|
+
}): MastraMessageV2[] {
|
|
281
|
+
const responseText = messages
|
|
282
|
+
.map(msg => msg.content.parts
|
|
283
|
+
.filter(part => part.type === 'text')
|
|
284
|
+
.map(part => (part as any).text)
|
|
285
|
+
.join('')
|
|
286
|
+
)
|
|
287
|
+
.join('');
|
|
288
|
+
|
|
289
|
+
// Check for required keywords
|
|
290
|
+
for (const keyword of this.requiredKeywords) {
|
|
291
|
+
if (!responseText.toLowerCase().includes(keyword.toLowerCase())) {
|
|
292
|
+
abort(`Response missing required keyword: ${keyword}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return messages;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
When creating custom output processors:
|
|
302
|
+
- Always return the processed data (chunks or messages)
|
|
303
|
+
- Use `abort(reason)` to terminate processing early. Abort is used to simulate blocking a response. Errors thrown with `abort` will be an instance of TripWire.
|
|
304
|
+
- For streaming processors, return `null` or `undefined` to skip emitting a chunk
|
|
305
|
+
- Keep processors focused on a single responsibility
|
|
306
|
+
- If using an agent inside your processor, use a fast model, limit the size of the response from it as much as possible, and make the system prompt as concise as possible.
|
|
307
|
+
|
|
308
|
+
## Integration with Agent Methods
|
|
309
|
+
|
|
310
|
+
Output processors work with both `generate()` and `streamVNext()` methods. The processor pipeline completes after the agent generates a response but before it's returned to the user.
|
|
311
|
+
|
|
312
|
+
```typescript copy showLineNumbers
|
|
313
|
+
// Processors run after generate() but before returning result
|
|
314
|
+
const result = await agent.generate('Hello');
|
|
315
|
+
console.log(result.text); // Processed text
|
|
316
|
+
console.log(result.object); // Structured data if applicable
|
|
317
|
+
|
|
318
|
+
// Processors also run during streamVNext() for each chunk
|
|
319
|
+
const stream = await agent.streamVNext('Hello');
|
|
320
|
+
for await (const chunk of stream) {
|
|
321
|
+
console.log(chunk); // Processed chunks
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Per-Call Overrides
|
|
326
|
+
|
|
327
|
+
You can override output processors for individual calls:
|
|
328
|
+
|
|
329
|
+
```typescript copy showLineNumbers
|
|
330
|
+
// Override output processors for this specific call
|
|
331
|
+
const result = await agent.generate('Hello', {
|
|
332
|
+
outputProcessors: [
|
|
333
|
+
new ModerationProcessor({ model: openai("gpt-4.1-nano") }),
|
|
334
|
+
],
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Same for streaming
|
|
338
|
+
const stream = await agent.streamVNext('Hello', {
|
|
339
|
+
outputProcessors: [
|
|
340
|
+
new TokenLimiterProcessor({ maxTokens: 500 }),
|
|
341
|
+
],
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Structured Output with Better DX
|
|
346
|
+
|
|
347
|
+
For better developer experience with structured output, you can use the `structuredOutput` option:
|
|
348
|
+
|
|
349
|
+
```typescript copy showLineNumbers
|
|
350
|
+
import { z } from "zod";
|
|
351
|
+
|
|
352
|
+
const result = await agent.generate('Analyze this text', {
|
|
353
|
+
structuredOutput: {
|
|
354
|
+
schema: z.object({
|
|
355
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
356
|
+
confidence: z.number(),
|
|
357
|
+
}),
|
|
358
|
+
model: openai("gpt-4o-mini"),
|
|
359
|
+
errorStrategy: 'warn',
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
console.log(result.text); // Original text
|
|
364
|
+
console.log(result.object); // Typed structured data: { sentiment: 'positive', confidence: 0.8 }
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
If any processor calls `abort()`, the request terminates immediately and subsequent processors are not executed. The agent returns a 200 response with details (`result.tripwireReason`) about why the response was blocked.
|
|
368
|
+
|
|
369
|
+
## Input vs Output Processors
|
|
370
|
+
|
|
371
|
+
- **Input Processors**: Handle user messages before they reach the language model
|
|
372
|
+
- **Output Processors**: Handle LLM responses after generation but before they're returned to the user
|
|
373
|
+
|
|
374
|
+
Use input processors for user input validation and security, and output processors for response validation and safety controls on LLM-generated content.
|
|
375
|
+
|
|
376
|
+
See the [Input Processors documentation](/docs/agents/input-processors) for details on processing user messages.
|