UNPKG

ai-sdk-guardrails

Version:

Input and output guardrails middleware for Vercel AI SDK.

945 lines (736 loc) • 34.3 kB
# AI SDK Guardrails ## Safety and quality controls for Vercel AI SDK Add guardrails to your AI applications in one line of code. Block PII, prevent prompt injection, enforce output quality - while keeping your existing telemetry and observability stack intact. [![npm version](https://img.shields.io/npm/v/ai-sdk-guardrails.svg?logo=npm&label=npm)](https://www.npmjs.com/package/ai-sdk-guardrails) [![downloads](https://img.shields.io/npm/dw/ai-sdk-guardrails.svg?label=downloads)](https://www.npmjs.com/package/ai-sdk-guardrails) [![bundle size](https://img.shields.io/bundlephobia/minzip/ai-sdk-guardrails.svg?label=minzipped)](https://bundlephobia.com/package/ai-sdk-guardrails) [![license](https://img.shields.io/npm/l/ai-sdk-guardrails.svg?label=license)](../../LICENSE) ![types](https://img.shields.io/badge/TypeScript-Ready-3178C6?logo=typescript&logoColor=white) ![Guardrails Demo](../../media/guardrail-example.gif) ## Drop-in Guardrails for any AI model ```ts import { withGuardrails, piiDetector } from 'ai-sdk-guardrails'; const model = openai('gpt-4o'); // or any other AI model // Everything else stays the same const safeModel = withGuardrails({ model, inputGuardrails: [piiDetector()] }); // Your existing code, telemetry, and logging still works await generateText({ model: safeModel, prompt: '...' }); ``` **That's it.** Your AI now blocks PII automatically. ## Installation ```bash npm install ai-sdk-guardrails ``` ## šŸ§™ā€ā™‚ļø No-Code Wizard (New!) **Don't want to write code?** Use our visual wizard to configure guardrails: 1. **Open the wizard**: [wizard-prototype/index.html](../../wizard-prototype/index.html) 2. **Choose your use case**: Content moderation, data protection, quality assurance, or security 3. **Select guardrails**: Pick from 40+ built-in guardrails 4. **Configure settings**: Adjust thresholds and parameters with sliders and toggles 5. **Copy generated code**: Get production-ready TypeScript code instantly **Perfect for:** - šŸŽÆ **Non-technical users** who need AI safety - šŸš€ **Quick prototyping** of guardrail configurations - šŸ“š **Learning** how to use the library - šŸ‘„ **Team onboarding** and training The wizard generates code that works out of the box - just copy, paste, and run! ## Why Guardrails Matter Real problems that guardrails solve: āŒ **Without guardrails:** ```ts // User: "My email is john@company.com, help me..." // → Sends PII to model → Compliance violation → $$$ ``` āœ… **With guardrails:** ```ts const model = withGuardrails({ model: baseModel, inputGuardrails: [piiDetector()], // Blocks before API call }); // → Request blocked → No PII leak → No cost → Compliant ``` Common use cases: - šŸ›”ļø **Compliance**: Block PII before it reaches your model - šŸ’° **Cost control**: Stop bad requests before they cost money - šŸ”’ **Security**: Prevent prompt injection and data exfiltration - āœ… **Quality**: Enforce minimum response standards - šŸ”§ **Production**: Works with your existing observability tools ## Copy-Paste Examples ### Basic Protection (Most Common) ```ts import { generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; import { withGuardrails, piiDetector, promptInjectionDetector, } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [piiDetector(), promptInjectionDetector()], }); // Use exactly like before - nothing else changes const { text } = await generateText({ model, prompt: 'Write a friendly email', }); ``` ### Input + Output Protection ```ts import { withGuardrails, piiDetector, sensitiveDataFilter, minLengthRequirement, } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [piiDetector()], // Block PII in prompts outputGuardrails: [ sensitiveDataFilter(), // Remove secrets from responses minLengthRequirement(100), // Enforce quality standards ], }); ``` ### Works With Streaming ```ts import { streamText } from 'ai'; const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [minLengthRequirement(100)], }); // Streaming just works - guardrails run after stream completes const { textStream } = await streamText({ model, prompt: '...' }); for await (const chunk of textStream) { process.stdout.write(chunk); } ``` ### Production Setup (With Error Handling) ```ts import { isGuardrailsError } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [piiDetector(), promptInjectionDetector()], outputGuardrails: [sensitiveDataFilter()], throwOnBlocked: true, // Throw errors instead of silent blocking }); try { const { text } = await generateText({ model, prompt: '...' }); console.log(text); } catch (error) { if (isGuardrailsError(error)) { console.error('Blocked by guardrail:', error.message); // Show user-friendly message } } ``` ## How It Works Guardrails run **in parallel** with your AI calls as middleware: ```mermaid flowchart LR A[Input] --> B[Input Guardrails] B -->|āœ… Clean| C[AI Model] B -->|āŒ Blocked| X[No API Call] C --> D[Output Guardrails] D -->|āœ… Clean| E[Response] D -->|āŒ Blocked| R[Retry/Replace/Block] ``` **Three-step workflow:** 1. **Receive**: Input or output arrives 2. **Check**: Guardrails run (PII detection, validation, etc.) 3. **Decide**: Pass through, block, or retry **Key benefit**: Non-invasive. Your existing telemetry, logging, and observability tools keep working because guardrails are just middleware. ## Built-in Guardrails ### Input Guardrails (Run Before Model) | Guardrail | Purpose | Example | | --------------------------- | ---------------------------------------- | ------------------- | | `piiDetector()` | Block emails, phones, SSNs | Compliance, privacy | | `promptInjectionDetector()` | Detect injection (obfuscation-resistant) | Security | | `blockedKeywords()` | Block specific terms | Content policy | | `inputLengthLimit()` | Enforce max input length | Cost control | | `rateLimiting()` | Per-user rate limits | Abuse prevention | | `profanityFilter()` | Block offensive language | Content moderation | | `toxicityDetector()` | Detect toxic content | Safety | | `allowedToolsGuardrail()` | Restrict which tools can be used | Tool security | | `highEntropyDetector()` | Flag encoded/obfuscated payloads | Security | ### Output Guardrails (Run After Model) | Guardrail | Purpose | Example | | ---------------------------- | -------------------------------------- | ------------------------- | | `sensitiveDataFilter()` | Remove secrets, API keys | Security | | `minLengthRequirement()` | Enforce minimum length | Quality control | | `outputLengthLimit()` | Enforce maximum length | Cost/UX control | | `toxicityFilter()` | Block toxic responses | Safety | | `jsonValidation()` | Validate JSON structure | Structured output | | `schemaValidation()` | Validate against Zod schema | Type safety | | `confidenceThreshold()` | Require minimum confidence | Quality | | `hallucinationDetector()` | Detect uncertain claims | Accuracy | | `secretRedaction()` | Redact secrets from output | Security | | `systemPromptLeakDetector()` | Catch the model echoing its own prompt | Prompt protection | | `mcpSecurityGuardrail()` | MCP tool security | Prevent data exfiltration | ### MCP Security Guardrails Protect against prompt injection and data exfiltration when using Model Context Protocol (MCP) tools: ```ts import { mcpSecurityGuardrail, mcpResponseSanitizer } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [ mcpSecurityGuardrail({ detectExfiltration: true, // Detect data exfiltration attempts scanEncodedContent: true, // Scan base64/hex encoded content allowedDomains: ['api.company.com'], // Domain allowlist maxContentSize: 51200, // 50KB limit injectionThreshold: 0.7, // Sensitivity (lower = stricter) }), mcpResponseSanitizer(), // Clean malicious content vs blocking ], }); ``` **Attack vectors prevented:** - āœ… Direct prompt injection - āœ… Tool response poisoning - āœ… Data exfiltration via URLs - āœ… Encoded attacks (base64/hex) - āœ… Cascading exploits - āœ… Context poisoning See [MCP Security documentation](#mcp-security-guardrails-advanced) for full details. ## Advanced Features ### Custom Guardrails Create domain-specific guardrails: ```ts import { defineInputGuardrail, defineOutputGuardrail } from 'ai-sdk-guardrails'; import { extractContent } from 'ai-sdk-guardrails/guardrails/output'; // Custom input guardrail const businessHours = defineInputGuardrail({ name: 'business-hours', execute: async () => { const hour = new Date().getHours(); return hour >= 9 && hour <= 17 ? { tripwireTriggered: false } : { tripwireTriggered: true, message: 'Outside business hours' }; }, }); // Custom output guardrail const minQuality = defineOutputGuardrail({ name: 'min-quality', execute: async ({ result }) => { const { text } = extractContent(result); return text.length >= 100 ? { tripwireTriggered: false } : { tripwireTriggered: true, message: 'Response too short' }; }, }); const model = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [businessHours], outputGuardrails: [minQuality], }); ``` ### Auto-Retry on Failures Automatically retry when output doesn't meet requirements: ```ts import { withGuardrails, minLengthRequirement } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [minLengthRequirement(100)], retry: { maxRetries: 2, buildRetryParams: ({ lastParams }) => ({ ...lastParams, // Increase max tokens on retry maxOutputTokens: (lastParams.maxOutputTokens ?? 400) + 200, // Add context about the failure prompt: [ ...lastParams.prompt, { role: 'user', content: 'Please provide a more detailed response.', }, ], }), }, }); ``` ### Reusable Configurations Create reusable guardrail sets: ```ts import { createGuardrails, piiDetector, sensitiveDataFilter, } from 'ai-sdk-guardrails'; // Define once const productionGuards = createGuardrails({ inputGuardrails: [piiDetector()], outputGuardrails: [sensitiveDataFilter()], throwOnBlocked: true, }); // Apply to multiple models const gpt4 = productionGuards(openai('gpt-4o')); const claude = productionGuards(anthropic('claude-3-sonnet')); ``` ### Streaming Modes Control when guardrails run during streaming: ```ts const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [minLengthRequirement(100)], streamMode: 'progressive', // Run guardrails as tokens arrive replaceOnBlocked: true, // Replace blocked output with fallback }); ``` - `buffer` (default): Wait for stream to complete, then check - `progressive`: Check guardrails as tokens arrive (early termination) ### Agent Support `agentGuardrails({ model, ...config })` returns native `ToolLoopAgentSettings` fragments — spread them into your **own** `ToolLoopAgent`. The result is a real agent, so streaming, structured `output`, `runtimeContext`, and `InferAgentUIMessage` all work: ```ts import { ToolLoopAgent, tool } from 'ai'; import { agentGuardrails, piiDetector, sensitiveDataFilter, toolEgressPolicy, } from 'ai-sdk-guardrails'; const agent = new ToolLoopAgent({ ...agentGuardrails({ model: openai('gpt-4o'), inputGuardrails: [piiDetector()], outputGuardrails: [sensitiveDataFilter()], // OutputGuardrails applied to tool calls (folded into the model's output guards): toolGuardrails: [ toolEgressPolicy({ allowedHosts: ['api.company.com'], scanForUrls: true, }), ], }), instructions: 'You are a helpful assistant.', tools: { search: searchTool }, }); const result = await agent.generate({ prompt: '...' }); // .stream() is guarded too ``` > Guardrails ride the SDK's own primitives — input/output guards run as model > middleware, tool-parameter gating uses native `toolApproval` > (`guardrailApproval([...])`), loop-stop uses `stopWhen`. Nothing wraps your agent. ## Tool Approval (AI SDK v7) AI SDK v7 added a first-class `toolApproval` hook to `generateText`, `streamText`, and `ToolLoopAgent`. It runs **inside the agent loop**, so it can deny a tool call outright or pause for human review and resume — something wrapping the model cannot do. Guardrails split cleanly across two axes — use the right tool for each: | Axis | Question | Mechanism | | ---------------------- | ------------------------------------------------------------------ | ------------------------------------ | | **Content safety** | Is this text/output safe? (PII, toxicity, injection) | `withGuardrails` middleware | | **Tool authorization** | Can this caller run this tool with these args? (RBAC, SQL, egress) | `guardrailApproval` → `toolApproval` | `guardrailApproval()` adapts your existing tool-parameter guardrails into the `toolApproval` slot. It drops straight into a `ToolLoopAgent` (the recommended agent API) — the tool set is inferred, no casts: ```ts import { ToolLoopAgent, tool } from 'ai'; import { guardrailApproval, sqlInjectionGuardrail, toolRBACGuardrail, } from 'ai-sdk-guardrails'; const agent = new ToolLoopAgent({ model: openai('gpt-4o'), instructions: 'You are a database assistant.', tools: { executeSQL: tool({/* ... */}), }, toolApproval: guardrailApproval( [ sqlInjectionGuardrail({ toolName: 'executeSQL' }), // critical → denied toolRBACGuardrail({ toolName: 'executeSQL', requiredPermissions: ['db:write'], }), ], { requestContext: { permissions: ['db:read'] }, onDecision: ({ toolName, status }) => console.log(toolName, status), }, ), }); const result = await agent.generate({ prompt: 'Show me last quarter revenue' }); ``` The same value works unchanged on `generateText` / `streamText`: ```ts await generateText({ model, tools, toolApproval: guardrailApproval([...]), prompt }); ``` **Decision mapping** (first failing guardrail wins): | Guardrail result | `toolApproval` decision | | ----------------------------------------------------------- | ----------------------------------- | | `valid: true` | `approved` | | `valid: false`, severity ≄ `denyAtOrAbove` (default `high`) | `denied` (tool never runs) | | `valid: false`, severity below the threshold | `user-approval` (pause for a human) | | no guardrail matches the tool | `not-applicable` | Tune with `denyAtOrAbove`, force a path with `onBlock: 'deny' | 'user-approval'`, and observe every decision via `onDecision`. See [example 54](../examples/54-tool-approval-guardrails.ts). > Need to **rewrite** tool input before it runs (e.g. sanitize a query) rather than > just allow/deny? Use `withToolParameterGuardrails` instead — `toolApproval` is > allow/deny only. ## Advanced Stopping Mechanisms Control exactly **when and how** guardrails stop execution with powerful, composable stopping mechanisms: ### 1. AbortSignal-Based Stopping Clean, standard API for canceling AI operations: ```ts import { createGuardrailAbortController } from 'ai-sdk-guardrails/advanced'; const { signal, abortOnViolation } = createGuardrailAbortController(); const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [toxicityFilter()], onOutputBlocked: abortOnViolation('critical'), // Abort on critical violations }); // Signal will be aborted if critical violation detected await streamText({ model, prompt: '...', abortSignal: signal }); ``` **Features:** - Standard AbortController API - Severity-based abortion (`'low' | 'medium' | 'high' | 'critical'`) - Custom abort conditions - Manual abortion support ### 2. Stream Transform with Source-Level Stopping Stop streaming at the **source** (most efficient): ```ts import { createGuardrailStreamTransform } from 'ai-sdk-guardrails/advanced'; const result = streamText({ model, prompt: 'Tell me a story', experimental_transform: createGuardrailStreamTransform( [toxicityFilter(), piiDetector()], { stopOnSeverity: 'high', // Stop on high/critical checkInterval: 1, // Check every chunk onViolation: (summary) => { // Violation callback console.log('Stopped:', summary); }, }, ), }); ``` **Modes:** - `createGuardrailStreamTransform` - Progressive checking (each chunk) - `createGuardrailStreamTransformBuffered` - Buffered checking (on flush) ### 3. Token-Level Control Reduce overhead with smart token-based checking: ```ts import { createTokenBudgetTransform, createTokenAwareGuardrailTransform, } from 'ai-sdk-guardrails/advanced'; experimental_transform: [ // Hard token limit createTokenBudgetTransform({ maxTokens: 1000, onBudgetExceeded: (info) => console.log(info), }), // Check guardrails every N tokens (not every chunk!) createTokenAwareGuardrailTransform([toxicityFilter()], { checkEveryTokens: 50, // Check every 50 tokens maxTokens: 1000, // Combined with budget stopOnSeverity: 'high', }), ]; ``` **Benefits:** - Reduce guardrail overhead by 80%+ - Cost control with token budgets - Custom tokenizer support ### 4. Adaptive Multi-Step Execution Self-correcting behavior across multi-step agent execution: ```ts import { createAdaptivePrepareStep } from 'ai-sdk-guardrails/advanced'; import type { GuardrailViolation } from 'ai-sdk-guardrails'; const violations: GuardrailViolation[] = []; const agent = new ToolLoopAgent({ ...agentGuardrails({ model, outputGuardrails: [toxicityFilter()], onOutputBlocked: (summary) => { violations.push({ step: violations.length, summary }); }, }), tools: { search: searchTool }, prepareStep: createAdaptivePrepareStep({ violations, escalateAfter: 3, // Stop after 3 violations strategy: (violations) => ({ temperature: Math.max(0.1, 0.7 - violations.length * 0.1), system: `${violations.length} violations detected. Be careful.`, }), }), }); ``` **Features:** - Progressive temperature reduction - Custom adaptive strategies - Escalation to auto-stop - Lookback window configuration ### 5. Tool Execution Abortion Prevent dangerous tool execution before or during execution: ```ts import { wrapToolWithAbortion } from 'ai-sdk-guardrails/advanced'; const safeTool = wrapToolWithAbortion( dangerousApiTool, [urlValidator, paramValidator], { checkBefore: true, // Validate before execution monitorDuring: true, // Monitor during execution monitorInterval: 1000, // Check every second checkInputDelta: true, // Monitor streaming inputs abortOnSeverity: 'critical', }, ); ``` **Protection:** - Pre-execution validation - Real-time monitoring - Streaming input checking - Manual abortion control ### 6. Finish Reason & Metadata Better observability with proper finish reasons and metadata: ```ts import { createFinishReasonEnhancement } from 'ai-sdk-guardrails/advanced'; // Automatically set in middleware, or manually: const enhanced = createFinishReasonEnhancement(summary, result); console.log(enhanced.finishReason); // 'content_filter' for blocks console.log(enhanced.providerMetadata.guardrails); // { // blocked: true, // violations: [{ message: '...', severity: 'high', ... }], // executionTime: 50, // stats: { passed: 2, blocked: 1, failed: 0 } // } ``` **Features:** - Standard `content_filter` finish reason - Structured violation metadata - Execution statistics - Custom metadata preservation ## MCP Security Guardrails (Advanced) **Production-Ready**: Protect against the ["lethal trifecta" vulnerability](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) when using Model Context Protocol (MCP) tools. ### The Problem AI agents with MCP tools are vulnerable when they have: 1. **Access to private data** (through tools) 2. **Process untrusted content** (from tool responses) 3. **Can communicate externally** (make web requests) Malicious tool responses can contain hidden instructions that trick the AI into exfiltrating sensitive data. ### Production Configuration Full configurability with sensible defaults: ```ts import { withGuardrails, promptInjectionDetector, mcpSecurityGuardrail, mcpResponseSanitizer, toolEgressPolicy, } from 'ai-sdk-guardrails'; // Conservative production setup (high security) const secureModel = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [ promptInjectionDetector({ threshold: 0.6, includeExamples: true }), ], outputGuardrails: [ mcpSecurityGuardrail({ injectionThreshold: 0.5, // Lower = more sensitive maxSuspiciousUrls: 0, // Zero tolerance maxContentSize: 25600, // 25KB limit minEncodedLength: 15, // Detect shorter encoded attacks encodedInjectionThreshold: 0.2, // Combined threshold highRiskThreshold: 0.3, // High-risk cascade blocking authorityThreshold: 0.5, // Authority manipulation detection allowedDomains: ['api.company.com', 'trusted-partner.com'], customSuspiciousDomains: ['evil.com'], blockCascadingCalls: true, scanEncodedContent: true, detectExfiltration: true, }), mcpResponseSanitizer(), // Clean vs block toolEgressPolicy({ allowedHosts: ['api.company.com'], blockedHosts: ['webhook.site', 'requestcatcher.com'], scanForUrls: true, }), ], }); ``` ### Environment-Based Configuration ```ts function getSecurityConfig(env: 'production' | 'staging' | 'development') { const configs = { production: { injectionThreshold: 0.5, // High security maxContentSize: 25600, // 25KB authorityThreshold: 0.5, }, staging: { injectionThreshold: 0.7, // Balanced maxContentSize: 51200, // 50KB authorityThreshold: 0.7, }, development: { injectionThreshold: 0.8, // Permissive maxContentSize: 102400, // 100KB authorityThreshold: 0.8, }, }; return configs[env]; } const model = withGuardrails({ model: openai('gpt-4o'), outputGuardrails: [mcpSecurityGuardrail(getSecurityConfig('production'))], }); ``` ### Configuration Options | Option | Default | Description | | --------------------------- | ------- | ------------------------------------------------ | | `injectionThreshold` | 0.7 | Prompt injection confidence threshold (0-1) | | `maxSuspiciousUrls` | 0 | Max allowed suspicious URLs (0 = zero tolerance) | | `maxContentSize` | 51200 | Max content size in bytes (50KB default) | | `minEncodedLength` | 20 | Min encoded content length to analyze | | `encodedInjectionThreshold` | 0.3 | Combined encoded + injection threshold | | `authorityThreshold` | 0.7 | Authority manipulation detection sensitivity | | `allowedDomains` | [] | Allowed domains for URL construction | | `customSuspiciousDomains` | [] | Additional suspicious domain patterns | See complete examples: - [Production MCP Configuration](../examples/44-production-mcp-config.ts) - [MCP Security Test Suite](../examples/41-mcp-security-test.ts) - [Enhanced Security Testing](../examples/43-enhanced-mcp-security-test.ts) ## Error Handling ### Throw Errors on Block ```ts const model = withGuardrails({ model: openai('gpt-4o'), inputGuardrails: [piiDetector()], throwOnBlocked: true, // Throw errors instead of silent blocking }); try { const { text } = await generateText({ model, prompt: '...' }); } catch (error) { if (isGuardrailsError(error)) { console.error('Blocked:', error.message); // GuardrailsInputError / GuardrailsOutputError expose `blockedGuardrails` // with the name, message, and severity of each guardrail that tripped. } } ``` ### Error Types - `GuardrailsInputError` - Input guardrail blocked - `GuardrailsOutputError` - Output guardrail blocked - `GuardrailExecutionError` - Guardrail threw an error - `GuardrailTimeoutError` - Guardrail exceeded timeout - `GuardrailConfigurationError` - Invalid configuration ## API Reference ### Primary Functions | Function | Purpose | | ------------------------------ | ------------------------------------------- | | `withGuardrails` | Wrap model with guardrails (main API) | | `createGuardrails` | Create reusable guardrail configurations | | `agentGuardrails` | Native settings fragments for ToolLoopAgent | | `guardrailApproval` | Gate tool calls via v7 `toolApproval` | | `defineInputGuardrail` | Create custom input guardrail | | `defineOutputGuardrail` | Create custom output guardrail | | `hardenSystemPrompt` | Wrap a system prompt with defensive rules | | `evaluatePromptDefense` | Grade a system prompt's OWASP-LLM coverage | | `scanMcpTool` / `scanMcpTools` | Scan MCP tool definitions for threats | | `executeInputGuardrails` | Run input guardrails programmatically | | `executeOutputGuardrails` | Run output guardrails programmatically | ### Error Utilities | Function | Purpose | | ------------------- | ------------------------------------ | | `isGuardrailsError` | Check if error is from guardrails | | `extractErrorInfo` | Extract structured error information | ### Retry Utilities | Function | Purpose | | ---------------------------- | --------------------------------- | | `retry` | Standalone retry utility | | `exponentialBackoff` | Exponential backoff strategy | | `linearBackoff` | Linear backoff strategy | | `jitteredExponentialBackoff` | Jittered exponential backoff | | `backoffPresets` | Pre-configured backoff strategies | See source for all built-in guardrails: - Input helpers: [`./src/guardrails/input.ts`](./src/guardrails/input.ts) - Output helpers: [`./src/guardrails/output.ts`](./src/guardrails/output.ts) - Tool helpers: [`./src/guardrails/tools.ts`](./src/guardrails/tools.ts) - MCP security: [`./src/guardrails/mcp-security.ts`](./src/guardrails/mcp-security.ts) ## Examples Browse 48+ runnable examples: [examples/README.md](../examples/README.md) | ### Quick Starts | Example | Description | File | | -------------------------- | ------------------------------- | ---------------------------------------------------------------------------------- | | Simple combined protection | Minimal input and output setup | [07a-simple-combined-protection.ts](../examples/07a-simple-combined-protection.ts) | | Auto retry on output | Retry until output meets a rule | [32-auto-retry-output.ts](../examples/32-auto-retry-output.ts) | | LLM judge auto-retry | Judge feedback drives retry | [35-judge-auto-retry.ts](../examples/35-judge-auto-retry.ts) | | Weather assistant | End-to-end input/output + retry | [33-blog-post-weather-assistant.ts](../examples/33-blog-post-weather-assistant.ts) | ### Input Safety | Example | Description | File | | ------------------ | ----------------------------------- | ---------------------------------------------------------------- | | Input length limit | Enforce max input length | [01-input-length-limit.ts](../examples/01-input-length-limit.ts) | | Blocked keywords | Block specific terms | [02-blocked-keywords.ts](../examples/02-blocked-keywords.ts) | | PII detection | Detect PII before calling the model | [03-pii-detection.ts](../examples/03-pii-detection.ts) | | Rate limiting | Simple per-user rate limit | [13-rate-limiting.ts](../examples/13-rate-limiting.ts) | ### Output Safety | Example | Description | File | | ----------------------- | ----------------------------------- | -------------------------------------------------------------------------- | | Output length check | Require min/max output length | [04-output-length-check.ts](../examples/04-output-length-check.ts) | | Sensitive output filter | Filter secrets and PII in responses | [05-sensitive-output-filter.ts](../examples/05-sensitive-output-filter.ts) | | Hallucination detection | Flag uncertain factual claims | [19-hallucination-detection.ts](../examples/19-hallucination-detection.ts) | ### Streaming | Example | Description | File | | ----------------- | ---------------------------------- | ---------------------------------------------------------------------------------- | | Streaming limits | Apply limits in buffered streaming | [11-streaming-limits.ts](../examples/11-streaming-limits.ts) | | Streaming quality | Quality checks with streaming | [12-streaming-quality.ts](../examples/12-streaming-quality.ts) | | Early termination | Stop streams early when blocked | [28-streaming-early-termination.ts](../examples/28-streaming-early-termination.ts) | ### Advanced | Example | Description | File | | -------------------------- | ----------------------------- | -------------------------------------------------------------------------------- | | Simple quality judge | Cheaper model judges quality | [15a-simple-quality-judge.ts](../examples/15a-simple-quality-judge.ts) | | Secret leakage scan | Scan responses for secrets | [18-secret-leakage-scan.ts](../examples/18-secret-leakage-scan.ts) | | SQL code safety | Basic SQL safety checks | [24-sql-code-safety.ts](../examples/24-sql-code-safety.ts) | | Role hierarchy enforcement | Enforce role rules in prompts | [23-role-hierarchy-enforcement.ts](../examples/23-role-hierarchy-enforcement.ts) | ## Migration from v3.x v6 removed the old v3.x names. Update imports and call sites: ```ts // v3.x (removed) import { wrapWithGuardrails, InputBlockedError } from 'ai-sdk-guardrails'; const model = wrapWithGuardrails(openai('gpt-4o'), { ... }); // v6 import { withGuardrails, GuardrailsInputError } from 'ai-sdk-guardrails'; const model = withGuardrails({ model: openai('gpt-4o'), ... }); ``` Name changes: - `wrapWithGuardrails(model, config)` → `withGuardrails({ model, ...config })` - `withAgentGuardrails(settings, config)` → `new ToolLoopAgent({ ...agentGuardrails({ model, ...config }), ...settings })` - `InputBlockedError` → `GuardrailsInputError` - `OutputBlockedError` → `GuardrailsOutputError` ## Compatibility - **Runtime**: Node.js 18+ recommended - **AI SDK**: v6 requires AI SDK 7 (`ai@^7`, `@ai-sdk/provider@^4`). Stay on `ai-sdk-guardrails@5.x` for AI SDK 6. - **TypeScript**: Full type safety with TypeScript 5+ - **Works with any model**: OpenAI, Anthropic, Mistral, Groq, etc. ### Upgrading to v6 (AI SDK 7) The public API is source-compatible — `withGuardrails`, `defineInputGuardrail`, `defineOutputGuardrail`, and every built-in guardrail keep the same signatures. What changes: - Bump your peer dependency to `ai@^7` (now emits `LanguageModelV4` middleware). - Advanced provider types are exported under their V4 names (`LanguageModelV4Middleware`, …); the old `LanguageModelV3*` names remain as deprecated aliases. - New: `guardrailApproval()` for the v7 [`toolApproval`](#tool-approval-ai-sdk-v7) hook. For tool gating, prefer it over `withToolParameterGuardrails`. ## Why This Library? **Non-invasive**: Guardrails are middleware. Your existing code, telemetry (Langfuse, Helicone), and logging stay intact. **Production-ready**: Used in production by teams who need compliance, security, and cost control without rebuilding their infrastructure. **Developer experience**: One line to add safety. Progressive complexity - start simple, add advanced features when needed. **Type-safe**: Rich TypeScript types and inference throughout. **Comprehensive**: 40+ built-in guardrails covering security, quality, compliance, and performance. **Advanced features**: Early detection, parallel execution, enhanced prompt injection detection, MCP security, and more. ## Contributing Issues and PRs are welcome. ## License MIT Ā© Jag Reehal. See [LICENSE](../../LICENSE) for details.