ai-sdk-guardrails 1.0.0 → 2.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,84 +1,74 @@
1
1
  # AI SDK Guardrails
2
2
 
3
- The safest way to build production AI applications with the Vercel AI SDK. A comprehensive TypeScript library that protects your AI systems with intelligent input and output validation, streaming safety, and enterprise-grade reliability.
3
+ Stop unnecessary AI calls. Optimize performance, improve quality, and prevent inappropriate AI responses with intelligent middleware for the Vercel AI SDK.
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
6
6
  [![Downloads](https://img.shields.io/npm/dm/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
 
10
- ## Why AI SDK Guardrails?
10
+ ## Requirements
11
11
 
12
- Building AI applications is exciting, but deploying them safely in production requires careful consideration. This library provides the safety net you need without sacrificing developer experience or performance.
12
+ This library requires the Vercel AI SDK (v5 and above) for its composable middleware architecture:
13
13
 
14
- ### 🛡️ Complete Protection
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:
15
21
 
16
- Validate inputs before they reach your model and outputs before they reach users. Catch harmful content, PII, prompt injections, and more.
22
+ ![Guardrails](./media/guardrail-example.gif)
17
23
 
18
- ### ⚡ Real-time Streaming Safety
24
+ ### ⚡ **Optimize API Usage**
19
25
 
20
- The only guardrails library with true streaming support. Monitor and stop streams in real-time when safety violations occur.
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.
21
27
 
22
- ### 🎯 Built for Vercel AI SDK
28
+ ### 🎯 **Improve Response Quality**
23
29
 
24
- First-class support for all AI SDK functions: `generateText`, `generateObject`, `streamText`, `streamObject`, and `embed`.
30
+ Ensure every AI response meets your standards. Filter out hallucinations, check factuality, enforce formatting requirements, and maintain consistent quality across your application.
25
31
 
26
- ### 🔧 Developer Friendly
32
+ ### 🛡️ **Prevent Embarrassing Responses**
27
33
 
28
- Simple API with TypeScript autocompletion, helpful error messages, and sensible defaults. Start safe in minutes, not hours.
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.
35
+
36
+ ### ⚡ **Focus AI Generations**
37
+
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.
29
39
 
30
40
  ## How It Works
31
41
 
42
+ ### Without Guardrails (Inefficient, Poor Quality)
43
+
32
44
  ```mermaid
33
- graph TB
34
- A[User Input] --> B{Input Guardrails}
35
- B -->|✅ Pass| C[AI Model]
36
- B -->|❌ Block| D[GuardrailError]
37
-
38
- C --> E[AI Response]
39
- E --> F{Output Guardrails}
40
- F -->|✅ Pass| G[Safe Response]
41
- F -->|❌ Block| H[GuardrailError]
42
-
43
- subgraph "Input Guardrails"
44
- I1[Length Limit]
45
- I2[Blocked Keywords]
46
- I3[PII Detection]
47
- I4[Prompt Injection]
48
- I5[Rate Limiting]
49
- end
45
+ flowchart LR
46
+ A[User Input<br/>'hello'] --> B[AI Model] --> C[Response<br/>⚠️ Wastes resources<br/>😞 Often useless]
47
+ ```
50
48
 
51
- subgraph "Output Guardrails"
52
- O1[Quality Check]
53
- O2[Toxicity Filter]
54
- O3[Privacy Leakage]
55
- O4[Schema Validation]
56
- O5[Confidence Threshold]
57
- end
49
+ ### With Input Guardrails (Save Resources)
50
+
51
+ ```mermaid
52
+ flowchart LR
53
+ A[User Input<br/>'hello'] --> B[Input Guardrails] --> C[❌ STOPPED<br/>✅ No API call made]
54
+ ```
55
+
56
+ ### With Output Guardrails (Ensure Quality)
58
57
 
59
- B -.-> I1
60
- B -.-> I2
61
- B -.-> I3
62
- B -.-> I4
63
- B -.-> I5
64
-
65
- F -.-> O1
66
- F -.-> O2
67
- F -.-> O3
68
- F -.-> O4
69
- F -.-> O5
70
-
71
- classDef inputNode fill:#e1f5fe
72
- classDef outputNode fill:#f3e5f5
73
- classDef blockNode fill:#ffebee
74
- classDef passNode fill:#e8f5e8
75
-
76
- class I1,I2,I3,I4,I5 inputNode
77
- class O1,O2,O3,O4,O5 outputNode
78
- class D,H blockNode
79
- class G passNode
58
+ ```mermaid
59
+ flowchart LR
60
+ A[AI Response<br/>'Here's my SSN: 123-45-6789'] --> B[Output Guardrails] --> C[❌ BLOCKED<br/>🛡️ Privacy protected]
61
+ ```
62
+
63
+ ### Complete Protection
64
+
65
+ ```mermaid
66
+ flowchart LR
67
+ A[User Input] --> B[Input Guardrails] --> C[AI Model] --> D[Output Guardrails] --> E[Clean Response]
80
68
  ```
81
69
 
70
+ That's it! Input guardrails optimize resource usage by stopping inefficient requests. Output guardrails ensure quality by filtering responses.
71
+
82
72
  ## Installation
83
73
 
84
74
  ```bash
@@ -91,639 +81,938 @@ yarn add ai-sdk-guardrails
91
81
 
92
82
  ## Quick Start
93
83
 
94
- Get started with production-ready guardrails in just a few lines:
84
+ Add smart validation to your AI applications in just 3 steps:
85
+
86
+ ### 1. Prevent Unnecessary AI Calls
95
87
 
96
88
  ```typescript
97
- import { generateTextWithGuardrails } from 'ai-sdk-guardrails';
98
- import { blockedKeywords } from 'ai-sdk-guardrails/guardrails/input';
99
- import { outputLengthLimit } from 'ai-sdk-guardrails/guardrails/output';
89
+ import { generateText, wrapLanguageModel } from 'ai';
100
90
  import { openai } from '@ai-sdk/openai';
91
+ import { createInputGuardrailsMiddleware } from 'ai-sdk-guardrails';
92
+ import { blockedKeywords } from 'ai-sdk-guardrails/guardrails/input';
101
93
 
102
- const result = await generateTextWithGuardrails(
103
- {
104
- model: openai('gpt-4-turbo'),
105
- prompt: 'Write a helpful response about web security',
106
- },
107
- {
108
- inputGuardrails: [blockedKeywords(['hack', 'exploit', 'vulnerability'])],
109
- outputGuardrails: [outputLengthLimit(500)],
110
- },
111
- );
94
+ // 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
+ ],
102
+ });
103
+
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
108
+ });
109
+ // → Throws GuardrailError: "Blocked keyword detected: hello"
112
110
 
