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 CHANGED
@@ -1,41 +1,53 @@
1
1
  # AI SDK Guardrails
2
2
 
3
- Stop unnecessary AI calls. Optimize performance, improve quality, and prevent inappropriate AI responses with intelligent middleware for the Vercel AI SDK.
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
- [![npm version](https://badge.fury.io/js/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
6
- [![Downloads](https://img.shields.io/npm/dm/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
7
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- ## Requirements
7
+ ![Guardrails Demo](./media/guardrail-example.gif)
11
8
 
12
- This library requires the Vercel AI SDK (v5 and above) for its composable middleware architecture:
9
+ ## TL;DR
13
10
 
14
- ```bash
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
- ![Guardrails](./media/guardrail-example.gif)
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
- ### 🎯 **Improve Response Quality**
29
-
30
- Ensure every AI response meets your standards. Filter out hallucinations, check factuality, enforce formatting requirements, and maintain consistent quality across your application.
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
- ### 🛡️ **Prevent Embarrassing Responses**
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
- Stop your AI from saying things you'll regret. Block inappropriate content, filter sensitive information, detect bias, and maintain professional standards in all interactions.
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
- ### **Focus AI Generations**
39
+ // 2. Wrap your model
40
+ const guardedModel = wrapWithGuardrails(openai('gpt-4o'), {
41
+ inputGuardrails: [inputGuard],
42
+ outputGuardrails: [outputGuard],
43
+ });
37
44
 
38
- Guide your AI to stay on topic and provide useful responses. Prevent prompt injection, enforce business policies, and ensure responses align with your application's purpose.
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
- pnpm add ai-sdk-guardrails
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
- ## Quick Start
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, wrapLanguageModel } from 'ai';
109
+ import { generateText } from 'ai';
90
110
  import { openai } from '@ai-sdk/openai';
91
- import { createInputGuardrailsMiddleware } from 'ai-sdk-guardrails';
92
- import { blockedKeywords } from 'ai-sdk-guardrails/guardrails/input';
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 optimizedModel = wrapLanguageModel({
96
- model: openai('gpt-4'),
97
- middleware: [
98
- createInputGuardrailsMiddleware({
99
- inputGuardrails: [blockedKeywords(['spam', 'test', 'hello'])],
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
- // This would normally waste an API call for a useless response
105
- const result = await generateText({
106
- model: optimizedModel,
107
- prompt: 'hello', // ❌ Blocked - prevents unnecessary API call
140
+ const optimizedModel = wrapWithInputGuardrails(openai('gpt-4'), {
141
+ inputGuardrails: [lengthGuard],
108
142
  });
109
- // → Throws GuardrailError: "Blocked keyword detected: hello"
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 { createOutputGuardrailsMiddleware } from 'ai-sdk-guardrails';
122
- import { sensitiveInfoDetector } from 'ai-sdk-guardrails/guardrails/output';
123
-
124
- const qualityModel = wrapLanguageModel({
125
- model: openai('gpt-4'),
126
- middleware: [
127
- // Optimize by filtering inefficient inputs
128
- createInputGuardrailsMiddleware({
129
- inputGuardrails: [blockedKeywords(['spam', 'test'])],
130
- }),
131
-
132
- // Ensure quality outputs
133
- createOutputGuardrailsMiddleware({
134
- outputGuardrails: [sensitiveInfoDetector()], // Prevents data leaks
135
- onOutputBlocked: (results) => {
136
- console.log('Prevented embarrassing response:', results[0]?.message);
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
- import { defineInputGuardrail } from 'ai-sdk-guardrails';
155
- import { extractTextContent } from 'ai-sdk-guardrails/guardrails/input';
156
-
157
- // Prevent inefficient homework help requests
158
- const homeworkDetector = defineInputGuardrail({
159
- name: 'homework-detector',
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: 'Homework help blocked - prevents inefficient API usage',
167
- suggestion: 'Ask about learning concepts instead',
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 = wrapLanguageModel({
176
- model: openai('gpt-4'),
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
- **That's it!** Your AI application now optimizes resource usage, ensures quality, and prevents inappropriate responses automatically.
245
+ ### 4. Type-Safe Metadata (TypeScript)
186
246
 
187
- ### Smart API Optimization Strategy
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
- // Layer 1: Immediate optimization - block inefficient requests
193
- const optimizationLayer = [
194
- defineInputGuardrail({
195
- name: 'length-validator',
196
- description: 'Prevents expensive long requests that often fail',
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
- return { tripwireTriggered: false };
278
- },
279
- }),
280
- ];
281
-
282
- // Smart model that optimizes performance and ensures quality
283
- const smartModel = wrapLanguageModel({
284
- model: openai('gpt-4'),
285
- middleware: [
286
- createInputGuardrailsMiddleware({
287
- inputGuardrails: optimizationLayer,
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
- // Example usage with cost tracking
306
- const result = await generateText({
307
- model: smartModel,
308
- prompt: 'Write a comprehensive guide to software testing best practices',
309
- experimental_telemetry: {
310
- isEnabled: true,
311
- functionId: 'cost-optimised-generation',
312
- metadata: {
313
- resource_optimization: true,
314
- quality_checks: true,
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
- ## Error Handling and Response Strategies
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
- When guardrails block requests or filter responses, your application needs to handle these situations gracefully. Understanding the middleware flow helps you implement proper error handling:
353
+ ## Architecture Overview
323
354
 
324
- ### Middleware Flow and Decision Points
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
- flowchart TB
328
- A[Your Application] --> B[wrapLanguageModel]
329
- B --> C[Input Middleware]
330
- C --> D{Validation<br/>Passed?}
331
- D -->|❌ Blocked| E[GuardrailError<br/>+ Callbacks]
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
- The diagram shows two key decision points where your error handling strategies activate:
364
+ subgraph "AI SDK Guardrails Middleware"
365
+ InputMW[Input Guardrails Middleware]
366
+ OutputMW[Output Guardrails Middleware]
346
367
 
347
- - **Input validation failures** → Trigger callbacks or throw errors
348
- - **Output quality issues** → Filter responses and log concerns
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
- Here's how to implement proper error handling for each scenario:
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
- ### Input Guardrail Errors
385
+ subgraph "AI SDK Core"
386
+ Wrapper[wrapLanguageModel]
387
+ Generator[generateText/Object/Stream]
388
+ end
353
389
 
354
- Input guardrails can either throw errors or trigger callbacks, depending on your configuration:
390
+ subgraph "External Services"
391
+ AI[AI Model Provider]
392
+ Log[Logging & Telemetry]
393
+ end
355
394
 
356
- ```typescript
357
- const protectedModel = wrapLanguageModel({
358
- model: openai('gpt-4'),
359
- middleware: [
360
- createInputGuardrailsMiddleware({
361
- inputGuardrails: [lengthLimitGuardrail, spamFilterGuardrail],
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
- try {
389
- const result = await generateText({
390
- model: protectedModel,
391
- prompt: userInput,
392
- });
403
+ InputMW -->|Valid Request| Wrapper
404
+ InputMW -->|Blocked Request| Log
393
405
 
394
- // Handle successful response
395
- if (result.text) {
396
- return result.text;
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
- ### Output Guardrail Handling
410
+ OutputMW --> Quality
411
+ OutputMW --> Sensitive
412
+ OutputMW --> Professional
413
+ OutputMW --> Factual
414
+ OutputMW --> Custom2
409
415
 
410
- Output guardrails typically filter or modify responses rather than throwing errors:
416
+ OutputMW -->|Clean Response| App
417
+ OutputMW -->|Quality Issues| Log
411
418
 
412
- ```typescript
413
- const qualityModel = wrapLanguageModel({
414
- model: openai('gpt-4'),
415
- middleware: [
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
- ### User-Friendly Error Messages
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
- case 'blocked-keywords':
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
- case 'rate-limit':
457
- return "You're sending requests too quickly. Please wait a moment before trying again.";
429
+ ### Rate Limiting
458
430
 
459
- case 'math-homework-detector':
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
- default:
463
- return (
464
- guardrailResult.suggestion ||
465
- 'Please refine your request and try again.'
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
- ### Best Practices for Error Handling
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
- ## Understanding the Benefits
452
+ Use a cheaper, faster model to "judge" the output of a more powerful one.
481
453
 
482
- ### Resource Optimization Through Input Validation
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
- Input guardrails act as intelligent gatekeepers that prevent inefficient API calls that would likely fail or provide little value:
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
- // Prevent inefficient calls for common time-wasters
491
- const resourceOptimizationGuardrail = defineInputGuardrail({
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
- // Block requests that typically result in low-value responses
498
- const timeWasters = [
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: `Blocked time-wasting request - prevented unnecessary API call`,
490
+ message: 'Input too short - likely to produce low-value response',
512
491
  severity: 'medium',
513
- metadata: {
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
- // Block requests that often exceed token limits
521
- if (prompt && prompt.length > 12000) {
496
+ if (prompt.length > 4000) {
522
497
  return {
523
498
  tripwireTriggered: true,
524
- message:
525
- 'Request likely to exceed token limits - preventing API failure',
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
- ### Quality Assurance Through Output Validation
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
- // Ensure responses are professional and useful
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 that indicates incomplete response
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
- ### Streaming Intelligence: Real-Time Quality Control
604
-
605
- For streaming responses, maintain quality while preserving the real-time experience:
586
+ ## 🔄 Streaming Support
606
587
 
607
- ```mermaid
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, wrapLanguageModel } from 'ai';
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
- // Monitor streaming quality without interrupting the experience
637
- const streamingQualityGuardrail = defineOutputGuardrail({
638
- name: 'streaming-quality-monitor',
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
- // Quality checks that run after streaming completes
644
- const qualityMetrics = {
645
- coherence: calculateCoherence(text),
646
- completeness:
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
- const issues = Object.entries(qualityMetrics)
653
- .filter(([_, passed]) => !passed)
654
- .map(([metric, _]) => metric);
602
+ // Stream the response to the client
603
+ for await (const delta of textStream) {
604
+ process.stdout.write(delta);
605
+ }
655
606
 
656
- if (issues.length > 0) {
657
- return {
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
- return { tripwireTriggered: false };
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
- // Helper functions for quality assessment
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
- function containsInappropriateContent(text: string): boolean {
680
- const inappropriate = ['inappropriate', 'offensive', 'harmful'];
681
- return inappropriate.some((term) => text.toLowerCase().includes(term));
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
- function isGenericResponse(text: string): boolean {
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
- const qualityStreamingModel = wrapLanguageModel({
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
- // Stream with quality monitoring
709
- const enhancedStream = await streamText({
710
- model: qualityStreamingModel,
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
- // Users see real-time streaming
716
- for await (const chunk of enhancedStream.textStream) {
717
- process.stdout.write(chunk);
718
- }
638
+ ### Cancellation Support
719
639
 
720
- // Quality analysis happens post-stream for continuous improvement
721
- console.log('\nStream completed with quality monitoring');
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
- ## Production-Ready Performance and Quality Controls
651
+ // Timeouts are enforced by guardrail execution; if it times out, you'll get a GuardrailTimeoutError.
652
+ ```
725
653
 
726
- ### Smart Input Filtering
654
+ ## 🛠️ Error Handling
727
655
 
728
- Access comprehensive input validation that optimizes performance while maintaining user experience:
656
+ When `throwOnBlocked: true` (the default), you can catch structured errors to handle blocks gracefully.
729
657
 
730
658
  ```typescript
731
- import {
732
- lengthLimit,
733
- rateLimitGuardrail,
734
- piiDetector,
735
- spamFilter,
736
- } from 'ai-sdk-guardrails/guardrails/input';
737
-
738
- const optimizedInputs = [
739
- // Prevent resource waste
740
- lengthLimit({
741
- minLength: 10, // Block "hi", "test", etc.
742
- maxLength: 4000, // Prevent token limit overruns
743
- encoding: 'tiktoken',
744
- }),
745
-
746
- spamFilter({
747
- detectRepetition: true,
748
- blockCommonWaste: ['test', 'hello', 'hi'],
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
- ### Advanced Output Quality Assurance
679
+ ### User-Friendly Error Messages
769
680
 
770
- Choose from sophisticated output validation that ensures professional results:
681
+ Transform technical guardrail messages into user-friendly guidance:
771
682
 
772
683
  ```typescript
773
- import {
774
- sensitiveInfoDetector,
775
- qualityAssurance,
776
- professionalToneChecker,
777
- factualnessValidator,
778
- } from 'ai-sdk-guardrails/guardrails/output';
779
-
780
- const qualityOutputs = [
781
- // Prevent embarrassing information leaks
782
- sensitiveInfoDetector({
783
- strictMode: true,
784
- blockOnDetection: true,
785
- customPatterns: ['internal-', 'confidential'],
786
- }),
787
-
788
- // Ensure responses meet quality standards
789
- qualityAssurance({
790
- minHelpfulness: 0.7,
791
- maxRepetition: 0.3,
792
- requireCompleteness: true,
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 through the middleware architecture:
708
+ The library seamlessly integrates with all AI SDK functions:
815
709
 
816
710
  ```typescript
817
- // Create your performance-optimized, quality-assured model once
818
- const productionModel = wrapLanguageModel({
819
- model: openai('gpt-4'),
820
- middleware: [
821
- createInputGuardrailsMiddleware({
822
- inputGuardrails: optimizedInputs,
823
- }),
824
- createOutputGuardrailsMiddleware({
825
- outputGuardrails: qualityOutputs,
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 - same optimization and quality everywhere
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 focused examples that demonstrate practical performance optimization and quality assurance:
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
- - **[Object Guardrails](examples/object-guardrails.ts)** - Schema validation and structured output quality
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
- ### Running Examples
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
- ```bash
884
- # Install dependencies
885
- pnpm install
772
+ ### Security & Protection Examples
886
773
 
887
- # Interactive examples with better UX
888
- tsx examples/basic-composition.ts # Start here - simplest example
889
- tsx examples/basic-guardrails.ts # Core patterns with 8 examples
890
- tsx examples/business-logic.ts # Business-specific rules
891
- tsx examples/llm-as-judge.ts # AI-powered quality control
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
- # Or run specific examples directly
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
- All examples feature interactive menus with arrow key navigation, multi-selection with checkboxes, and automatic return to the main menu. They demonstrate practical performance optimization and quality assurance patterns.
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
- ## Architecture Overview
792
+ ### Compliance & Regulation Examples
901
793
 
902
- The library leverages the Vercel AI SDK's middleware architecture to provide composable guardrails that integrate seamlessly with your existing AI applications:
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
- ```mermaid
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
- subgraph "AI SDK Guardrails Middleware"
912
- InputMW[Input Guardrails Middleware]
913
- OutputMW[Output Guardrails Middleware]
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
- subgraph "Input Guardrails Layer"
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
- subgraph "Output Guardrails Layer"
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
- subgraph "AI SDK Core"
933
- Wrapper[wrapLanguageModel]
934
- Generator[generateText/Object/Stream]
935
- end
807
+ ### Privacy & Memory Management Examples
936
808
 
937
- subgraph "External Services"
938
- AI[AI Model Provider]
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
- App --> Config
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
- InputMW -->|Valid Request| Wrapper
951
- InputMW -->|Blocked Request| Log
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
- Wrapper --> Generator
954
- Generator --> AI
955
- AI --> OutputMW
817
+ ### Streaming Examples
956
818
 
957
- OutputMW --> Quality
958
- OutputMW --> Sensitive
959
- OutputMW --> Professional
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
- OutputMW -->|Clean Response| App
964
- OutputMW -->|Quality Issues| Log
823
+ ### Resource Management Examples
965
824
 
966
- style InputMW fill:#e1f5fe
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
- ### Middleware Execution Flow
827
+ ### Running Examples
973
828
 
974
- The guardrails execute in a specific order to maximize efficiency and ensure quality:
829
+ ```bash
830
+ # Install dependencies
831
+ pnpm install
975
832
 
976
- ```mermaid
977
- sequenceDiagram
978
- participant App as Your Application
979
- participant IM as Input Middleware
980
- participant SDK as AI SDK Core
981
- participant AI as AI Model
982
- participant OM as Output Middleware
983
- participant Log as Telemetry
984
-
985
- App->>IM: User Request
986
- IM->>IM: Resource Validation
987
- alt Request Blocked
988
- IM->>Log: 📊 Log Blocked Request
989
- IM->>App: GuardrailError
990
- else Request Approved
991
- IM->>SDK: Validated Request
992
- SDK->>AI: API Call
993
- AI->>SDK: Raw Response
994
- SDK->>OM: Process Response
995
- OM->>OM: 🛡️ Quality Validation
996
- alt Quality Issues
997
- OM->>Log: 📊 Log Quality Issues
998
- OM->>App: ⚠️ Filtered Response
999
- else High Quality
1000
- OM->>App: Clean Response
1001
- end
1002
- end
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
- This architecture ensures that:
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
- We welcome contributions! Please open issues and pull requests on [GitHub](https://github.com/jagreehal/ai-sdk-guardrails).
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.