ai-sdk-guardrails 3.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 +279 -35
- package/package.json +26 -20
- package/dist/chunk-HHQ3CIFN.js +0 -12
- package/dist/chunk-LLCOPUS6.js +0 -159
- package/dist/errors-BTTWMQEI.js +0 -24
- package/dist/guardrails/input.cjs +0 -493
- package/dist/guardrails/input.d.cts +0 -36
- package/dist/guardrails/input.d.ts +0 -36
- package/dist/guardrails/input.js +0 -453
- package/dist/guardrails/output.cjs +0 -698
- package/dist/guardrails/output.d.cts +0 -46
- package/dist/guardrails/output.d.ts +0 -46
- package/dist/guardrails/output.js +0 -654
- package/dist/index.cjs +0 -815
- package/dist/index.d.cts +0 -272
- package/dist/index.d.ts +0 -272
- package/dist/index.js +0 -607
- package/dist/types-B9h_0Gyl.d.cts +0 -121
- package/dist/types-B9h_0Gyl.d.ts +0 -121
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AI SDK Guardrails
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Middleware for the Vercel AI SDK that adds safety, quality control, and cost management to your AI applications by intercepting prompts and responses.
|
|
4
4
|
|
|
5
5
|
Block harmful inputs, filter low-quality outputs, and gain observability, all in just a few lines of code.
|
|
6
6
|
|
|
@@ -95,6 +95,10 @@ yarn add ai-sdk-guardrails
|
|
|
95
95
|
pnpm add ai-sdk-guardrails
|
|
96
96
|
```
|
|
97
97
|
|
|
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
|
+
|
|
98
102
|
## 🚀 Quick Start
|
|
99
103
|
|
|
100
104
|
Add smart validation to your AI applications in just 3 steps:
|
|
@@ -193,8 +197,16 @@ const qualityGuard = defineOutputGuardrail({
|
|
|
193
197
|
|
|
194
198
|
const qualityModel = wrapWithOutputGuardrails(openai('gpt-4'), {
|
|
195
199
|
outputGuardrails: [qualityGuard],
|
|
196
|
-
onOutputBlocked: (
|
|
197
|
-
console.log(
|
|
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
|
+
);
|
|
198
210
|
},
|
|
199
211
|
});
|
|
200
212
|
|
|
@@ -230,17 +242,95 @@ const smartEducationModel = wrapWithInputGuardrails(openai('gpt-4'), {
|
|
|
230
242
|
});
|
|
231
243
|
```
|
|
232
244
|
|
|
233
|
-
|
|
245
|
+
### 4. Type-Safe Metadata (TypeScript)
|
|
246
|
+
|
|
247
|
+
The library automatically infers metadata types from your guardrail definitions - no manual type annotations needed!
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
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
|
+
}
|
|
255
|
+
|
|
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',
|
|
267
|
+
},
|
|
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
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
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
|
+
}
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**That's it!** Your AI application now optimizes resource usage, ensures quality, prevents inappropriate responses, and provides full type safety automatically.
|
|
234
315
|
|
|
235
316
|
## ✨ Features
|
|
236
317
|
|
|
237
318
|
- 🛡️ **Input & Output Guardrails**: Enforce custom safety, compliance, and quality policies on both prompts and LLM responses.
|
|
238
319
|
- 💰 **Cost Control**: Block invalid or wasteful prompts before they are sent to your LLM provider, saving you money.
|
|
239
320
|
- 🎯 **Quality Improvement**: Automatically filter, flag, or retry low-quality or irrelevant model outputs.
|
|
240
|
-
-
|
|
241
|
-
-
|
|
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.
|
|
242
325
|
- ⚙️ **Configurable Execution**: Run guardrails in parallel or sequentially and set custom timeouts.
|
|
243
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.
|
|
244
334
|
|
|
245
335
|
## 📚 API Overview
|
|
246
336
|
|
|
@@ -251,13 +341,13 @@ const smartEducationModel = wrapWithInputGuardrails(openai('gpt-4'), {
|
|
|
251
341
|
| `wrapWithGuardrails()` | ⭐ **Recommended** - The easiest way to add both input and output guardrails. |
|
|
252
342
|
| `wrapWithInputGuardrails()` | Attaches input-only guardrails to a model. |
|
|
253
343
|
| `wrapWithOutputGuardrails()` | Attaches output-only guardrails to a model. |
|
|
254
|
-
| `
|
|
344
|
+
| `isGuardrailsError()`, etc. | Error handling utilities and structured error types. |
|
|
255
345
|
|
|
256
346
|
## 🧠 Design Philosophy
|
|
257
347
|
|
|
258
348
|
- ✅ **Helper-First**: Simple, chainable utility functions provide a great developer experience for fast adoption.
|
|
259
349
|
- 🧩 **Composable**: Multiple guardrails can be chained together and will run in your specified order (or in parallel).
|
|
260
|
-
- 🧾 **Type-Safe**: Full TypeScript support with
|
|
350
|
+
- 🧾 **Type-Safe**: Full TypeScript support with automatic type inference for guardrail metadata - no manual type annotations needed!
|
|
261
351
|
- 🧪 **Sensible Defaults**: Get started quickly with zero-config default behaviors that can be easily overridden.
|
|
262
352
|
|
|
263
353
|
## Architecture Overview
|
|
@@ -495,7 +585,7 @@ const professionalQualityGuard = defineOutputGuardrail({
|
|
|
495
585
|
|
|
496
586
|
## 🔄 Streaming Support
|
|
497
587
|
|
|
498
|
-
Guardrails work with streams out-of-the-box.
|
|
588
|
+
Guardrails work with streams out-of-the-box. By default, output guardrails run after the complete response has been streamed (buffer mode).
|
|
499
589
|
|
|
500
590
|
```typescript
|
|
501
591
|
import { streamText } from 'ai';
|
|
@@ -517,6 +607,50 @@ for await (const delta of textStream) {
|
|
|
517
607
|
// The qualityJudge guardrail will run after the stream is complete.
|
|
518
608
|
```
|
|
519
609
|
|
|
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,
|
|
621
|
+
});
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
In progressive mode, guardrails evaluate text as it arrives. If blocked:
|
|
625
|
+
|
|
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`).
|
|
629
|
+
|
|
630
|
+
Note: Progressive mode runs guardrails more frequently and may increase overhead for long streams.
|
|
631
|
+
|
|
632
|
+
### Configuration Highlights
|
|
633
|
+
|
|
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.
|
|
637
|
+
|
|
638
|
+
### Cancellation Support
|
|
639
|
+
|
|
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
|
+
});
|
|
650
|
+
|
|
651
|
+
// Timeouts are enforced by guardrail execution; if it times out, you'll get a GuardrailTimeoutError.
|
|
652
|
+
```
|
|
653
|
+
|
|
520
654
|
## 🛠️ Error Handling
|
|
521
655
|
|
|
522
656
|
When `throwOnBlocked: true` (the default), you can catch structured errors to handle blocks gracefully.
|
|
@@ -579,11 +713,27 @@ const productionModel = wrapWithGuardrails(openai('gpt-4'), {
|
|
|
579
713
|
inputGuardrails: [lengthGuard, spamGuard, rateLimitGuard],
|
|
580
714
|
outputGuardrails: [qualityGuard, sensitiveInfoGuard],
|
|
581
715
|
throwOnBlocked: false,
|
|
582
|
-
onInputBlocked: (
|
|
583
|
-
console.log('Input blocked:',
|
|
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
|
+
);
|
|
584
724
|
},
|
|
585
|
-
onOutputBlocked: (
|
|
586
|
-
console.log(
|
|
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
|
+
});
|
|
587
737
|
},
|
|
588
738
|
});
|
|
589
739
|
|
|
@@ -607,21 +757,72 @@ const textStream = await streamText({
|
|
|
607
757
|
|
|
608
758
|
## Examples
|
|
609
759
|
|
|
610
|
-
Explore
|
|
760
|
+
Explore **30 comprehensive examples** that demonstrate practical performance optimization, security protection, quality assurance, and enterprise-grade safety patterns:
|
|
761
|
+
|
|
762
|
+
### Core Foundation Examples
|
|
763
|
+
|
|
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
|
|
771
|
+
|
|
772
|
+
### Security & Protection Examples
|
|
773
|
+
|
|
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
|
|
782
|
+
|
|
783
|
+
### Content Quality & Validation Examples
|
|
784
|
+
|
|
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
|
|
791
|
+
|
|
792
|
+
### Compliance & Regulation Examples
|
|
793
|
+
|
|
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
|
|
796
|
+
|
|
797
|
+
### Data Integrity & Code Safety Examples
|
|
611
798
|
|
|
612
|
-
|
|
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
|
|
613
802
|
|
|
614
|
-
|
|
615
|
-
- **[Basic Guardrails](examples/basic-guardrails.ts)** - Foundation patterns for input/output validation
|
|
616
|
-
- **[Business Logic](examples/business-logic.ts)** - Custom business rules, work hours, and professional standards
|
|
617
|
-
- **[LLM-as-Judge](examples/llm-as-judge.ts)** - AI-powered quality evaluation and scoring
|
|
803
|
+
### Network & External Access Examples
|
|
618
804
|
|
|
619
|
-
|
|
805
|
+
- **[Domain Allowlisting](examples/25-browsing-domain-allowlist.ts)** - Domain allowlisting with URL sanitization and security validation
|
|
620
806
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
- **[
|
|
624
|
-
- **[
|
|
807
|
+
### Privacy & Memory Management Examples
|
|
808
|
+
|
|
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
|
|
811
|
+
|
|
812
|
+
### Safety & Escalation Examples
|
|
813
|
+
|
|
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
|
|
816
|
+
|
|
817
|
+
### Streaming Examples
|
|
818
|
+
|
|
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
|
|
822
|
+
|
|
823
|
+
### Resource Management Examples
|
|
824
|
+
|
|
825
|
+
- **[Rate Limiting](examples/13-rate-limiting.ts)** - Smart rate limiting that prevents resource overuse
|
|
625
826
|
|
|
626
827
|
### Running Examples
|
|
627
828
|
|
|
@@ -629,19 +830,62 @@ Explore focused examples that demonstrate practical performance optimization and
|
|
|
629
830
|
# Install dependencies
|
|
630
831
|
pnpm install
|
|
631
832
|
|
|
632
|
-
#
|
|
633
|
-
tsx examples/
|
|
634
|
-
tsx examples/
|
|
635
|
-
tsx examples/
|
|
636
|
-
tsx examples/
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
tsx examples/
|
|
640
|
-
|
|
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
|
|
641
887
|
```
|
|
642
888
|
|
|
643
|
-
All examples feature interactive menus with arrow key navigation, multi-selection with checkboxes, and automatic return to the main menu.
|
|
644
|
-
|
|
645
889
|
## 🤝 Contributing
|
|
646
890
|
|
|
647
891
|
Contributions of all sizes are welcome! Please open issues and pull requests on [GitHub](https://github.com/jagreehal/ai-sdk-guardrails).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-sdk-guardrails",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Input and output guardrails middleware for Vercel AI SDK.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -49,47 +49,53 @@
|
|
|
49
49
|
"type": "module",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@ai-sdk/provider": "2.0.0",
|
|
52
|
-
"ai": "5.0.
|
|
53
|
-
"zod": "^4.
|
|
52
|
+
"ai": "5.0.25",
|
|
53
|
+
"zod": "^4.1.3"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@ai-sdk/mistral": "2.0.
|
|
57
|
-
"@ai-sdk/openai": "2.0.
|
|
56
|
+
"@ai-sdk/mistral": "2.0.12",
|
|
57
|
+
"@ai-sdk/openai": "2.0.22",
|
|
58
58
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
59
|
-
"@changesets/cli": "^2.29.
|
|
59
|
+
"@changesets/cli": "^2.29.6",
|
|
60
60
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
61
61
|
"@total-typescript/tsconfig": "^1.0.4",
|
|
62
62
|
"@types/eslint-config-prettier": "^6.11.3",
|
|
63
|
-
"@types/inquirer": "^9.0.
|
|
64
|
-
"@types/node": "^24.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"@typescript-eslint/parser": "^8.
|
|
67
|
-
"
|
|
63
|
+
"@types/inquirer": "^9.0.9",
|
|
64
|
+
"@types/node": "^24.3.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.41.0",
|
|
67
|
+
"@eslint/js": "^9.34.0",
|
|
68
|
+
"eslint": "^9.34.0",
|
|
69
|
+
"ai-sdk-ollama": "^0.5.2",
|
|
70
|
+
"autoevals": "^0.0.131",
|
|
68
71
|
"dotenv": "^17.2.1",
|
|
69
72
|
"eslint-config-prettier": "^10.1.8",
|
|
70
73
|
"eslint-plugin-unicorn": "^60.0.0",
|
|
71
|
-
"inquirer": "^12.9.
|
|
74
|
+
"inquirer": "^12.9.4",
|
|
72
75
|
"mathjs": "^14.6.0",
|
|
73
|
-
"ollama": "^0.5.
|
|
76
|
+
"ollama": "^0.5.17",
|
|
74
77
|
"ollama-ai-provider": "^1.2.0",
|
|
75
|
-
"openai": "^5.
|
|
78
|
+
"openai": "^5.15.0",
|
|
76
79
|
"prettier": "^3.6.2",
|
|
77
80
|
"tsup": "^8.5.0",
|
|
78
|
-
"
|
|
79
|
-
"typescript
|
|
81
|
+
"tsx": "^4.20.5",
|
|
82
|
+
"typescript": "^5.9.2",
|
|
83
|
+
"typescript-eslint": "^8.41.0",
|
|
80
84
|
"vitest": "^3.2.4"
|
|
81
85
|
},
|
|
82
86
|
"scripts": {
|
|
83
87
|
"build": "tsup",
|
|
84
|
-
"ci": "
|
|
85
|
-
"lint": "eslint src/**/*.ts",
|
|
88
|
+
"ci": "pnpm build && pnpm format:check && pnpm check-exports && pnpm lint && pnpm test",
|
|
89
|
+
"lint": "eslint src/**/*.ts examples/**/*.ts",
|
|
86
90
|
"lint:fix": "eslint src/**/*.ts --fix",
|
|
87
91
|
"format": "prettier --write .",
|
|
88
|
-
"format:check": "prettier --check src/**/*.ts",
|
|
92
|
+
"format:check": "prettier --check src/**/*.ts examples/**/*.ts",
|
|
89
93
|
"type-check": "tsc --noEmit",
|
|
90
94
|
"test": "vitest run",
|
|
91
95
|
"check-format": "prettier --check .",
|
|
92
96
|
"check-exports": "attw --pack . --ignore-rules false-esm no-resolution",
|
|
93
|
-
"local-release": "
|
|
97
|
+
"local-release": "pnpm build && pnpm format:check && pnpm check-exports && pnpm lint && pnpm test && changeset version && changeset publish",
|
|
98
|
+
"release": "changeset publish",
|
|
99
|
+
"quality": "pnpm lint && pnpm format && pnpm format:check && pnpm type-check"
|
|
94
100
|
}
|
|
95
101
|
}
|
package/dist/chunk-HHQ3CIFN.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// src/core.ts
|
|
2
|
-
function createInputGuardrail(name, description, execute) {
|
|
3
|
-
return { name, description, execute };
|
|
4
|
-
}
|
|
5
|
-
function createOutputGuardrail(name, execute) {
|
|
6
|
-
return { name, execute };
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
createInputGuardrail,
|
|
11
|
-
createOutputGuardrail
|
|
12
|
-
};
|
package/dist/chunk-LLCOPUS6.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
// src/errors.ts
|
|
2
|
-
var GuardrailsError = class extends Error {
|
|
3
|
-
timestamp;
|
|
4
|
-
metadata;
|
|
5
|
-
constructor(message, metadata = {}) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.timestamp = /* @__PURE__ */ new Date();
|
|
8
|
-
this.metadata = metadata;
|
|
9
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Convert the error to a serializable object for logging/reporting
|
|
13
|
-
*/
|
|
14
|
-
toJSON() {
|
|
15
|
-
return {
|
|
16
|
-
name: this.name,
|
|
17
|
-
code: this.code,
|
|
18
|
-
message: this.message,
|
|
19
|
-
timestamp: this.timestamp.toISOString(),
|
|
20
|
-
metadata: this.metadata,
|
|
21
|
-
stack: this.stack
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Check if this error is of a specific type
|
|
26
|
-
*/
|
|
27
|
-
is(errorClass) {
|
|
28
|
-
return this instanceof errorClass;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
var GuardrailValidationError = class extends GuardrailsError {
|
|
32
|
-
name = "GuardrailValidationError";
|
|
33
|
-
code = "GUARDRAIL_VALIDATION_FAILED";
|
|
34
|
-
guardrailName;
|
|
35
|
-
validationErrors;
|
|
36
|
-
constructor(guardrailName, validationErrors, metadata = {}) {
|
|
37
|
-
const message = `Guardrail "${guardrailName}" validation failed: ${validationErrors.map((e) => e.message).join(", ")}`;
|
|
38
|
-
super(message, { ...metadata, guardrailName, validationErrors });
|
|
39
|
-
this.guardrailName = guardrailName;
|
|
40
|
-
this.validationErrors = validationErrors;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
var GuardrailExecutionError = class extends GuardrailsError {
|
|
44
|
-
name = "GuardrailExecutionError";
|
|
45
|
-
code = "GUARDRAIL_EXECUTION_FAILED";
|
|
46
|
-
guardrailName;
|
|
47
|
-
originalError;
|
|
48
|
-
constructor(guardrailName, originalError, metadata = {}) {
|
|
49
|
-
const message = originalError ? `Guardrail "${guardrailName}" execution failed: ${originalError.message}` : `Guardrail "${guardrailName}" execution failed`;
|
|
50
|
-
super(message, {
|
|
51
|
-
...metadata,
|
|
52
|
-
guardrailName,
|
|
53
|
-
originalError: originalError?.message
|
|
54
|
-
});
|
|
55
|
-
this.guardrailName = guardrailName;
|
|
56
|
-
this.originalError = originalError;
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
var GuardrailTimeoutError = class extends GuardrailsError {
|
|
60
|
-
name = "GuardrailTimeoutError";
|
|
61
|
-
code = "GUARDRAIL_TIMEOUT";
|
|
62
|
-
guardrailName;
|
|
63
|
-
timeoutMs;
|
|
64
|
-
constructor(guardrailName, timeoutMs, metadata = {}) {
|
|
65
|
-
const message = `Guardrail "${guardrailName}" timed out after ${timeoutMs}ms`;
|
|
66
|
-
super(message, { ...metadata, guardrailName, timeoutMs });
|
|
67
|
-
this.guardrailName = guardrailName;
|
|
68
|
-
this.timeoutMs = timeoutMs;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
var GuardrailConfigurationError = class extends GuardrailsError {
|
|
72
|
-
name = "GuardrailConfigurationError";
|
|
73
|
-
code = "GUARDRAIL_CONFIG_INVALID";
|
|
74
|
-
configPath;
|
|
75
|
-
configErrors;
|
|
76
|
-
constructor(configErrors, configPath, metadata = {}) {
|
|
77
|
-
const message = `Guardrail configuration error${configPath ? ` in ${configPath}` : ""}: ${configErrors.join(", ")}`;
|
|
78
|
-
super(message, { ...metadata, configPath, configErrors });
|
|
79
|
-
this.configPath = configPath;
|
|
80
|
-
this.configErrors = configErrors;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
var InputBlockedError = class extends GuardrailsError {
|
|
84
|
-
name = "InputBlockedError";
|
|
85
|
-
code = "INPUT_BLOCKED";
|
|
86
|
-
blockedGuardrails;
|
|
87
|
-
constructor(blockedGuardrails, metadata = {}) {
|
|
88
|
-
const guardrailNames = blockedGuardrails.map((g) => g.name).join(", ");
|
|
89
|
-
const message = `Input blocked by guardrail${blockedGuardrails.length > 1 ? "s" : ""}: ${guardrailNames}`;
|
|
90
|
-
super(message, { ...metadata, blockedGuardrails });
|
|
91
|
-
this.blockedGuardrails = blockedGuardrails;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
var OutputBlockedError = class extends GuardrailsError {
|
|
95
|
-
name = "OutputBlockedError";
|
|
96
|
-
code = "OUTPUT_BLOCKED";
|
|
97
|
-
blockedGuardrails;
|
|
98
|
-
constructor(blockedGuardrails, metadata = {}) {
|
|
99
|
-
const guardrailNames = blockedGuardrails.map((g) => g.name).join(", ");
|
|
100
|
-
const message = `Output blocked by guardrail${blockedGuardrails.length > 1 ? "s" : ""}: ${guardrailNames}`;
|
|
101
|
-
super(message, { ...metadata, blockedGuardrails });
|
|
102
|
-
this.blockedGuardrails = blockedGuardrails;
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
var MiddlewareError = class extends GuardrailsError {
|
|
106
|
-
name = "MiddlewareError";
|
|
107
|
-
code = "MIDDLEWARE_ERROR";
|
|
108
|
-
middlewareType;
|
|
109
|
-
phase;
|
|
110
|
-
originalError;
|
|
111
|
-
constructor(middlewareType, phase, originalError, metadata = {}) {
|
|
112
|
-
const message = originalError ? `${middlewareType} middleware ${phase} error: ${originalError.message}` : `${middlewareType} middleware ${phase} error`;
|
|
113
|
-
super(message, {
|
|
114
|
-
...metadata,
|
|
115
|
-
middlewareType,
|
|
116
|
-
phase,
|
|
117
|
-
originalError: originalError?.message
|
|
118
|
-
});
|
|
119
|
-
this.middlewareType = middlewareType;
|
|
120
|
-
this.phase = phase;
|
|
121
|
-
this.originalError = originalError;
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
function isGuardrailsError(error) {
|
|
125
|
-
return error instanceof GuardrailsError;
|
|
126
|
-
}
|
|
127
|
-
function extractErrorInfo(error) {
|
|
128
|
-
if (isGuardrailsError(error)) {
|
|
129
|
-
return {
|
|
130
|
-
name: error.name,
|
|
131
|
-
message: error.message,
|
|
132
|
-
code: error.code,
|
|
133
|
-
metadata: error.metadata
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
if (error instanceof Error) {
|
|
137
|
-
return {
|
|
138
|
-
name: error.name,
|
|
139
|
-
message: error.message
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
return {
|
|
143
|
-
name: "UnknownError",
|
|
144
|
-
message: String(error)
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export {
|
|
149
|
-
GuardrailsError,
|
|
150
|
-
GuardrailValidationError,
|
|
151
|
-
GuardrailExecutionError,
|
|
152
|
-
GuardrailTimeoutError,
|
|
153
|
-
GuardrailConfigurationError,
|
|
154
|
-
InputBlockedError,
|
|
155
|
-
OutputBlockedError,
|
|
156
|
-
MiddlewareError,
|
|
157
|
-
isGuardrailsError,
|
|
158
|
-
extractErrorInfo
|
|
159
|
-
};
|