113
- console.log(result.text);
111
+ // This generates valuable content
112
+ const goodResult = await generateText({
113
+ model: optimizedModel,
114
+ prompt: 'Write a product description for our new software', // ✅ This creates value
115
+ });
114
116
  ```
115
117
 
116
- ## Core Concepts
118
+ ### 2. Ensure Quality Output
117
119
 
118
- ### Input Guardrails
120
+ ```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
+ ],
140
+ });
119
141
 
120
- Input guardrails validate prompts before they reach your AI model. Use them to:
142
+ const result = await generateText({
143
+ model: qualityModel,
144
+ prompt: 'Create a user profile example',
145
+ });
146
+ // 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
+ ```
121
150
 
122
- - Block harmful or inappropriate content
123
- - Enforce length limits
124
- - Detect prompt injection attempts
125
- - Remove personally identifiable information (PII)
126
- - Implement rate limiting
151
+ ### 3. Custom Business Logic
127
152
 
128
153
  ```typescript
129
- import { createInputGuardrail } from 'ai-sdk-guardrails';
130
-
131
- const mathHomeworkDetector = createInputGuardrail(
132
- 'math-homework-detector',
133
- 'Prevents direct homework solving requests',
134
- (context) => {
135
- const { prompt } = context;
136
- const homeworkPatterns = [
137
- /solve this equation/i,
138
- /what is \d+ [\+\-\*\/] \d+/i,
139
- /calculate the answer/i,
140
- ];
154
+ import { defineInputGuardrail } from 'ai-sdk-guardrails';
155
+ import { extractTextContent } from 'ai-sdk-guardrails/guardrails/input';
141
156
 
142
- const isHomework = homeworkPatterns.some((pattern) =>
143
- pattern.test(prompt || ''),
144
- );
157
+ // Prevent inefficient homework help requests
158
+ const homeworkDetector = defineInputGuardrail({
159
+ name: 'homework-detector',
160
+ execute: async (context) => {
161
+ const { prompt } = extractTextContent(context);
145
162
 
146
- return {
147
- tripwireTriggered: isHomework,
148
- message: isHomework ? 'Direct homework solving detected' : undefined,
149
- suggestion: isHomework
150
- ? 'Try asking about the concepts instead'
151
- : undefined,
152
- };
163
+ if (prompt.includes('solve this equation') || prompt.includes('homework')) {
164
+ return {
165
+ tripwireTriggered: true,
166
+ message: 'Homework help blocked - prevents inefficient API usage',
167
+ suggestion: 'Ask about learning concepts instead',
168
+ };
169
+ }
170
+
171
+ return { tripwireTriggered: false };
153
172
  },
154
- );
173
+ });
174
+
175
+ const smartEducationModel = wrapLanguageModel({
176
+ model: openai('gpt-4'),
177
+ middleware: [
178
+ createInputGuardrailsMiddleware({
179
+ inputGuardrails: [homeworkDetector],
180
+ }),
181
+ ],
182
+ });
155
183
  ```
156
184
 
157
- ### Output Guardrails
185
+ **That's it!** Your AI application now optimizes resource usage, ensures quality, and prevents inappropriate responses automatically.
158
186
 
159
- Output guardrails validate AI responses before they reach users. Use them to:
187
+ ### Smart API Optimization Strategy
160
188
 
161
- - Ensure response quality
162
- - Block sensitive information
163
- - Enforce formatting requirements
164
- - Validate against schemas
165
- - Check confidence levels
189
+ Build intelligent resource management by combining multiple validation layers:
166
190
 
167
191
  ```typescript
168
- import { createOutputGuardrail } from 'ai-sdk-guardrails';
169
-
170
- const sensitiveInfoFilter = createOutputGuardrail(
171
- 'sensitive-info-filter',
172
- (context) => {
173
- const { text } = context.result;
174
- const sensitivePatterns = [
175
- /password:\s*\w+/i,
176
- /api[_-]?key:\s*\w+/i,
177
- /\b\d{3}-\d{2}-\d{4}\b/, // SSN format
178
- ];
179
-
180
- const hasSensitive = sensitivePatterns.some((pattern) =>
181
- pattern.test(text || ''),
182
- );
183
-
184
- return {
185
- tripwireTriggered: hasSensitive,
186
- message: hasSensitive
187
- ? 'Response contains sensitive information'
188
- : undefined,
189
- severity: hasSensitive ? 'critical' : 'low',
190
- };
191
- },
192
- );
193
- ```
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
+ ];
194
250
 
195
- ### Streaming Guardrails
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
+ }
196
276
 
197
- Protect streaming responses in real-time. The stream automatically stops if guardrails detect violations:
277
+ return { tripwireTriggered: false };
278
+ },
279
+ }),
280
+ ];
198
281
 
199
- ```typescript
200
- import { streamTextWithGuardrails } from 'ai-sdk-guardrails';
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
+ );
300
+ },
301
+ }),
302
+ ],
303
+ });
201
304
 
