ai-sdk-guardrails 2.0.0 → 4.0.0
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/README.md +598 -721
- package/package.json +30 -24
- package/dist/chunk-HHQ3CIFN.js +0 -12
- package/dist/chunk-LLCOPUS6.js +0 -159
- package/dist/errors-BTTWMQEI.js +0 -24
- package/dist/guardrails/input.cjs +0 -493
- package/dist/guardrails/input.d.cts +0 -36
- package/dist/guardrails/input.d.ts +0 -36
- package/dist/guardrails/input.js +0 -453
- package/dist/guardrails/output.cjs +0 -698
- package/dist/guardrails/output.d.cts +0 -46
- package/dist/guardrails/output.d.ts +0 -46
- package/dist/guardrails/output.js +0 -654
- package/dist/index.cjs +0 -752
- package/dist/index.d.cts +0 -194
- package/dist/index.d.ts +0 -194
- package/dist/index.js +0 -547
- package/dist/types-B9h_0Gyl.d.cts +0 -121
- package/dist/types-B9h_0Gyl.d.ts +0 -121
package/README.md
CHANGED
|
@@ -1,41 +1,53 @@
|
|
|
1
1
|
# AI SDK Guardrails
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Middleware for the Vercel AI SDK that adds safety, quality control, and cost management to your AI applications by intercepting prompts and responses.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[](https://www.npmjs.com/package/ai-sdk-guardrails)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
8
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
Block harmful inputs, filter low-quality outputs, and gain observability, all in just a few lines of code.
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+

|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
## ⚡ TL;DR
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
pnpm add ai@latest ai-sdk-guardrails
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Why Use AI SDK Guardrails?
|
|
19
|
-
|
|
20
|
-
Every AI call consumes resources and carries risk. One inappropriate response can damage your reputation whilst inefficient requests waste valuable API resources. AI SDK Guardrails helps you:
|
|
21
|
-
|
|
22
|
-

|
|
23
|
-
|
|
24
|
-
### ⚡ **Optimize API Usage**
|
|
25
|
-
|
|
26
|
-
Block inefficient requests before they reach your AI model. Validate inputs, enforce length limits, detect spam, and prevent unnecessary calls that would have failed anyway.
|
|
11
|
+
Quickly add input and output validation to any AI SDK-compatible model.
|
|
27
12
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
import { openai } from '@ai-sdk/openai';
|
|
15
|
+
import { generateText } from 'ai';
|
|
16
|
+
import {
|
|
17
|
+
wrapWithGuardrails,
|
|
18
|
+
defineInputGuardrail,
|
|
19
|
+
defineOutputGuardrail,
|
|
20
|
+
} from 'ai-sdk-guardrails';
|
|
31
21
|
|
|
32
|
-
|
|
22
|
+
// 1. Define your guardrails
|
|
23
|
+
const inputGuard = defineInputGuardrail({
|
|
24
|
+
name: 'length-check',
|
|
25
|
+
execute: async ({ prompt }) =>
|
|
26
|
+
prompt.length > 100
|
|
27
|
+
? { tripwireTriggered: true, message: 'Input too long' }
|
|
28
|
+
: { tripwireTriggered: false },
|
|
29
|
+
});
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
const outputGuard = defineOutputGuardrail({
|
|
32
|
+
name: 'quality-check',
|
|
33
|
+
execute: async ({ result }) =>
|
|
34
|
+
result.text.length < 10
|
|
35
|
+
? { tripwireTriggered: true, message: 'Response too short' }
|
|
36
|
+
: { tripwireTriggered: false },
|
|
37
|
+
});
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
// 2. Wrap your model
|
|
40
|
+
const guardedModel = wrapWithGuardrails(openai('gpt-4o'), {
|
|
41
|
+
inputGuardrails: [inputGuard],
|
|
42
|
+
outputGuardrails: [outputGuard],
|
|
43
|
+
});
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
// 3. Use it! Guardrails will run automatically.
|
|
46
|
+
const { text } = await generateText({
|
|
47
|
+
model: guardedModel,
|
|
48
|
+
prompt: 'A prompt that is definitely not too long.',
|
|
49
|
+
});
|
|
50
|
+
```
|
|
39
51
|
|
|
40
52
|
## How It Works
|
|
41
53
|
|
|
@@ -69,44 +81,75 @@ flowchart LR
|
|
|
69
81
|
|
|
70
82
|
That's it! Input guardrails optimize resource usage by stopping inefficient requests. Output guardrails ensure quality by filtering responses.
|
|
71
83
|
|
|
72
|
-
## Installation
|
|
84
|
+
## 📦 Installation
|
|
73
85
|
|
|
74
86
|
```bash
|
|
75
87
|
npm install ai-sdk-guardrails
|
|
88
|
+
|
|
76
89
|
# or
|
|
77
|
-
|
|
78
|
-
# or
|
|
90
|
+
|
|
79
91
|
yarn add ai-sdk-guardrails
|
|
92
|
+
|
|
93
|
+
# or
|
|
94
|
+
|
|
95
|
+
pnpm add ai-sdk-guardrails
|
|
80
96
|
```
|
|
81
97
|
|
|
82
|
-
##
|
|
98
|
+
## 🔄 Migration Guide
|
|
99
|
+
|
|
100
|
+
For breaking changes from v3 to v4 (including the new analytics-rich callbacks), see [v3-v4-MIGRATION.md](./v3-v4-MIGRATION.md).
|
|
101
|
+
|
|
102
|
+
## 🚀 Quick Start
|
|
83
103
|
|
|
84
104
|
Add smart validation to your AI applications in just 3 steps:
|
|
85
105
|
|
|
86
106
|
### 1. Prevent Unnecessary AI Calls
|
|
87
107
|
|
|
88
108
|
```typescript
|
|
89
|
-
import { generateText
|
|
109
|
+
import { generateText } from 'ai';
|
|
90
110
|
import { openai } from '@ai-sdk/openai';
|
|
91
|
-
import {
|
|
92
|
-
|
|
111
|
+
import {
|
|
112
|
+
wrapWithInputGuardrails,
|
|
113
|
+
defineInputGuardrail,
|
|
114
|
+
} from 'ai-sdk-guardrails';
|
|
115
|
+
import { extractTextContent } from 'ai-sdk-guardrails/guardrails/input';
|
|
93
116
|
|
|
94
117
|
// Block inefficient requests before calling the AI model
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
const lengthGuard = defineInputGuardrail({
|
|
119
|
+
name: 'blocked-keywords',
|
|
120
|
+
execute: async (context) => {
|
|
121
|
+
const { prompt } = extractTextContent(context);
|
|
122
|
+
const blockedWords = ['spam', 'test', 'hello'];
|
|
123
|
+
|
|
124
|
+
const foundWord = blockedWords.find((word) =>
|
|
125
|
+
prompt.toLowerCase().includes(word.toLowerCase()),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (foundWord) {
|
|
129
|
+
return {
|
|
130
|
+
tripwireTriggered: true,
|
|
131
|
+
message: `Blocked keyword detected: ${foundWord}`,
|
|
132
|
+
severity: 'medium',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return { tripwireTriggered: false };
|
|
137
|
+
},
|
|
102
138
|
});
|
|
103
139
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
model: optimizedModel,
|
|
107
|
-
prompt: 'hello', // ❌ Blocked - prevents unnecessary API call
|
|
140
|
+
const optimizedModel = wrapWithInputGuardrails(openai('gpt-4'), {
|
|
141
|
+
inputGuardrails: [lengthGuard],
|
|
108
142
|
});
|
|
109
|
-
|
|
143
|
+
|
|
144
|
+
// This would normally waste an API call for a useless response
|
|
145
|
+
try {
|
|
146
|
+
const result = await generateText({
|
|
147
|
+
model: optimizedModel,
|
|
148
|
+
prompt: 'hello', // ❌ Blocked - prevents unnecessary API call
|
|
149
|
+
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.log('Blocked request, saved money!');
|
|
152
|
+
}
|
|
110
153
|
|
|
111
154
|
// This generates valuable content
|
|
112
155
|
const goodResult = await generateText({
|
|
@@ -118,25 +161,53 @@ const goodResult = await generateText({
|
|
|
118
161
|
### 2. Ensure Quality Output
|
|
119
162
|
|
|
120
163
|
```typescript
|
|
121
|
-
import {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
164
|
+
import {
|
|
165
|
+
wrapWithOutputGuardrails,
|
|
166
|
+
defineOutputGuardrail,
|
|
167
|
+
} from 'ai-sdk-guardrails';
|
|
168
|
+
import { extractContent } from 'ai-sdk-guardrails/guardrails/output';
|
|
169
|
+
|
|
170
|
+
const qualityGuard = defineOutputGuardrail({
|
|
171
|
+
name: 'sensitive-info-detector',
|
|
172
|
+
execute: async (context) => {
|
|
173
|
+
const { text } = extractContent(context.result);
|
|
174
|
+
|
|
175
|
+
// Simple sensitive info patterns
|
|
176
|
+
const sensitivePatterns = [
|
|
177
|
+
/\b\d{3}-\d{2}-\d{4}\b/, // SSN
|
|
178
|
+
/\b[\w\.-]+@[\w\.-]+\.\w+\b/, // Email
|
|
179
|
+
/\b\d{3}-\d{3}-\d{4}\b/, // Phone
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
const foundPattern = sensitivePatterns.find((pattern) =>
|
|
183
|
+
pattern.test(text),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (foundPattern) {
|
|
187
|
+
return {
|
|
188
|
+
tripwireTriggered: true,
|
|
189
|
+
message: 'Sensitive information detected in response',
|
|
190
|
+
severity: 'high',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return { tripwireTriggered: false };
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const qualityModel = wrapWithOutputGuardrails(openai('gpt-4'), {
|
|
199
|
+
outputGuardrails: [qualityGuard],
|
|
200
|
+
onOutputBlocked: (executionSummary) => {
|
|
201
|
+
console.log(
|
|
202
|
+
'Prevented sensitive data leak:',
|
|
203
|
+
executionSummary.blockedResults[0]?.message,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Access comprehensive analytics (New in v4.0.0)
|
|
207
|
+
console.log(
|
|
208
|
+
`Blocked ${executionSummary.stats.blocked} of ${executionSummary.guardrailsExecuted} guardrails`,
|
|
209
|
+
);
|
|
210
|
+
},
|
|
140
211
|
});
|
|
141
212
|
|
|
142
213
|
const result = await generateText({
|
|
@@ -144,388 +215,305 @@ const result = await generateText({
|
|
|
144
215
|
prompt: 'Create a user profile example',
|
|
145
216
|
});
|
|
146
217
|
// Automatically blocks responses containing emails, phone numbers, or SSNs
|
|
147
|
-
// Prevents: "Here's a profile: john.doe@email.com, (555) 123-4567, SSN: 123-45-6789"
|
|
148
|
-
// Returns: "Here's a profile: [contact information], [phone number], [SSN removed]"
|
|
149
218
|
```
|
|
150
219
|
|
|
151
220
|
### 3. Custom Business Logic
|
|
152
221
|
|
|
153
222
|
```typescript
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
execute: async (context) => {
|
|
161
|
-
const { prompt } = extractTextContent(context);
|
|
162
|
-
|
|
163
|
-
if (prompt.includes('solve this equation') || prompt.includes('homework')) {
|
|
223
|
+
const businessHoursGuard = defineInputGuardrail({
|
|
224
|
+
name: 'business-hours-only',
|
|
225
|
+
execute: async () => {
|
|
226
|
+
const hour = new Date().getUTCHours();
|
|
227
|
+
// Only allow requests between 9 AM and 5 PM UTC
|
|
228
|
+
if (hour < 9 || hour > 17) {
|
|
164
229
|
return {
|
|
165
230
|
tripwireTriggered: true,
|
|
166
|
-
message:
|
|
167
|
-
|
|
231
|
+
message:
|
|
232
|
+
'Requests are only permitted during business hours (9:00-17:00 UTC).',
|
|
233
|
+
severity: 'low',
|
|
168
234
|
};
|
|
169
235
|
}
|
|
170
|
-
|
|
171
236
|
return { tripwireTriggered: false };
|
|
172
237
|
},
|
|
173
238
|
});
|
|
174
239
|
|
|
175
|
-
const smartEducationModel =
|
|
176
|
-
|
|
177
|
-
middleware: [
|
|
178
|
-
createInputGuardrailsMiddleware({
|
|
179
|
-
inputGuardrails: [homeworkDetector],
|
|
180
|
-
}),
|
|
181
|
-
],
|
|
240
|
+
const smartEducationModel = wrapWithInputGuardrails(openai('gpt-4'), {
|
|
241
|
+
inputGuardrails: [businessHoursGuard],
|
|
182
242
|
});
|
|
183
243
|
```
|
|
184
244
|
|
|
185
|
-
|
|
245
|
+
### 4. Type-Safe Metadata (TypeScript)
|
|
186
246
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
Build intelligent resource management by combining multiple validation layers:
|
|
247
|
+
The library automatically infers metadata types from your guardrail definitions - no manual type annotations needed!
|
|
190
248
|
|
|
191
249
|
```typescript
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
execute: async (params) => {
|
|
198
|
-
const { prompt } = extractTextContent(params);
|
|
199
|
-
if (typeof prompt === 'string') {
|
|
200
|
-
// Block extremely short requests that waste resources
|
|
201
|
-
if (prompt.trim().length < 10) {
|
|
202
|
-
return {
|
|
203
|
-
tripwireTriggered: true,
|
|
204
|
-
message: 'Request too short - inefficient API usage',
|
|
205
|
-
severity: 'medium',
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
// Block extremely long requests that often hit limits anyway
|
|
209
|
-
if (prompt.length > 8000) {
|
|
210
|
-
return {
|
|
211
|
-
tripwireTriggered: true,
|
|
212
|
-
message: 'Request too long - would likely hit token limits',
|
|
213
|
-
severity: 'medium',
|
|
214
|
-
suggestion: 'Break into smaller, focused requests',
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return { tripwireTriggered: false };
|
|
219
|
-
},
|
|
220
|
-
}),
|
|
221
|
-
|
|
222
|
-
defineInputGuardrail({
|
|
223
|
-
name: 'spam-detector',
|
|
224
|
-
description: 'Blocks repetitive or low-value requests',
|
|
225
|
-
execute: async (params) => {
|
|
226
|
-
const { prompt } = extractTextContent(params);
|
|
227
|
-
|
|
228
|
-
// Detect repetitive patterns that waste money
|
|
229
|
-
const spamPatterns = [
|
|
230
|
-
/^(.)\1{10,}$/, // Repeated characters
|
|
231
|
-
/^(test|hello|hi|hey)$/i, // Common spam words
|
|
232
|
-
/(.{1,20})\1{3,}/g, // Repetitive phrases
|
|
233
|
-
];
|
|
234
|
-
|
|
235
|
-
if (
|
|
236
|
-
typeof prompt === 'string' &&
|
|
237
|
-
spamPatterns.some((pattern) => pattern.test(prompt))
|
|
238
|
-
) {
|
|
239
|
-
return {
|
|
240
|
-
tripwireTriggered: true,
|
|
241
|
-
message:
|
|
242
|
-
'Spam-like content blocked - preventing unnecessary API calls',
|
|
243
|
-
severity: 'high',
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
return { tripwireTriggered: false };
|
|
247
|
-
},
|
|
248
|
-
}),
|
|
249
|
-
];
|
|
250
|
-
|
|
251
|
-
// Layer 2: Quality assurance - ensure responses are useful
|
|
252
|
-
const qualityAssuranceLayer = [
|
|
253
|
-
defineOutputGuardrail({
|
|
254
|
-
name: 'response-value-checker',
|
|
255
|
-
description: 'Ensures responses provide actual value',
|
|
256
|
-
execute: async (context) => {
|
|
257
|
-
const { text } = extractContent(context.result);
|
|
258
|
-
|
|
259
|
-
// Check for low-value responses that waste resources
|
|
260
|
-
const lowValueIndicators = [
|
|
261
|
-
text.length < 20, // Too short to be useful
|
|
262
|
-
/^(I don't know|I cannot|Sorry, I can't)/.test(text), // Refusal without help
|
|
263
|
-
text.split(' ').length < 5, // Minimal effort response
|
|
264
|
-
];
|
|
265
|
-
|
|
266
|
-
if (
|
|
267
|
-
lowValueIndicators.some((indicator) => indicator === true || indicator)
|
|
268
|
-
) {
|
|
269
|
-
return {
|
|
270
|
-
tripwireTriggered: true,
|
|
271
|
-
message: 'Low-value response detected - inefficient use of resources',
|
|
272
|
-
severity: 'medium',
|
|
273
|
-
suggestion: 'Rephrase request for more specific, actionable help',
|
|
274
|
-
};
|
|
275
|
-
}
|
|
250
|
+
// Define metadata interface for your guardrail
|
|
251
|
+
interface PIIMetadata extends Record<string, unknown> {
|
|
252
|
+
detectedTypes: Array<{ type: string; description: string }>;
|
|
253
|
+
count: number;
|
|
254
|
+
}
|
|
276
255
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
throwOnBlocked: true, // Stop wasteful requests immediately
|
|
289
|
-
}),
|
|
290
|
-
|
|
291
|
-
createOutputGuardrailsMiddleware({
|
|
292
|
-
outputGuardrails: qualityAssuranceLayer,
|
|
293
|
-
throwOnBlocked: false, // Log quality issues but don't break flow
|
|
294
|
-
onOutputBlocked: (results) => {
|
|
295
|
-
// Track quality metrics for optimization
|
|
296
|
-
console.log(
|
|
297
|
-
'Quality issue detected - optimizing for next time:',
|
|
298
|
-
results[0]?.message,
|
|
299
|
-
);
|
|
256
|
+
// Create guardrail with typed metadata
|
|
257
|
+
const piiDetectionGuardrail = defineInputGuardrail({
|
|
258
|
+
name: 'pii-detection',
|
|
259
|
+
execute: async (context) => {
|
|
260
|
+
const { prompt } = extractTextContent(context);
|
|
261
|
+
|
|
262
|
+
const patterns = [
|
|
263
|
+
{
|
|
264
|
+
name: 'SSN',
|
|
265
|
+
regex: /\b\d{3}-\d{2}-\d{4}\b/,
|
|
266
|
+
description: 'Social Security Number',
|
|
300
267
|
},
|
|
301
|
-
|
|
302
|
-
|
|
268
|
+
{
|
|
269
|
+
name: 'Email',
|
|
270
|
+
regex: /\b[\w\.-]+@[\w\.-]+\.\w+\b/,
|
|
271
|
+
description: 'Email address',
|
|
272
|
+
},
|
|
273
|
+
];
|
|
274
|
+
|
|
275
|
+
const detected = patterns.filter((p) => p.regex.test(prompt));
|
|
276
|
+
|
|
277
|
+
if (detected.length > 0) {
|
|
278
|
+
// TypeScript knows this metadata matches PIIMetadata
|
|
279
|
+
const metadata: PIIMetadata = {
|
|
280
|
+
detectedTypes: detected.map((p) => ({
|
|
281
|
+
type: p.name,
|
|
282
|
+
description: p.description,
|
|
283
|
+
})),
|
|
284
|
+
count: detected.length,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
tripwireTriggered: true,
|
|
289
|
+
message: `PII detected: ${detected.map((p) => p.name).join(', ')}`,
|
|
290
|
+
severity: 'high',
|
|
291
|
+
metadata, // Type is automatically inferred!
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return { tripwireTriggered: false };
|
|
296
|
+
},
|
|
303
297
|
});
|
|
304
298
|
|
|
305
|
-
//
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
299
|
+
// Use the guardrail - types flow through automatically!
|
|
300
|
+
const protectedModel = wrapWithInputGuardrails(model, [piiDetectionGuardrail], {
|
|
301
|
+
onInputBlocked: (summary) => {
|
|
302
|
+
// TypeScript knows the metadata type - no casting needed!
|
|
303
|
+
const metadata = summary.blockedResults[0]?.metadata;
|
|
304
|
+
if (metadata?.detectedTypes) {
|
|
305
|
+
// Full type safety and autocomplete for metadata.detectedTypes
|
|
306
|
+
for (const type of metadata.detectedTypes) {
|
|
307
|
+
console.log(`Detected: ${type.type} - ${type.description}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
316
310
|
},
|
|
317
311
|
});
|
|
318
312
|
```
|
|
319
313
|
|
|
320
|
-
|
|
314
|
+
**That's it!** Your AI application now optimizes resource usage, ensures quality, prevents inappropriate responses, and provides full type safety automatically.
|
|
315
|
+
|
|
316
|
+
## ✨ Features
|
|
317
|
+
|
|
318
|
+
- 🛡️ **Input & Output Guardrails**: Enforce custom safety, compliance, and quality policies on both prompts and LLM responses.
|
|
319
|
+
- 💰 **Cost Control**: Block invalid or wasteful prompts before they are sent to your LLM provider, saving you money.
|
|
320
|
+
- 🎯 **Quality Improvement**: Automatically filter, flag, or retry low-quality or irrelevant model outputs.
|
|
321
|
+
- 🔒 **Security Protection**: Built-in defenses against prompt injection, jailbreak attempts, PII leakage, secret exposure, and tool call validation.
|
|
322
|
+
- 🏛️ **Compliance & Governance**: Enforce regulatory guidelines and business rules for enterprise applications with jurisdiction-specific compliance.
|
|
323
|
+
- 🔄 **Streaming Support**: Works seamlessly with both streaming (streamText) and standard (generateText) API responses with real-time content monitoring.
|
|
324
|
+
- 📊 **Observability Hooks**: Built-in callbacks (onInputBlocked, onOutputBlocked, etc.) for logging and monitoring with comprehensive execution analytics.
|
|
325
|
+
- ⚙️ **Configurable Execution**: Run guardrails in parallel or sequentially and set custom timeouts.
|
|
326
|
+
- 🚀 **AI SDK Native**: Designed from the ground up to integrate cleanly with AI SDK middleware patterns.
|
|
327
|
+
- 🧠 **AI-Powered Verification**: LLM-as-judge capabilities for hallucination detection and quality assessment.
|
|
328
|
+
- 🌍 **Global Compliance**: Support for multiple jurisdictions (US, EU, UK, CA, AU, JP, CN, IN) with region-specific policies.
|
|
329
|
+
- 📝 **Content Protection**: Copyright and IP protection with originality scoring and verbatim passage detection.
|
|
330
|
+
- 🔐 **Data Integrity**: Comprehensive table validation, SQL code safety, and schema enforcement.
|
|
331
|
+
- 🌐 **Network Security**: Domain allowlisting, URL sanitization, and external access controls.
|
|
332
|
+
- 🔒 **Privacy & Memory**: PII redaction, memory minimization, and secure logging practices.
|
|
333
|
+
- 🛡️ **Safety & Escalation**: Toxicity de-escalation, human review workflows, and streaming early termination.
|
|
334
|
+
|
|
335
|
+
## 📚 API Overview
|
|
336
|
+
|
|
337
|
+
| Function | Description |
|
|
338
|
+
| ---------------------------- | ----------------------------------------------------------------------------- |
|
|
339
|
+
| `defineInputGuardrail()` | Creates a guardrail to validate, inspect, or block prompts. |
|
|
340
|
+
| `defineOutputGuardrail()` | Creates a guardrail to validate, filter, or re-route LLM outputs. |
|
|
341
|
+
| `wrapWithGuardrails()` | ⭐ **Recommended** - The easiest way to add both input and output guardrails. |
|
|
342
|
+
| `wrapWithInputGuardrails()` | Attaches input-only guardrails to a model. |
|
|
343
|
+
| `wrapWithOutputGuardrails()` | Attaches output-only guardrails to a model. |
|
|
344
|
+
| `isGuardrailsError()`, etc. | Error handling utilities and structured error types. |
|
|
345
|
+
|
|
346
|
+
## 🧠 Design Philosophy
|
|
347
|
+
|
|
348
|
+
- ✅ **Helper-First**: Simple, chainable utility functions provide a great developer experience for fast adoption.
|
|
349
|
+
- 🧩 **Composable**: Multiple guardrails can be chained together and will run in your specified order (or in parallel).
|
|
350
|
+
- 🧾 **Type-Safe**: Full TypeScript support with automatic type inference for guardrail metadata - no manual type annotations needed!
|
|
351
|
+
- 🧪 **Sensible Defaults**: Get started quickly with zero-config default behaviors that can be easily overridden.
|
|
321
352
|
|
|
322
|
-
|
|
353
|
+
## Architecture Overview
|
|
323
354
|
|
|
324
|
-
|
|
355
|
+
The library leverages the Vercel AI SDK's middleware architecture to provide composable guardrails that integrate seamlessly with your existing AI applications:
|
|
325
356
|
|
|
326
357
|
```mermaid
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
D -->|✅ Approved| F[AI SDK Core]
|
|
333
|
-
F --> G[AI Model Call]
|
|
334
|
-
G --> H[Output Middleware]
|
|
335
|
-
H --> I{Quality<br/>Check?}
|
|
336
|
-
I -->|⚠️ Issues| J[Filtered Response<br/>+ Callbacks]
|
|
337
|
-
I -->|✅ Clean| K[Final Response]
|
|
338
|
-
|
|
339
|
-
style C fill:#e1f5fe
|
|
340
|
-
style H fill:#f3e5f5
|
|
341
|
-
style E fill:#ffebee
|
|
342
|
-
style J fill:#fff3e0
|
|
343
|
-
```
|
|
358
|
+
graph TB
|
|
359
|
+
subgraph "Your Application"
|
|
360
|
+
App[Your App Code]
|
|
361
|
+
Config[Guardrail Configuration]
|
|
362
|
+
end
|
|
344
363
|
|
|
345
|
-
|
|
364
|
+
subgraph "AI SDK Guardrails Middleware"
|
|
365
|
+
InputMW[Input Guardrails Middleware]
|
|
366
|
+
OutputMW[Output Guardrails Middleware]
|
|
346
367
|
|
|
347
|
-
|
|
348
|
-
|
|
368
|
+
subgraph "Input Guardrails Layer"
|
|
369
|
+
Length[Length Validation]
|
|
370
|
+
Spam[Spam Detection]
|
|
371
|
+
PII[PII Detection]
|
|
372
|
+
Business[Business Rules]
|
|
373
|
+
Custom1[Custom Guards]
|
|
374
|
+
end
|
|
349
375
|
|
|
350
|
-
|
|
376
|
+
subgraph "Output Guardrails Layer"
|
|
377
|
+
Quality[Quality Assurance]
|
|
378
|
+
Sensitive[Sensitive Info Filter]
|
|
379
|
+
Professional[Professional Tone]
|
|
380
|
+
Factual[Factual Validation]
|
|
381
|
+
Custom2[Custom Guards]
|
|
382
|
+
end
|
|
383
|
+
end
|
|
351
384
|
|
|
352
|
-
|
|
385
|
+
subgraph "AI SDK Core"
|
|
386
|
+
Wrapper[wrapLanguageModel]
|
|
387
|
+
Generator[generateText/Object/Stream]
|
|
388
|
+
end
|
|
353
389
|
|
|
354
|
-
|
|
390
|
+
subgraph "External Services"
|
|
391
|
+
AI[AI Model Provider]
|
|
392
|
+
Log[Logging & Telemetry]
|
|
393
|
+
end
|
|
355
394
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
// Option 1: Handle via callbacks (recommended for production)
|
|
364
|
-
throwOnBlocked: false,
|
|
365
|
-
onInputBlocked: (results) => {
|
|
366
|
-
results.forEach((result) => {
|
|
367
|
-
console.warn(
|
|
368
|
-
`Blocked by ${result.context?.guardrailName}: ${result.message}`,
|
|
369
|
-
);
|
|
370
|
-
|
|
371
|
-
// Log to monitoring system
|
|
372
|
-
analytics.track('guardrail_blocked', {
|
|
373
|
-
guardrail: result.context?.guardrailName,
|
|
374
|
-
severity: result.severity,
|
|
375
|
-
suggestion: result.suggestion,
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// Notify user with helpful message
|
|
379
|
-
notifyUser(
|
|
380
|
-
result.suggestion || 'Please refine your request and try again',
|
|
381
|
-
);
|
|
382
|
-
});
|
|
383
|
-
},
|
|
384
|
-
}),
|
|
385
|
-
],
|
|
386
|
-
});
|
|
395
|
+
App --> Config
|
|
396
|
+
Config --> InputMW
|
|
397
|
+
InputMW --> Length
|
|
398
|
+
InputMW --> Spam
|
|
399
|
+
InputMW --> PII
|
|
400
|
+
InputMW --> Business
|
|
401
|
+
InputMW --> Custom1
|
|
387
402
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
model: protectedModel,
|
|
391
|
-
prompt: userInput,
|
|
392
|
-
});
|
|
403
|
+
InputMW -->|Valid Request| Wrapper
|
|
404
|
+
InputMW -->|Blocked Request| Log
|
|
393
405
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
} else {
|
|
398
|
-
// Request was blocked but handled gracefully
|
|
399
|
-
return "I'm sorry, I couldn't process that request. Please try rephrasing.";
|
|
400
|
-
}
|
|
401
|
-
} catch (error) {
|
|
402
|
-
// Handle any unexpected errors
|
|
403
|
-
console.error('Unexpected error:', error);
|
|
404
|
-
return "I'm experiencing technical difficulties. Please try again later.";
|
|
405
|
-
}
|
|
406
|
-
```
|
|
406
|
+
Wrapper --> Generator
|
|
407
|
+
Generator --> AI
|
|
408
|
+
AI --> OutputMW
|
|
407
409
|
|
|
408
|
-
|
|
410
|
+
OutputMW --> Quality
|
|
411
|
+
OutputMW --> Sensitive
|
|
412
|
+
OutputMW --> Professional
|
|
413
|
+
OutputMW --> Factual
|
|
414
|
+
OutputMW --> Custom2
|
|
409
415
|
|
|
410
|
-
|
|
416
|
+
OutputMW -->|Clean Response| App
|
|
417
|
+
OutputMW -->|Quality Issues| Log
|
|
411
418
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
createOutputGuardrailsMiddleware({
|
|
417
|
-
outputGuardrails: [sensitiveInfoDetector, professionalToneChecker],
|
|
418
|
-
throwOnBlocked: false, // Usually false for output guardrails
|
|
419
|
-
onOutputBlocked: (results) => {
|
|
420
|
-
results.forEach((result) => {
|
|
421
|
-
// Log quality issues for continuous improvement
|
|
422
|
-
console.log(`Quality issue: ${result.message}`);
|
|
423
|
-
|
|
424
|
-
// Track metrics
|
|
425
|
-
metrics.increment('output_filtered', {
|
|
426
|
-
guardrail: result.context?.guardrailName,
|
|
427
|
-
severity: result.severity,
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
// Optionally regenerate with stronger guidance
|
|
431
|
-
if (result.severity === 'high') {
|
|
432
|
-
scheduleRegeneration(result.suggestion);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
},
|
|
436
|
-
}),
|
|
437
|
-
],
|
|
438
|
-
});
|
|
419
|
+
style InputMW fill:#e1f5fe
|
|
420
|
+
style OutputMW fill:#f3e5f5
|
|
421
|
+
style AI fill:#fff3e0
|
|
422
|
+
style App fill:#e8f5e8
|
|
439
423
|
```
|
|
440
424
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
Transform technical guardrail messages into user-friendly guidance:
|
|
444
|
-
|
|
445
|
-
```typescript
|
|
446
|
-
function createUserFriendlyMessage(guardrailResult: GuardrailResult): string {
|
|
447
|
-
const guardrailName = guardrailResult.context?.guardrailName;
|
|
448
|
-
|
|
449
|
-
switch (guardrailName) {
|
|
450
|
-
case 'content-length-limit':
|
|
451
|
-
return 'Your message is too long. Please keep it under 500 characters for the best response.';
|
|
425
|
+
## 🍳 Recipes & Use Cases
|
|
452
426
|
|
|
453
|
-
|
|
454
|
-
return "I can't help with that topic. Try asking about something else I can assist with.";
|
|
427
|
+
Guardrails can enforce any custom logic. Here are a few common patterns.
|
|
455
428
|
|
|
456
|
-
|
|
457
|
-
return "You're sending requests too quickly. Please wait a moment before trying again.";
|
|
429
|
+
### Rate Limiting
|
|
458
430
|
|
|
459
|
-
|
|
460
|
-
return "I'm designed to help you understand concepts, not solve homework directly. Ask me to explain the topic instead!";
|
|
431
|
+
Pass a userId in the metadata of your generateText call to enforce per-user rate limits.
|
|
461
432
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
433
|
+
```typescript
|
|
434
|
+
const rateLimitGuard = defineInputGuardrail({
|
|
435
|
+
name: 'user-rate-limit',
|
|
436
|
+
execute: async ({ metadata }) => {
|
|
437
|
+
const userId = metadata?.userId ?? 'anonymous';
|
|
438
|
+
const allowed = await checkRateLimit(userId); // Your rate-limiting logic
|
|
439
|
+
|
|
440
|
+
return allowed
|
|
441
|
+
? { tripwireTriggered: false }
|
|
442
|
+
: {
|
|
443
|
+
tripwireTriggered: true,
|
|
444
|
+
message: `Rate limit exceeded for user: ${userId}`,
|
|
445
|
+
};
|
|
446
|
+
},
|
|
447
|
+
});
|
|
469
448
|
```
|
|
470
449
|
|
|
471
|
-
###
|
|
472
|
-
|
|
473
|
-
1. **Use callbacks over exceptions** for better user experience
|
|
474
|
-
2. **Log guardrail events** for monitoring and improvement
|
|
475
|
-
3. **Provide helpful suggestions** rather than just blocking
|
|
476
|
-
4. **Track metrics** to understand usage patterns
|
|
477
|
-
5. **Implement fallback responses** for graceful degradation
|
|
478
|
-
6. **Consider retry logic** with exponential backoff for rate limits
|
|
450
|
+
### LLM-as-Judge for Quality Scoring
|
|
479
451
|
|
|
480
|
-
|
|
452
|
+
Use a cheaper, faster model to "judge" the output of a more powerful one.
|
|
481
453
|
|
|
482
|
-
|
|
454
|
+
```typescript
|
|
455
|
+
const qualityJudge = defineOutputGuardrail({
|
|
456
|
+
name: 'llm-quality-judge',
|
|
457
|
+
execute: async ({ result }) => {
|
|
458
|
+
// Use a cheap model to score the primary model's output
|
|
459
|
+
const judgement = await generateText({
|
|
460
|
+
model: openai('gpt-3.5-turbo'),
|
|
461
|
+
prompt: `Is the following response helpful and safe? Answer YES or NO. \n\nResponse: "${result.text}"`,
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const isSafe = judgement.text.includes('YES');
|
|
465
|
+
return isSafe
|
|
466
|
+
? { tripwireTriggered: false }
|
|
467
|
+
: {
|
|
468
|
+
tripwireTriggered: true,
|
|
469
|
+
message: `Output failed LLM-as-judge quality check.`,
|
|
470
|
+
metadata: { originalText: result.text },
|
|
471
|
+
};
|
|
472
|
+
},
|
|
473
|
+
});
|
|
474
|
+
```
|
|
483
475
|
|
|
484
|
-
|
|
476
|
+
### Advanced Input Validation
|
|
485
477
|
|
|
486
478
|
```typescript
|
|
487
|
-
import { defineInputGuardrail } from 'ai-sdk-guardrails';
|
|
488
479
|
import { extractTextContent } from 'ai-sdk-guardrails/guardrails/input';
|
|
489
480
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
name: 'resource-optimization',
|
|
493
|
-
description: 'Prevents inefficient API calls that provide little value',
|
|
481
|
+
const comprehensiveInputGuard = defineInputGuardrail({
|
|
482
|
+
name: 'comprehensive-input-validation',
|
|
494
483
|
execute: async (context) => {
|
|
495
484
|
const { prompt } = extractTextContent(context);
|
|
496
485
|
|
|
497
|
-
//
|
|
498
|
-
|
|
499
|
-
/^(hi|hello|hey|test)$/i,
|
|
500
|
-
/^.{1,5}$/, // Too short
|
|
501
|
-
/just testing/i,
|
|
502
|
-
/can you hear me/i,
|
|
503
|
-
];
|
|
504
|
-
|
|
505
|
-
const foundWaste = timeWasters.find((pattern) =>
|
|
506
|
-
pattern.test(prompt || ''),
|
|
507
|
-
);
|
|
508
|
-
if (foundWaste) {
|
|
486
|
+
// Length validation
|
|
487
|
+
if (prompt.length < 10) {
|
|
509
488
|
return {
|
|
510
489
|
tripwireTriggered: true,
|
|
511
|
-
message:
|
|
490
|
+
message: 'Input too short - likely to produce low-value response',
|
|
512
491
|
severity: 'medium',
|
|
513
|
-
|
|
514
|
-
pattern: foundWaste.source,
|
|
515
|
-
api_calls_prevented: 1,
|
|
516
|
-
},
|
|
492
|
+
suggestion: 'Please provide more detailed input for better results',
|
|
517
493
|
};
|
|
518
494
|
}
|
|
519
495
|
|
|
520
|
-
|
|
521
|
-
if (prompt && prompt.length > 12000) {
|
|
496
|
+
if (prompt.length > 4000) {
|
|
522
497
|
return {
|
|
523
498
|
tripwireTriggered: true,
|
|
524
|
-
message:
|
|
525
|
-
|
|
499
|
+
message: 'Input too long - may exceed token limits',
|
|
500
|
+
severity: 'high',
|
|
501
|
+
suggestion: 'Break your request into smaller, focused parts',
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Content quality checks
|
|
506
|
+
const spamPatterns = [
|
|
507
|
+
/^(.)\1{10,}$/, // Repeated characters
|
|
508
|
+
/^(test|hello|hi|hey)$/i, // Common spam words
|
|
509
|
+
];
|
|
510
|
+
|
|
511
|
+
const foundSpam = spamPatterns.find((pattern) => pattern.test(prompt));
|
|
512
|
+
if (foundSpam) {
|
|
513
|
+
return {
|
|
514
|
+
tripwireTriggered: true,
|
|
515
|
+
message: 'Low-quality input detected',
|
|
526
516
|
severity: 'high',
|
|
527
|
-
suggestion:
|
|
528
|
-
'Break into smaller, focused requests for better results and efficiency',
|
|
529
517
|
};
|
|
530
518
|
}
|
|
531
519
|
|
|
@@ -534,18 +522,13 @@ const resourceOptimizationGuardrail = defineInputGuardrail({
|
|
|
534
522
|
});
|
|
535
523
|
```
|
|
536
524
|
|
|
537
|
-
###
|
|
538
|
-
|
|
539
|
-
Output guardrails ensure every response meets your quality standards before reaching users:
|
|
525
|
+
### Professional Output Quality Control
|
|
540
526
|
|
|
541
527
|
```typescript
|
|
542
|
-
import { defineOutputGuardrail } from 'ai-sdk-guardrails';
|
|
543
528
|
import { extractContent } from 'ai-sdk-guardrails/guardrails/output';
|
|
544
529
|
|
|
545
|
-
|
|
546
|
-
const professionalQualityGuardrail = defineOutputGuardrail({
|
|
530
|
+
const professionalQualityGuard = defineOutputGuardrail({
|
|
547
531
|
name: 'professional-quality-control',
|
|
548
|
-
description: 'Ensures responses meet professional standards',
|
|
549
532
|
execute: async (context) => {
|
|
550
533
|
const { text } = extractContent(context.result);
|
|
551
534
|
|
|
@@ -561,7 +544,7 @@ const professionalQualityGuardrail = defineOutputGuardrail({
|
|
|
561
544
|
qualityIssues.push('Contains unprofessional language');
|
|
562
545
|
}
|
|
563
546
|
|
|
564
|
-
// Check for placeholder text
|
|
547
|
+
// Check for placeholder text
|
|
565
548
|
const placeholders = ['[insert', '[add', '[your', 'TODO:', 'FIXME:'];
|
|
566
549
|
const hasPlaceholders = placeholders.some((placeholder) =>
|
|
567
550
|
text.includes(placeholder),
|
|
@@ -600,419 +583,313 @@ const professionalQualityGuardrail = defineOutputGuardrail({
|
|
|
600
583
|
});
|
|
601
584
|
```
|
|
602
585
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
For streaming responses, maintain quality while preserving the real-time experience:
|
|
586
|
+
## 🔄 Streaming Support
|
|
606
587
|
|
|
607
|
-
|
|
608
|
-
sequenceDiagram
|
|
609
|
-
participant U as User
|
|
610
|
-
participant I as Input Guardrails
|
|
611
|
-
participant A as AI Model
|
|
612
|
-
participant S as Stream
|
|
613
|
-
participant O as Output Guardrails
|
|
614
|
-
|
|
615
|
-
U->>I: Request
|
|
616
|
-
I->>I: ✅ Validate & Approve
|
|
617
|
-
I->>A: Start Stream
|
|
618
|
-
A->>S: Stream chunks
|
|
619
|
-
loop Real-time streaming
|
|
620
|
-
S-->>U: Chunk 1, 2, 3...
|
|
621
|
-
end
|
|
622
|
-
S->>O: Complete response
|
|
623
|
-
O->>O: 🛡️ Quality check
|
|
624
|
-
Note over O: Post-completion validation
|
|
625
|
-
O-->>U: Quality feedback (if needed)
|
|
626
|
-
```
|
|
588
|
+
Guardrails work with streams out-of-the-box. By default, output guardrails run after the complete response has been streamed (buffer mode).
|
|
627
589
|
|
|
628
590
|
```typescript
|
|
629
|
-
import { streamText
|
|
630
|
-
import {
|
|
631
|
-
createOutputGuardrailsMiddleware,
|
|
632
|
-
defineOutputGuardrail,
|
|
633
|
-
} from 'ai-sdk-guardrails';
|
|
634
|
-
import { extractContent } from 'ai-sdk-guardrails/guardrails/output';
|
|
591
|
+
import { streamText } from 'ai';
|
|
635
592
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
description: 'Monitors streaming content for quality and appropriateness',
|
|
640
|
-
execute: async (context) => {
|
|
641
|
-
const { text } = extractContent(context.result);
|
|
593
|
+
const guardedModel = wrapWithGuardrails(openai('gpt-4o'), {
|
|
594
|
+
outputGuardrails: [qualityJudge],
|
|
595
|
+
});
|
|
642
596
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
text.endsWith('.') || text.endsWith('!') || text.endsWith('?'),
|
|
648
|
-
appropriateness: !containsInappropriateContent(text),
|
|
649
|
-
value: text.length > 50 && !isGenericResponse(text),
|
|
650
|
-
};
|
|
597
|
+
const { textStream } = await streamText({
|
|
598
|
+
model: guardedModel,
|
|
599
|
+
prompt: 'Tell me a short story about a robot.',
|
|
600
|
+
});
|
|
651
601
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
602
|
+
// Stream the response to the client
|
|
603
|
+
for await (const delta of textStream) {
|
|
604
|
+
process.stdout.write(delta);
|
|
605
|
+
}
|
|
655
606
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
tripwireTriggered: true,
|
|
659
|
-
message: `Streaming quality issues: ${issues.join(', ')}`,
|
|
660
|
-
severity: 'low', // Don't break user experience, just log
|
|
661
|
-
metadata: {
|
|
662
|
-
quality_metrics: qualityMetrics,
|
|
663
|
-
stream_complete: true,
|
|
664
|
-
},
|
|
665
|
-
};
|
|
666
|
-
}
|
|
607
|
+
// The qualityJudge guardrail will run after the stream is complete.
|
|
608
|
+
```
|
|
667
609
|
|
|
668
|
-
|
|
669
|
-
|
|
610
|
+
### Progressive Streaming (opt-in)
|
|
611
|
+
|
|
612
|
+
For early blocking, enable progressive evaluation:
|
|
613
|
+
|
|
614
|
+
```ts
|
|
615
|
+
const guardedModel = wrapWithGuardrails(openai('gpt-4o'), {
|
|
616
|
+
outputGuardrails: [qualityJudge],
|
|
617
|
+
// Evaluate on the fly and stop early when blocked
|
|
618
|
+
streamMode: 'progressive',
|
|
619
|
+
// Replace blocked output with a placeholder (default: true)
|
|
620
|
+
replaceOnBlocked: true,
|
|
670
621
|
});
|
|
622
|
+
```
|
|
671
623
|
|
|
672
|
-
|
|
673
|
-
function calculateCoherence(text: string): boolean {
|
|
674
|
-
// Simple coherence check - more sophisticated versions could use embeddings
|
|
675
|
-
const sentences = text.split(/[.!?]+/).filter((s) => s.trim());
|
|
676
|
-
return sentences.length > 1 && sentences.every((s) => s.trim().length > 10);
|
|
677
|
-
}
|
|
624
|
+
In progressive mode, guardrails evaluate text as it arrives. If blocked:
|
|
678
625
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
626
|
+
- with `throwOnBlocked: true`, the stream errors.
|
|
627
|
+
- with `replaceOnBlocked: true`, a placeholder message is streamed and the stream ends.
|
|
628
|
+
- otherwise, the original chunks continue (with a callback via `onOutputBlocked`).
|
|
683
629
|
|
|
684
|
-
|
|
685
|
-
const genericPhrases = [
|
|
686
|
-
'I cannot help',
|
|
687
|
-
"I don't have information",
|
|
688
|
-
'I cannot provide',
|
|
689
|
-
"Sorry, I can't",
|
|
690
|
-
];
|
|
691
|
-
return genericPhrases.some((phrase) => text.includes(phrase));
|
|
692
|
-
}
|
|
630
|
+
Note: Progressive mode runs guardrails more frequently and may increase overhead for long streams.
|
|
693
631
|
|
|
694
|
-
|
|
695
|
-
model: openai('gpt-4'),
|
|
696
|
-
middleware: [
|
|
697
|
-
createOutputGuardrailsMiddleware({
|
|
698
|
-
outputGuardrails: [streamingQualityGuardrail],
|
|
699
|
-
throwOnBlocked: false, // Log issues but don't interrupt streaming
|
|
700
|
-
onOutputBlocked: (results) => {
|
|
701
|
-
// Log for continuous improvement
|
|
702
|
-
console.log('Stream quality feedback:', results[0]?.metadata);
|
|
703
|
-
},
|
|
704
|
-
}),
|
|
705
|
-
],
|
|
706
|
-
});
|
|
632
|
+
### Configuration Highlights
|
|
707
633
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
prompt: 'Explain the benefits of automated testing',
|
|
712
|
-
maxTokens: 1000,
|
|
713
|
-
});
|
|
634
|
+
- `replaceOnBlocked` (output): defaults to `true` for safer behavior.
|
|
635
|
+
- `executionOptions.logLevel`: defaults to `'warn'` (respects `'none' | 'error' | 'warn' | 'info' | 'debug'`).
|
|
636
|
+
- `onInputBlocked` / `onOutputBlocked`: receive a `GuardrailExecutionSummary` with analytics.
|
|
714
637
|
|
|
715
|
-
|
|
716
|
-
for await (const chunk of enhancedStream.textStream) {
|
|
717
|
-
process.stdout.write(chunk);
|
|
718
|
-
}
|
|
638
|
+
### Cancellation Support
|
|
719
639
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
```
|
|
640
|
+
Guardrails can receive an `AbortSignal` and should abort work on timeout or caller-initiated cancel:
|
|
641
|
+
|
|
642
|
+
```ts
|
|
643
|
+
const guard = defineInputGuardrail({
|
|
644
|
+
name: 'long-check',
|
|
645
|
+
async execute(context, { signal }) {
|
|
646
|
+
await doWork({ signal }); // Pass signal to your async ops
|
|
647
|
+
return { tripwireTriggered: false };
|
|
648
|
+
},
|
|
649
|
+
});
|
|
723
650
|
|
|
724
|
-
|
|
651
|
+
// Timeouts are enforced by guardrail execution; if it times out, you'll get a GuardrailTimeoutError.
|
|
652
|
+
```
|
|
725
653
|
|
|
726
|
-
|
|
654
|
+
## 🛠️ Error Handling
|
|
727
655
|
|
|
728
|
-
|
|
656
|
+
When `throwOnBlocked: true` (the default), you can catch structured errors to handle blocks gracefully.
|
|
729
657
|
|
|
730
658
|
```typescript
|
|
731
|
-
import {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
sensitivity: 'medium',
|
|
750
|
-
}),
|
|
751
|
-
|
|
752
|
-
// Smart rate limiting that adapts to user behavior
|
|
753
|
-
rateLimitGuardrail({
|
|
754
|
-
requestsPerMinute: 30,
|
|
755
|
-
burstAllowance: 5,
|
|
756
|
-
adaptiveThrottling: true, // Reduces limits for low-quality requests
|
|
757
|
-
}),
|
|
758
|
-
|
|
759
|
-
// Block requests containing sensitive data (often leads to refusals)
|
|
760
|
-
piiDetector({
|
|
761
|
-
redactionMode: 'block', // Stop the request entirely
|
|
762
|
-
includeFinancial: true,
|
|
763
|
-
strictMode: true,
|
|
764
|
-
}),
|
|
765
|
-
];
|
|
659
|
+
import { generateText } from 'ai';
|
|
660
|
+
import { isGuardrailsError } from 'ai-sdk-guardrails';
|
|
661
|
+
|
|
662
|
+
try {
|
|
663
|
+
const result = await generateText({
|
|
664
|
+
model: guardedModel,
|
|
665
|
+
prompt: 'A prompt that might be blocked...',
|
|
666
|
+
});
|
|
667
|
+
} catch (error) {
|
|
668
|
+
if (isGuardrailsError(error)) {
|
|
669
|
+
// Error was thrown by one of our guardrails
|
|
670
|
+
console.error('Guardrail check failed:', error.message);
|
|
671
|
+
console.error('Triggered Guards:', error.results);
|
|
672
|
+
} else {
|
|
673
|
+
// Some other error occurred
|
|
674
|
+
console.error('An unexpected error occurred:', error);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
766
677
|
```
|
|
767
678
|
|
|
768
|
-
###
|
|
679
|
+
### User-Friendly Error Messages
|
|
769
680
|
|
|
770
|
-
|
|
681
|
+
Transform technical guardrail messages into user-friendly guidance:
|
|
771
682
|
|
|
772
683
|
```typescript
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
blockGenericResponses: true,
|
|
794
|
-
}),
|
|
795
|
-
|
|
796
|
-
// Maintain professional tone
|
|
797
|
-
professionalToneChecker({
|
|
798
|
-
blockUnprofessional: true,
|
|
799
|
-
requireCourteousLanguage: true,
|
|
800
|
-
forbidSlang: true,
|
|
801
|
-
}),
|
|
802
|
-
|
|
803
|
-
// Validate factual accuracy (uses AI-powered checking)
|
|
804
|
-
factualnessValidator({
|
|
805
|
-
confidence: 0.8,
|
|
806
|
-
checkCitations: true,
|
|
807
|
-
blockUncertain: false, // Log but don't block uncertain claims
|
|
808
|
-
}),
|
|
809
|
-
];
|
|
684
|
+
function createUserFriendlyMessage(guardrailResult): string {
|
|
685
|
+
const guardrailName = guardrailResult.context?.guardrailName;
|
|
686
|
+
|
|
687
|
+
switch (guardrailName) {
|
|
688
|
+
case 'content-length-limit':
|
|
689
|
+
return 'Your message is too long. Please keep it under 500 characters for the best response.';
|
|
690
|
+
|
|
691
|
+
case 'blocked-keywords':
|
|
692
|
+
return "I can't help with that topic. Try asking about something else I can assist with.";
|
|
693
|
+
|
|
694
|
+
case 'user-rate-limit':
|
|
695
|
+
return "You're sending requests too quickly. Please wait a moment before trying again.";
|
|
696
|
+
|
|
697
|
+
default:
|
|
698
|
+
return (
|
|
699
|
+
guardrailResult.suggestion ||
|
|
700
|
+
'Please refine your request and try again.'
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
810
704
|
```
|
|
811
705
|
|
|
812
706
|
## Complete AI SDK Integration
|
|
813
707
|
|
|
814
|
-
The library seamlessly integrates with all AI SDK functions
|
|
708
|
+
The library seamlessly integrates with all AI SDK functions:
|
|
815
709
|
|
|
816
710
|
```typescript
|
|
817
|
-
// Create your
|
|
818
|
-
const productionModel =
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
})
|
|
827
|
-
|
|
711
|
+
// Create your production-ready model once
|
|
712
|
+
const productionModel = wrapWithGuardrails(openai('gpt-4'), {
|
|
713
|
+
inputGuardrails: [lengthGuard, spamGuard, rateLimitGuard],
|
|
714
|
+
outputGuardrails: [qualityGuard, sensitiveInfoGuard],
|
|
715
|
+
throwOnBlocked: false,
|
|
716
|
+
onInputBlocked: (executionSummary) => {
|
|
717
|
+
console.log('Input blocked:', executionSummary.blockedResults[0]?.message);
|
|
718
|
+
|
|
719
|
+
// Enhanced analytics available in v4.0.0
|
|
720
|
+
console.log(`Execution time: ${executionSummary.totalExecutionTime}ms`);
|
|
721
|
+
console.log(
|
|
722
|
+
`Guardrails: ${executionSummary.stats.blocked} blocked, ${executionSummary.stats.passed} passed`,
|
|
723
|
+
);
|
|
724
|
+
},
|
|
725
|
+
onOutputBlocked: (executionSummary) => {
|
|
726
|
+
console.log(
|
|
727
|
+
'Output filtered:',
|
|
728
|
+
executionSummary.blockedResults[0]?.message,
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
// Track comprehensive metrics
|
|
732
|
+
analytics.track('output_blocked', {
|
|
733
|
+
severity: executionSummary.blockedResults[0]?.severity,
|
|
734
|
+
totalGuardrails: executionSummary.guardrailsExecuted,
|
|
735
|
+
executionTime: executionSummary.totalExecutionTime,
|
|
736
|
+
});
|
|
737
|
+
},
|
|
828
738
|
});
|
|
829
739
|
|
|
830
|
-
// Use with any AI SDK function
|
|
740
|
+
// Use with any AI SDK function
|
|
831
741
|
const textResult = await generateText({
|
|
832
742
|
model: productionModel,
|
|
833
743
|
prompt: 'Write a professional email response',
|
|
834
|
-
experimental_telemetry: {
|
|
835
|
-
isEnabled: true,
|
|
836
|
-
functionId: 'performance-optimized-text',
|
|
837
|
-
metadata: { optimization: 'performance+quality' },
|
|
838
|
-
},
|
|
839
744
|
});
|
|
840
745
|
|
|
841
746
|
const objectResult = await generateObject({
|
|
842
747
|
model: productionModel,
|
|
843
748
|
prompt: 'Create a user profile',
|
|
844
749
|
schema: userProfileSchema,
|
|
845
|
-
experimental_telemetry: {
|
|
846
|
-
isEnabled: true,
|
|
847
|
-
functionId: 'performance-optimized-object',
|
|
848
|
-
metadata: { optimization: 'performance+quality' },
|
|
849
|
-
},
|
|
850
750
|
});
|
|
851
751
|
|
|
852
752
|
const textStream = await streamText({
|
|
853
753
|
model: productionModel,
|
|
854
754
|
prompt: 'Explain our product features',
|
|
855
|
-
experimental_telemetry: {
|
|
856
|
-
isEnabled: true,
|
|
857
|
-
functionId: 'performance-optimized-stream',
|
|
858
|
-
metadata: { optimization: 'performance+quality' },
|
|
859
|
-
},
|
|
860
755
|
});
|
|
861
756
|
```
|
|
862
757
|
|
|
863
758
|
## Examples
|
|
864
759
|
|
|
865
|
-
Explore
|
|
866
|
-
|
|
867
|
-
### Core Examples
|
|
868
|
-
|
|
869
|
-
- **[Basic Composition](examples/basic-composition.ts)** - Simple input/output validation for efficiency and quality
|
|
870
|
-
- **[Basic Guardrails](examples/basic-guardrails.ts)** - Foundation patterns for input/output validation
|
|
871
|
-
- **[Business Logic](examples/business-logic.ts)** - Custom business rules, work hours, and professional standards
|
|
872
|
-
- **[LLM-as-Judge](examples/llm-as-judge.ts)** - AI-powered quality evaluation and scoring
|
|
873
|
-
|
|
874
|
-
### Additional Examples
|
|
760
|
+
Explore **30 comprehensive examples** that demonstrate practical performance optimization, security protection, quality assurance, and enterprise-grade safety patterns:
|
|
875
761
|
|
|
876
|
-
|
|
877
|
-
- **[Streaming Guardrails](examples/streaming-guardrails.ts)** - Real-time quality monitoring
|
|
878
|
-
- **[Rate Limiting](examples/rate-limit-guardrail.ts)** - Smart rate limiting that prevents resource overuse
|
|
879
|
-
- **[Autoevals Integration](examples/autoevals-guardrails.ts)** - Advanced AI-powered evaluation
|
|
762
|
+
### Core Foundation Examples
|
|
880
763
|
|
|
881
|
-
|
|
764
|
+
- **[Input Length Limits](examples/01-input-length-limit.ts)** - Foundation patterns for input validation
|
|
765
|
+
- **[Blocked Keywords](examples/02-blocked-keywords.ts)** - Block prompts with specific keywords and content filtering
|
|
766
|
+
- **[Output Length Check](examples/04-output-length-check.ts)** - Ensure minimum output length and quality control
|
|
767
|
+
- **[Quality Assessment](examples/06-quality-assessment.ts)** - Assess response quality and content analysis
|
|
768
|
+
- **[Combined Protection](examples/07-combined-protection.ts)** - Simple input/output validation for efficiency and quality
|
|
769
|
+
- **[Simple Combined Protection](examples/07a-simple-combined-protection.ts)** - Simplified combined guardrails example
|
|
770
|
+
- **[Blocking vs Warning](examples/08-blocking-vs-warning.ts)** - Compare blocking and warning modes with error handling
|
|
882
771
|
|
|
883
|
-
|
|
884
|
-
# Install dependencies
|
|
885
|
-
pnpm install
|
|
772
|
+
### Security & Protection Examples
|
|
886
773
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
774
|
+
- **[PII Detection](examples/03-pii-detection.ts)** - Detect and block personal information in inputs
|
|
775
|
+
- **[Sensitive Output Filter](examples/05-sensitive-output-filter.ts)** - Filter sensitive data from responses
|
|
776
|
+
- **[Prompt Injection Detection](examples/16-prompt-injection-detection.ts)** - Comprehensive prompt injection detection with pattern matching and heuristic scoring
|
|
777
|
+
- **[Tool Call Validation](examples/17-tool-call-validation.ts)** - Tool call validation with security patterns and dangerous operation detection
|
|
778
|
+
- **[Basic Tool Allowlist](examples/17a-basic-tool-allowlist.ts)** - Basic tool allowlisting for secure tool usage
|
|
779
|
+
- **[Tool Parameter Validation](examples/17b-tool-parameter-validation.ts)** - Validate tool parameters for security
|
|
780
|
+
- **[Secret Leakage Scan](examples/18-secret-leakage-scan.ts)** - Secret leakage scanning with automatic redaction and entropy calculation
|
|
781
|
+
- **[Jailbreak Detection](examples/30-jailbreak-detection.ts)** - Jailbreak detection with safe response templates and pattern recognition
|
|
892
782
|
|
|
893
|
-
|
|
894
|
-
tsx examples/basic-guardrails.ts 1 # Run first example only
|
|
895
|
-
tsx examples/streaming-guardrails.ts 3 # Run third streaming example
|
|
896
|
-
```
|
|
783
|
+
### Content Quality & Validation Examples
|
|
897
784
|
|
|
898
|
-
|
|
785
|
+
- **[Autoevals Guardrails](examples/31-autoevals-guardrails.ts)** - AI-powered quality evaluation using Autoevals library for factuality checking
|
|
786
|
+
- **[Business Logic](examples/14-business-logic.ts)** - Custom business rules, work hours, and professional standards
|
|
787
|
+
- **[LLM-as-Judge](examples/15-llm-as-judge.ts)** - AI-powered quality evaluation and scoring
|
|
788
|
+
- **[Simple Quality Judge](examples/15a-simple-quality-judge.ts)** - Simplified quality assessment example
|
|
789
|
+
- **[Hallucination Detection](examples/19-hallucination-detection.ts)** - Hallucination detection with LLM-as-judge verification and fact-checking
|
|
790
|
+
- **[Response Consistency](examples/22-response-consistency.ts)** - Response consistency validation and coherence checking
|
|
899
791
|
|
|
900
|
-
|
|
792
|
+
### Compliance & Regulation Examples
|
|
901
793
|
|
|
902
|
-
|
|
794
|
+
- **[Regulated Advice Compliance](examples/21-regulated-advice-compliance.ts)** - Regulated advice compliance with jurisdiction-specific rules (US, EU, UK, CA, AU, JP, CN, IN)
|
|
795
|
+
- **[Role Hierarchy Enforcement](examples/23-role-hierarchy-enforcement.ts)** - Role hierarchy enforcement with multi-layered violation detection
|
|
903
796
|
|
|
904
|
-
|
|
905
|
-
graph TB
|
|
906
|
-
subgraph "Your Application"
|
|
907
|
-
App[Your App Code]
|
|
908
|
-
Config[Guardrail Configuration]
|
|
909
|
-
end
|
|
797
|
+
### Data Integrity & Code Safety Examples
|
|
910
798
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
799
|
+
- **[Schema Validation](examples/09-schema-validation.ts)** - Schema validation and structured output quality
|
|
800
|
+
- **[Object Content Filter](examples/10-object-content-filter.ts)** - Filter inappropriate content in generated objects
|
|
801
|
+
- **[SQL Code Safety](examples/24-sql-code-safety.ts)** - SQL code safety with dangerous operation blocking and injection detection
|
|
914
802
|
|
|
915
|
-
|
|
916
|
-
Length[Length Validation]
|
|
917
|
-
Spam[Spam Detection]
|
|
918
|
-
PII[PII Detection]
|
|
919
|
-
Business[Business Rules]
|
|
920
|
-
Custom1[Custom Guards]
|
|
921
|
-
end
|
|
803
|
+
### Network & External Access Examples
|
|
922
804
|
|
|
923
|
-
|
|
924
|
-
Quality[Quality Assurance]
|
|
925
|
-
Sensitive[Sensitive Info Filter]
|
|
926
|
-
Professional[Professional Tone]
|
|
927
|
-
Factual[Factual Validation]
|
|
928
|
-
Custom2[Custom Guards]
|
|
929
|
-
end
|
|
930
|
-
end
|
|
805
|
+
- **[Domain Allowlisting](examples/25-browsing-domain-allowlist.ts)** - Domain allowlisting with URL sanitization and security validation
|
|
931
806
|
|
|
932
|
-
|
|
933
|
-
Wrapper[wrapLanguageModel]
|
|
934
|
-
Generator[generateText/Object/Stream]
|
|
935
|
-
end
|
|
807
|
+
### Privacy & Memory Management Examples
|
|
936
808
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
Log[Logging & Telemetry]
|
|
940
|
-
end
|
|
809
|
+
- **[Memory Minimization](examples/26-memory-minimization.ts)** - Memory minimization with PII redaction and multiple redaction strategies
|
|
810
|
+
- **[Logging Redaction](examples/27-logging-redaction.ts)** - Logging redaction with secure logging practices and compliance frameworks
|
|
941
811
|
|
|
942
|
-
|
|
943
|
-
Config --> InputMW
|
|
944
|
-
InputMW --> Length
|
|
945
|
-
InputMW --> Spam
|
|
946
|
-
InputMW --> PII
|
|
947
|
-
InputMW --> Business
|
|
948
|
-
InputMW --> Custom1
|
|
812
|
+
### Safety & Escalation Examples
|
|
949
813
|
|
|
950
|
-
|
|
951
|
-
|
|
814
|
+
- **[Human Review Escalation](examples/20-human-review-escalation.ts)** - Human review escalation with content flagging, review routing, and quality control workflows
|
|
815
|
+
- **[Toxicity & Harassment De-escalation](examples/29-toxicity-harassment-deescalation.ts)** - Toxicity and harassment de-escalation with safe response generation and user escalation tracking
|
|
952
816
|
|
|
953
|
-
|
|
954
|
-
Generator --> AI
|
|
955
|
-
AI --> OutputMW
|
|
817
|
+
### Streaming Examples
|
|
956
818
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
OutputMW --> Factual
|
|
961
|
-
OutputMW --> Custom2
|
|
819
|
+
- **[Streaming Limits](examples/11-streaming-limits.ts)** - Apply guardrails to streaming responses with real-time validation
|
|
820
|
+
- **[Streaming Quality](examples/12-streaming-quality.ts)** - Real-time quality monitoring for streams
|
|
821
|
+
- **[Streaming Early Termination](examples/28-streaming-early-termination.ts)** - Streaming early termination with real-time content monitoring and session state management
|
|
962
822
|
|
|
963
|
-
|
|
964
|
-
OutputMW -->|Quality Issues| Log
|
|
823
|
+
### Resource Management Examples
|
|
965
824
|
|
|
966
|
-
|
|
967
|
-
style OutputMW fill:#f3e5f5
|
|
968
|
-
style AI fill:#fff3e0
|
|
969
|
-
style App fill:#e8f5e8
|
|
970
|
-
```
|
|
825
|
+
- **[Rate Limiting](examples/13-rate-limiting.ts)** - Smart rate limiting that prevents resource overuse
|
|
971
826
|
|
|
972
|
-
###
|
|
827
|
+
### Running Examples
|
|
973
828
|
|
|
974
|
-
|
|
829
|
+
```bash
|
|
830
|
+
# Install dependencies
|
|
831
|
+
pnpm install
|
|
975
832
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
833
|
+
# Run core foundation examples
|
|
834
|
+
tsx examples/01-input-length-limit.ts # Basic input validation
|
|
835
|
+
tsx examples/02-blocked-keywords.ts # Keyword blocking
|
|
836
|
+
tsx examples/04-output-length-check.ts # Output length validation
|
|
837
|
+
tsx examples/06-quality-assessment.ts # Quality assessment
|
|
838
|
+
tsx examples/07-combined-protection.ts # Combined input/output protection
|
|
839
|
+
tsx examples/07a-simple-combined-protection.ts # Simplified combined protection
|
|
840
|
+
tsx examples/08-blocking-vs-warning.ts # Blocking vs warning modes
|
|
841
|
+
|
|
842
|
+
# Run security examples
|
|
843
|
+
tsx examples/03-pii-detection.ts # PII protection
|
|
844
|
+
tsx examples/05-sensitive-output-filter.ts # Sensitive output filtering
|
|
845
|
+
tsx examples/16-prompt-injection-detection.ts # Prompt injection protection
|
|
846
|
+
tsx examples/17-tool-call-validation.ts # Tool call validation
|
|
847
|
+
tsx examples/17a-basic-tool-allowlist.ts # Basic tool allowlisting
|
|
848
|
+
tsx examples/17b-tool-parameter-validation.ts # Tool parameter validation
|
|
849
|
+
tsx examples/18-secret-leakage-scan.ts # Secret leakage prevention
|
|
850
|
+
tsx examples/30-jailbreak-detection.ts # Jailbreak detection
|
|
851
|
+
|
|
852
|
+
# Run content quality examples
|
|
853
|
+
tsx examples/31-autoevals-guardrails.ts # AI-powered quality evaluation with Autoevals
|
|
854
|
+
tsx examples/14-business-logic.ts # Business-specific rules
|
|
855
|
+
tsx examples/15-llm-as-judge.ts # AI-powered quality control
|
|
856
|
+
tsx examples/15a-simple-quality-judge.ts # Simplified quality assessment
|
|
857
|
+
tsx examples/19-hallucination-detection.ts # Hallucination detection
|
|
858
|
+
tsx examples/22-response-consistency.ts # Response consistency
|
|
859
|
+
|
|
860
|
+
# Run compliance examples
|
|
861
|
+
tsx examples/21-regulated-advice-compliance.ts # Regulatory compliance
|
|
862
|
+
tsx examples/23-role-hierarchy-enforcement.ts # Role hierarchy enforcement
|
|
863
|
+
|
|
864
|
+
# Run data integrity examples
|
|
865
|
+
tsx examples/09-schema-validation.ts # Schema validation
|
|
866
|
+
tsx examples/10-object-content-filter.ts # Object content filtering
|
|
867
|
+
tsx examples/24-sql-code-safety.ts # SQL code safety
|
|
868
|
+
|
|
869
|
+
# Run network security examples
|
|
870
|
+
tsx examples/25-browsing-domain-allowlist.ts # Domain allowlisting
|
|
871
|
+
|
|
872
|
+
# Run privacy examples
|
|
873
|
+
tsx examples/26-memory-minimization.ts # Memory minimization
|
|
874
|
+
tsx examples/27-logging-redaction.ts # Logging redaction
|
|
875
|
+
|
|
876
|
+
# Run safety examples
|
|
877
|
+
tsx examples/20-human-review-escalation.ts # Human review escalation
|
|
878
|
+
tsx examples/29-toxicity-harassment-deescalation.ts # Toxicity de-escalation
|
|
879
|
+
|
|
880
|
+
# Run streaming examples
|
|
881
|
+
tsx examples/11-streaming-limits.ts # Streaming limits
|
|
882
|
+
tsx examples/12-streaming-quality.ts # Streaming quality monitoring
|
|
883
|
+
tsx examples/28-streaming-early-termination.ts # Streaming early termination
|
|
884
|
+
|
|
885
|
+
# Run resource management examples
|
|
886
|
+
tsx examples/13-rate-limiting.ts # Rate limiting
|
|
1003
887
|
```
|
|
1004
888
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
- **Resource optimization** happens first to prevent unnecessary API calls
|
|
1008
|
-
- **Quality assurance** happens last to ensure professional responses
|
|
1009
|
-
- **Telemetry** captures both blocked requests and quality metrics
|
|
1010
|
-
- **Composability** allows mixing and matching guardrails as needed
|
|
1011
|
-
|
|
1012
|
-
## Contributing
|
|
889
|
+
## 🤝 Contributing
|
|
1013
890
|
|
|
1014
|
-
|
|
891
|
+
Contributions of all sizes are welcome! Please open issues and pull requests on [GitHub](https://github.com/jagreehal/ai-sdk-guardrails).
|
|
1015
892
|
|
|
1016
|
-
## License
|
|
893
|
+
## 📄 License
|
|
1017
894
|
|
|
1018
|
-
MIT © [Jag Reehal](https://github.com/jagreehal)
|
|
895
|
+
MIT © [Jag Reehal](https://github.com/jagreehal) – See LICENSE for full details.
|