202
- const stream = await streamTextWithGuardrails(
203
- {
204
- model: openai('gpt-4-turbo'),
205
- prompt: 'Generate a long story...',
206
- },
207
- {
208
- outputGuardrails: [
209
- outputLengthLimit(1000),
210
- blockedOutputContent(['inappropriate', 'offensive']),
211
- ],
212
- onOutputBlocked: (error) => {
213
- console.error('Stream blocked:', error.reason);
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,
214
315
  },
215
316
  },
216
- );
217
-
218
- // The stream will automatically stop if guardrails trigger
219
- for await (const chunk of stream.textStream) {
220
- process.stdout.write(chunk);
221
- }
317
+ });
222
318
  ```
223
319
 
224
- ## Built-in Guardrails
320
+ ## Error Handling and Response Strategies
225
321
 
226
- ### Input Guardrails
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:
227
323
 
228
- ```typescript
229
- import {
230
- lengthLimit,
231
- blockedWords,
232
- blockedKeywords,
233
- profanityFilter,
234
- promptInjectionDetector,
235
- piiDetector,
236
- toxicityDetector,
237
- mathHomeworkDetector,
238
- codeGenerationLimiter,
239
- } from 'ai-sdk-guardrails/guardrails/input';
324
+ ### Middleware Flow and Decision Points
240
325
 
241
- // Content filters
242
- const contentGuardrails = [
243
- lengthLimit(1000),
244
- blockedWords(['spam', 'hack']),
245
- profanityFilter(['custom', 'words']),
246
- toxicityDetector(0.7), // threshold
247
- ];
326
+ ```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
+ ```
248
344
 
249
- // Security guardrails
250
- const securityGuardrails = [promptInjectionDetector(), piiDetector()];
345
+ The diagram shows two key decision points where your error handling strategies activate:
251
346
 
252
- // Educational guardrails
253
- const educationGuardrails = [
254
- mathHomeworkDetector(),
255
- codeGenerationLimiter(['javascript', 'python']),
256
- ];
257
- ```
347
+ - **Input validation failures** → Trigger callbacks or throw errors
348
+ - **Output quality issues** → Filter responses and log concerns
258
349
 
259
- ### Output Guardrails
350
+ Here's how to implement proper error handling for each scenario:
260
351
 
261
- ```typescript
262
- import {
263
- lengthLimit,
264
- blockedContent,
265
- jsonValidation,
266
- confidenceThreshold,
267
- toxicityFilter,
268
- schemaValidation,
269
- tokenUsageLimit,
270
- performanceMonitor,
271
- hallucinationDetector,
272
- biasDetector,
273
- factualAccuracyChecker,
274
- privacyLeakageDetector,
275
- contentConsistencyChecker,
276
- complianceChecker,
277
- } from 'ai-sdk-guardrails/guardrails/output';
352
+ ### Input Guardrail Errors
278
353
 
279
- // Quality guardrails
280
- const qualityGuardrails = [
281
- lengthLimit(500),
282
- confidenceThreshold(0.8),
283
- hallucinationDetector(0.7),
284
- factualAccuracyChecker(true), // require sources
285
- ];
354
+ Input guardrails can either throw errors or trigger callbacks, depending on your configuration:
286
355
 
287
- // Safety guardrails
288
- const safetyGuardrails = [
289
- toxicityFilter(0.5),
290
- biasDetector(),
291
- privacyLeakageDetector(),
292
- complianceChecker(['GDPR', 'HIPAA']),
293
- ];
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
+ });
294
387
 
295
- // Performance guardrails
296
- const performanceGuardrails = [
297
- tokenUsageLimit(1000),
298
- performanceMonitor(5000), // max 5 seconds
299
- ];
388
+ try {
389
+ const result = await generateText({
390
+ model: protectedModel,
391
+ prompt: userInput,
392
+ });
393
+
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
+ }
300
406
  ```
301
407
 
302
- ## Integration with Autoevals
408
+ ### Output Guardrail Handling
303
409
 
304
- Use [Autoevals](https://github.com/braintrust-data/autoevals) for sophisticated AI quality evaluation as guardrails:
410
+ Output guardrails typically filter or modify responses rather than throwing errors:
305
411
 
306
412
  ```typescript
307
- import { Factuality, init } from 'autoevals';
308
- import { createOutputGuardrail } from 'ai-sdk-guardrails';
309
-
310
- function createFactualityGuardrail({
311
- expected,
312
- minScore,
313
- }: {
314
- expected: string;
315
- minScore: number;
316
- }) {
317
- return createOutputGuardrail('factuality-check', async (context) => {
318
- const { text } = extractContent(context.result);
319
- const { prompt } = extractTextContent(context.input);
320
-
321
- const evalResult = await Factuality({
322
- output: text,
323
- expected,
324
- input: prompt || '',
325
- model: MODEL_NAME,
326
- });
327
-
328
- const isFactual = (evalResult.score || 0) >= minScore;
329
-
330
- return {
331
- tripwireTriggered: !isFactual,
332
- message: isFactual
333
- ? `Factual content (score: ${evalResult.score})`
334
- : `Factual accuracy too low (score: ${evalResult.score}, required: ${minScore})`,
335
- severity: isFactual ? 'low' : 'high',
336
- metadata: {
337
- factualityScore: evalResult.score,
338
- rationale: evalResult.metadata?.rationale,
339
- expected,
340
- minScore,
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
+ });
341
435
  },
342
- suggestion: isFactual
343
- ? undefined
344
- : 'Please provide more accurate information',
345
- };
346
- });
347
- }
348
-
349
- // Usage
350
- const result = await generateTextWithGuardrails(
351
- {
352
- model: openai('gpt-4-turbo'),
353
- prompt: 'Which country has the highest population?',
354
- },
355
- {
356
- outputGuardrails: [
357
- createFactualityGuardrail({
358
- expected: 'China',
359
- minScore: 0.7,
360
- }),
361
- ],
362
- },
363
- );
436
+ }),
437
+ ],
438
+ });
364
439
  ```
365
440
 
366
- ## Error Handling
441
+ ### User-Friendly Error Messages
367
442
 
368
- Guardrails provide rich error information to help you handle violations gracefully:
443
+ Transform technical guardrail messages into user-friendly guidance:
369
444
 
370
445
  ```typescript
371
- import { GuardrailError } from 'ai-sdk-guardrails';
446
+ function createUserFriendlyMessage(guardrailResult: GuardrailResult): string {
447
+ const guardrailName = guardrailResult.context?.guardrailName;
372
448
 
373
- try {
374
- const result = await generateTextWithGuardrails(params, guardrails);
375
- } catch (error) {
376
- if (error instanceof GuardrailError) {
377
- // Access detailed error information
378
- console.log('Guardrail triggered:', error.guardrailName);
379
- console.log('Reason:', error.reason);
380
- console.log('Type:', error.type); // 'input' or 'output'
381
-
382
- // Get all issues
383
- error.issues.forEach((issue) => {
384
- console.log(`${issue.guardrail}: ${issue.message}`);
385
- console.log('Severity:', issue.severity);
386
- console.log('Suggestion:', issue.suggestion);
387
- });
388
-
389
- // Use helper methods
390
- const summary = error.getSummary();
391
- console.log(`Total issues: ${summary.totalIssues}`);
392
- console.log(
393
- `Guardrails triggered: ${summary.guardrailsTriggered.join(', ')}`,
394
- );
395
- }
396
- }
397
- ```
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.';
398
452
 
399
- ## Advanced Usage
453
+ case 'blocked-keywords':
454
+ return "I can't help with that topic. Try asking about something else I can assist with.";
400
455
 
401
- ### Custom Validation Logic
456
+ case 'rate-limit':
457
+ return "You're sending requests too quickly. Please wait a moment before trying again.";
402
458
 
403
- Create sophisticated guardrails for your specific needs:
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!";
404
461
 
405
- ```typescript
406
- const businessLogicGuardrail = createInputGuardrail(
407
- 'business-logic-validator',
408
- 'Ensures requests meet business requirements',
409
- async (context) => {
410
- const { prompt, messages } = context;
411
-
412
- // Implement your custom logic
413
- const validationResult = await validateBusinessRules({
414
- content: prompt,
415
- history: messages,
416
- });
417
-
418
- return {
419
- tripwireTriggered: !validationResult.isValid,
420
- message: validationResult.error,
421
- metadata: validationResult.details,
422
- severity: validationResult.severity,
423
- suggestion: validationResult.suggestion,
424
- };
425
- },
426
- );
462
+ default:
463
+ return (
464
+ guardrailResult.suggestion ||
465
+ 'Please refine your request and try again.'
466
+ );
467
+ }
468
+ }
427
469
  ```
428
470
 
429
- ### Composing Guardrails
471
+ ### Best Practices for Error Handling
430
472
 
431
- Combine multiple guardrail configurations for different scenarios:
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
432
479
 
433
- ```typescript
434
- // Development guardrails (more lenient)
435
- const devGuardrails = {
436
- inputGuardrails: [lengthLimit(2000)],
437
- throwOnBlocked: false,
438
- onInputBlocked: (error) => console.warn('Dev warning:', error),
439
- };
440
-
441
- // Production guardrails (strict)
442
- const prodGuardrails = {
443
- inputGuardrails: [lengthLimit(500), blockedKeywords(['test', 'debug'])],
444
- outputGuardrails: [confidenceThreshold(0.9), complianceChecker(['GDPR'])],
445
- throwOnBlocked: true,
446
- };
447
-
448
- // Use based on environment
449
- const guardrails =
450
- process.env.NODE_ENV === 'production' ? prodGuardrails : devGuardrails;
451
- ```
480
+ ## Understanding the Benefits
452
481
 
453
- ### Object Generation with Schema Validation
482
+ ### Resource Optimization Through Input Validation
454
483
 
455
- Validate structured outputs with custom business logic:
484
+ Input guardrails act as intelligent gatekeepers that prevent inefficient API calls that would likely fail or provide little value:
456
485
 
457
486
  ```typescript
458
- import { z } from 'zod';
487
+ import { defineInputGuardrail } from 'ai-sdk-guardrails';
488
+ import { extractTextContent } from 'ai-sdk-guardrails/guardrails/input';
489
+
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',
494
+ execute: async (context) => {
495
+ const { prompt } = extractTextContent(context);
496
+
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
+ ];
459
504
 
460
- const userSchema = z.object({
461
- name: z.string(),
462
- age: z.number().min(0).max(120),
463
- email: z.string().email(),
464
- });
505
+ const foundWaste = timeWasters.find((pattern) =>
506
+ pattern.test(prompt || ''),
507
+ );
508
+ if (foundWaste) {
509
+ return {
510
+ tripwireTriggered: true,
511
+ message: `Blocked time-wasting request - prevented unnecessary API call`,
512
+ severity: 'medium',
513
+ metadata: {
514
+ pattern: foundWaste.source,
515
+ api_calls_prevented: 1,
516
+ },
517
+ };
518
+ }
465
519
 
466
- const schemaValidator = createOutputGuardrail(
467
- 'schema-validator',
468
- async (context) => {
469
- const { object } = extractContent(context.result);
470
- try {
471
- userSchema.parse(object);
472
- return { tripwireTriggered: false };
473
- } catch (error) {
520
+ // Block requests that often exceed token limits
521
+ if (prompt && prompt.length > 12000) {
474
522
  return {
475
523
  tripwireTriggered: true,
476
- message: 'Schema validation failed',
524
+ message:
525
+ 'Request likely to exceed token limits - preventing API failure',
477
526
  severity: 'high',
478
- metadata: { validationError: error.message },
527
+ suggestion:
528
+ 'Break into smaller, focused requests for better results and efficiency',
479
529
  };
480
530
  }
481
- },
482
- );
483
531
 
484
- const result = await generateObjectWithGuardrails(
485
- {
486
- model: openai('gpt-4-turbo'),
487
- prompt: 'Create a user profile for John Doe, age 30',
488
- schema: userSchema,
489
- },
490
- {
491
- outputGuardrails: [schemaValidator],
532
+ return { tripwireTriggered: false };
492
533
  },
493
- );
534
+ });
494
535
  ```
495
536
 
496
- ## Best Practices
497
-
498
- ### 1. Layer Your Defence
537
+ ### Quality Assurance Through Output Validation
499
538
 
500
- Use multiple guardrails for comprehensive protection:
539
+ Output guardrails ensure every response meets your quality standards before reaching users:
501
540
 
502
541
  ```typescript
503
- const guardrails = {
504
- inputGuardrails: [
505
- // First line: Block obvious threats
506
- promptInjectionDetector(),
507
- blockedKeywords(['malicious', 'exploit']),
508
-
509
- // Second line: Quality control
510
- lengthLimit(1000),
542
+ import { defineOutputGuardrail } from 'ai-sdk-guardrails';
543
+ import { extractContent } from 'ai-sdk-guardrails/guardrails/output';
544
+
545
+ // Ensure responses are professional and useful
546
+ const professionalQualityGuardrail = defineOutputGuardrail({
547
+ name: 'professional-quality-control',
548
+ description: 'Ensures responses meet professional standards',
549
+ execute: async (context) => {
550
+ const { text } = extractContent(context.result);
511
551
 
512
- // Third line: Business logic
513
- customBusinessRules(),
514
- ],
515
- outputGuardrails: [
516
- // Ensure quality
517
- confidenceThreshold(0.7),
552
+ const qualityIssues = [];
518
553
 
519
- // Ensure safety
520
- toxicityFilter(),
521
- privacyLeakageDetector(),
522
- ],
523
- };
524
- ```
554
+ // Check for unprofessional language
555
+ const unprofessionalTerms = ['lol', 'wtf', 'omg', 'ur', 'u r'];
556
+ const hasUnprofessional = unprofessionalTerms.some((term) =>
557
+ text.toLowerCase().includes(term),
558
+ );
525
559
 
526
- ### 2. Handle Errors Gracefully
560
+ if (hasUnprofessional) {
561
+ qualityIssues.push('Contains unprofessional language');
562
+ }
527
563
 
528
- Provide helpful feedback when guardrails trigger:
564
+ // Check for placeholder text that indicates incomplete response
565
+ const placeholders = ['[insert', '[add', '[your', 'TODO:', 'FIXME:'];
566
+ const hasPlaceholders = placeholders.some((placeholder) =>
567
+ text.includes(placeholder),
568
+ );
529
569
 
530
- ```typescript
531
- onInputBlocked: (error) => {
532
- // Map technical errors to user-friendly messages
533
- const userMessage =
534
- {
535
- 'content-length-limit': 'Your message is too long. Please shorten it.',
536
- 'blocked-keywords': 'Your request contains restricted content.',
537
- 'pii-detector': 'Please remove personal information from your request.',
538
- }[error.guardrailName] || 'Your request could not be processed.';
539
-
540
- return userMessage;
541
- };
542
- ```
570
+ if (hasPlaceholders) {
571
+ qualityIssues.push('Contains placeholder text - incomplete response');
572
+ }
543
573
 
544
- ### 3. **Publishing Process (Using Changesets)**
574
+ // Check for excessive repetition
575
+ const sentences = text.split(/[.!?]+/).filter((s) => s.trim());
576
+ const uniqueSentences = new Set(
577
+ sentences.map((s) => s.trim().toLowerCase()),
578
+ );
579
+ const repetitionRatio = uniqueSentences.size / sentences.length;
545
580
 
546
- You're already set up with **Changesets** which is the recommended approach. Here's the process:
581
+ if (sentences.length > 3 && repetitionRatio < 0.6) {
582
+ qualityIssues.push('Excessive repetition detected');
583
+ }
547
584
 
548
- #### **Step 1: Create a Changeset**
585
+ if (qualityIssues.length > 0) {
586
+ return {
587
+ tripwireTriggered: true,
588
+ message: `Quality issues found: ${qualityIssues.join(', ')}`,
589
+ severity: 'medium',
590
+ suggestion: 'Request a more professional, complete response',
591
+ metadata: {
592
+ issues: qualityIssues,
593
+ quality_score: repetitionRatio,
594
+ },
595
+ };
596
+ }
549
597
 
550
- ```bash
551
- npx changeset
598
+ return { tripwireTriggered: false };
599
+ },
600
+ });
552
601
  ```
553
602
 
554
- This will:
603
+ ### Streaming Intelligence: Real-Time Quality Control
555
604
 
556
- - Ask you what type of change (patch/minor/major)
557
- - Let you write a summary of changes
558
- - Create a changeset file
605
+ For streaming responses, maintain quality while preserving the real-time experience:
559
606
 
560
- #### **Step 2: Version and Publish**
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
+ ```
561
627
 
562
- You have two options:
628
+ ```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';
563
635
 
564
- **Option A: Manual Control**
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);
565
642
 
566
- ```bash
567
- # 1. Run CI to ensure everything passes
568
- npm run ci
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
+ };
569
651
 
570
- # 2. Version the package (reads changesets and updates version)
571
- npx changeset version
652
+ const issues = Object.entries(qualityMetrics)
653
+ .filter(([_, passed]) => !passed)
654
+ .map(([metric, _]) => metric);
572
655
 
573
- # 3. Publish to npm
574
- npx changeset publish
575
- ```
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
+ }
667
+
668
+ return { tripwireTriggered: false };
669
+ },
670
+ });
576
671
 
577
- **Option B: Use Your Local Release Script**
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
+ }
578
678
 
579
- ```bash
580
- npm run local-release
581
- ```
679
+ function containsInappropriateContent(text: string): boolean {
680
+ const inappropriate = ['inappropriate', 'offensive', 'harmful'];
681
+ return inappropriate.some((term) => text.toLowerCase().includes(term));
682
+ }
582
683
 
583
- This runs: `npm run ci && changeset version && changeset publish`
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
+ }
584
693
 
585
- ### 4. **First Release Steps**
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
+ });
586
707
 
587
- For your first release, I recommend:
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
+ });
588
714
 
589
- 1. **Fix any remaining issues** (like the prettier formatting):
715
+ // Users see real-time streaming
716
+ for await (const chunk of enhancedStream.textStream) {
717
+ process.stdout.write(chunk);
718
+ }
590
719
 
591
- ```bash
592
- npm run format
720
+ // Quality analysis happens post-stream for continuous improvement
721
+ console.log('\nStream completed with quality monitoring');
593
722
  ```
594
723
 
595
- 2. **Create your first changeset**:
724
+ ## Production-Ready Performance and Quality Controls
596
725
 
597
- ```bash
598
- npx changeset
726
+ ### Smart Input Filtering
727
+
728
+ Access comprehensive input validation that optimizes performance while maintaining user experience:
729
+
730
+ ```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
+ ];
599
766
  ```
600
767
 
601
- - Select "major" (since this is 0.0.1 → 1.0.0)
602
- - Write: "Initial release of AI SDK Guardrails"
768
+ ### Advanced Output Quality Assurance
603
769
 
604
- 3. **Release it**:
770
+ Choose from sophisticated output validation that ensures professional results:
605
771
 
606
- ```bash
607
- npm run local-release
772
+ ```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
+ ];
608
810
  ```
609
811
 
610
- ### 5. **Package Name Assessment**
812
+ ## Complete AI SDK Integration
611
813
 
612
- **✅ `ai-sdk-guardrails` is excellent because:**
814
+ The library seamlessly integrates with all AI SDK functions through the middleware architecture:
613
815
 
614
- - Available on npm
615
- - Descriptive and searchable
616
- - Follows naming conventions
617
- - Clearly indicates it's for AI SDK
618
- - Professional sounding
816
+ ```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
+ ],
828
+ });
619
829
 
620
- ### 6. **Additional Recommendations**
830
+ // Use with any AI SDK function - same optimization and quality everywhere
831
+ const textResult = await generateText({
832
+ model: productionModel,
833
+ prompt: 'Write a professional email response',
834
+ experimental_telemetry: {
835
+ isEnabled: true,
836
+ functionId: 'performance-optimized-text',
837
+ metadata: { optimization: 'performance+quality' },
838
+ },
839
+ });
621
840
 
622
- Consider these npm badges for your README:
841
+ const objectResult = await generateObject({
842
+ model: productionModel,
843
+ prompt: 'Create a user profile',
844
+ schema: userProfileSchema,
845
+ experimental_telemetry: {
846
+ isEnabled: true,
847
+ functionId: 'performance-optimized-object',
848
+ metadata: { optimization: 'performance+quality' },
849
+ },
850
+ });
623
851
 
624
- ```markdown
625
- <code_block_to_apply_changes_from>
626
- [![npm version](https://badge.fury.io/js/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
627
- [![Downloads](https://img.shields.io/npm/dm/ai-sdk-guardrails.svg)](https://www.npmjs.com/package/ai-sdk-guardrails)
852
+ const textStream = await streamText({
853
+ model: productionModel,
854
+ prompt: 'Explain our product features',
855
+ experimental_telemetry: {
856
+ isEnabled: true,
857
+ functionId: 'performance-optimized-stream',
858
+ metadata: { optimization: 'performance+quality' },
859
+ },
860
+ });
628
861
  ```
629
862
 
630
- ### 7. **GitHub Release Integration**
863
+ ## Examples
631
864
 
632
- After publishing to npm, you might want to:
865
+ Explore focused examples that demonstrate practical performance optimization and quality assurance:
633
866
 
634
- - Create GitHub releases that match your npm versions
635
- - Set up GitHub Actions for automated publishing (optional)
867
+ ### Core Examples
636
868
 
637
- **Would you like me to help you run through the first release process now?**
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
638
873
 
639
- ## All AI SDK Functions Supported
874
+ ### Additional Examples
640
875
 
641
- The library provides guarded versions of all AI SDK functions:
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
642
880
 
643
- ```typescript
644
- import {
645
- generateTextWithGuardrails,
646
- generateObjectWithGuardrails,
647
- streamTextWithGuardrails,
648
- streamObjectWithGuardrails,
649
- embedWithGuardrails,
650
- } from 'ai-sdk-guardrails';
881
+ ### Running Examples
651
882
 
652
- // Generate text with guardrails
653
- const textResult = await generateTextWithGuardrails(
654
- { model, prompt: 'Hello' },
655
- { inputGuardrails: [lengthLimit(100)] },
656
- );
657
-
658
- // Generate structured objects with guardrails
659
- const objectResult = await generateObjectWithGuardrails(
660
- { model, prompt: 'Create user', schema: userSchema },
661
- { outputGuardrails: [schemaValidation(userSchema)] },
662
- );
663
-
664
- // Stream text with real-time guardrails
665
- const textStream = await streamTextWithGuardrails(
666
- { model, prompt: 'Long response' },
667
- { outputGuardrails: [outputLengthLimit(1000)] },
668
- );
669
-
670
- // Stream objects with guardrails
671
- const objectStream = await streamObjectWithGuardrails(
672
- { model, prompt: 'Stream data', schema: dataSchema },
673
- { outputGuardrails: [schemaValidation(dataSchema)] },
674
- );
675
-
676
- // Embed with input validation
677
- const embedResult = await embedWithGuardrails(
678
- { model, value: 'Text to embed' },
679
- { inputGuardrails: [piiDetector()] },
680
- );
883
+ ```bash
884
+ # Install dependencies
885
+ pnpm install
886
+
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
892
+
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
681
896
  ```
682
897
 
683
- ## TypeScript Support
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.
684
899
 
685
- Full TypeScript support with intelligent type inference:
900
+ ## Architecture Overview
686
901
 
687
- ```typescript
688
- // Types are automatically inferred
689
- const result = await generateTextWithGuardrails(
690
- {
691
- model: openai('gpt-4-turbo'),
692
- prompt: 'Hello',
693
- },
694
- {
695
- inputGuardrails: [
696
- /* your guardrails */
697
- ],
698
- },
699
- );
902
+ The library leverages the Vercel AI SDK's middleware architecture to provide composable guardrails that integrate seamlessly with your existing AI applications:
700
903
 
701
- // result is fully typed as GenerateTextResult
702
- console.log(result.text);
703
- console.log(result.usage);
704
- console.log(result.finishReason);
904
+ ```mermaid
905
+ graph TB
906
+ subgraph "Your Application"
907
+ App[Your App Code]
908
+ Config[Guardrail Configuration]
909
+ end
910
+
911
+ subgraph "AI SDK Guardrails Middleware"
912
+ InputMW[Input Guardrails Middleware]
913
+ OutputMW[Output Guardrails Middleware]
914
+
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
922
+
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
931
+
932
+ subgraph "AI SDK Core"
933
+ Wrapper[wrapLanguageModel]
934
+ Generator[generateText/Object/Stream]
935
+ end
936
+
937
+ subgraph "External Services"
938
+ AI[AI Model Provider]
939
+ Log[Logging & Telemetry]
940
+ end
941
+
942
+ App --> Config
943
+ Config --> InputMW
944
+ InputMW --> Length
945
+ InputMW --> Spam
946
+ InputMW --> PII
947
+ InputMW --> Business
948
+ InputMW --> Custom1
949
+
950
+ InputMW -->|Valid Request| Wrapper
951
+ InputMW -->|Blocked Request| Log
952
+
953
+ Wrapper --> Generator
954
+ Generator --> AI
955
+ AI --> OutputMW
956
+
957
+ OutputMW --> Quality
958
+ OutputMW --> Sensitive
959
+ OutputMW --> Professional
960
+ OutputMW --> Factual
961
+ OutputMW --> Custom2
962
+
963
+ OutputMW -->|Clean Response| App
964
+ OutputMW -->|Quality Issues| Log
965
+
966
+ style InputMW fill:#e1f5fe
967
+ style OutputMW fill:#f3e5f5
968
+ style AI fill:#fff3e0
969
+ style App fill:#e8f5e8
705
970
  ```
706
971
 
707
- ## Examples
972
+ ### Middleware Execution Flow
708
973
 
709
- Explore our comprehensive examples that demonstrate real-world usage patterns:
974
+ The guardrails execute in a specific order to maximize efficiency and ensure quality:
710
975
 
711
- - **[Basic Guardrails](examples/basic-guardrails.ts)** - Simple input/output validation with math homework detection
712
- - **[Streaming Guardrails](examples/streaming-guardrails.ts)** - Real-time stream protection with content filtering
713
- - **[Object Guardrails](examples/object-guardrails.ts)** - Schema validation and custom object validation
714
- - **[Autoevals Integration](examples/autoevals-guardrails.ts)** - AI quality evaluation with factuality checking
715
- - **[Kitchen Sink](examples/kitchen-sink.ts)** - Advanced patterns, composition, and LLM-as-judge
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
1003
+ ```
716
1004
 
717
- Each example is fully functional and demonstrates different aspects of the library with practical use cases.
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
718
1011
 
719
1012
  ## Contributing
720
1013
 
721
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
1014
+ We welcome contributions! Please open issues and pull requests on [GitHub](https://github.com/jagreehal/ai-sdk-guardrails).
722
1015
 
723
1016
  ## License
724
1017
 
725
1018
  MIT © [Jag Reehal](https://github.com/jagreehal)
726
-
727
- ---
728
-
729
- Built with ❤️ for the AI community. Star the repo if you find it helpful!