ai-sdk-guardrails 5.0.2 → 5.1.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
@@ -386,6 +386,191 @@ const agent = withAgentGuardrails(
386
386
  const result = await agent.generate({ prompt: '...' });
387
387
  ```
388
388
 
389
+ ## Advanced Stopping Mechanisms
390
+
391
+ Control exactly **when and how** guardrails stop execution with powerful, composable stopping mechanisms:
392
+
393
+ ### 1. AbortSignal-Based Stopping
394
+
395
+ Clean, standard API for canceling AI operations:
396
+
397
+ ```ts
398
+ import { createGuardrailAbortController } from 'ai-sdk-guardrails';
399
+
400
+ const { signal, abortOnViolation } = createGuardrailAbortController();
401
+
402
+ const model = withGuardrails(openai('gpt-4o'), {
403
+ outputGuardrails: [toxicityFilter()],
404
+ onOutputBlocked: abortOnViolation('critical'), // Abort on critical violations
405
+ });
406
+
407
+ // Signal will be aborted if critical violation detected
408
+ await streamText({ model, prompt: '...', abortSignal: signal });
409
+ ```
410
+
411
+ **Features:**
412
+
413
+ - Standard AbortController API
414
+ - Severity-based abortion (`'low' | 'medium' | 'high' | 'critical'`)
415
+ - Custom abort conditions
416
+ - Manual abortion support
417
+
418
+ ### 2. Stream Transform with Source-Level Stopping
419
+
420
+ Stop streaming at the **source** (most efficient):
421
+
422
+ ```ts
423
+ import { createGuardrailStreamTransform } from 'ai-sdk-guardrails';
424
+
425
+ const result = streamText({
426
+ model,
427
+ prompt: 'Tell me a story',
428
+ experimental_transform: createGuardrailStreamTransform(
429
+ [toxicityFilter(), piiDetector()],
430
+ {
431
+ stopOnSeverity: 'high', // Stop on high/critical
432
+ checkInterval: 1, // Check every chunk
433
+ onViolation: (summary) => {
434
+ // Violation callback
435
+ console.log('Stopped:', summary);
436
+ },
437
+ },
438
+ ),
439
+ });
440
+ ```
441
+
442
+ **Modes:**
443
+
444
+ - `createGuardrailStreamTransform` - Progressive checking (each chunk)
445
+ - `createGuardrailStreamTransformBuffered` - Buffered checking (on flush)
446
+
447
+ ### 3. Token-Level Control
448
+
449
+ Reduce overhead with smart token-based checking:
450
+
451
+ ```ts
452
+ import {
453
+ createTokenBudgetTransform,
454
+ createTokenAwareGuardrailTransform,
455
+ } from 'ai-sdk-guardrails';
456
+
457
+ experimental_transform: [
458
+ // Hard token limit
459
+ createTokenBudgetTransform({
460
+ maxTokens: 1000,
461
+ onBudgetExceeded: (info) => console.log(info),
462
+ }),
463
+
464
+ // Check guardrails every N tokens (not every chunk!)
465
+ createTokenAwareGuardrailTransform([toxicityFilter()], {
466
+ checkEveryTokens: 50, // Check every 50 tokens
467
+ maxTokens: 1000, // Combined with budget
468
+ stopOnSeverity: 'high',
469
+ }),
470
+ ];
471
+ ```
472
+
473
+ **Benefits:**
474
+
475
+ - Reduce guardrail overhead by 80%+
476
+ - Cost control with token budgets
477
+ - Custom tokenizer support
478
+
479
+ ### 4. Adaptive Multi-Step Execution
480
+
481
+ Self-correcting behavior across multi-step agent execution:
482
+
483
+ ```ts
484
+ import {
485
+ createAdaptivePrepareStep,
486
+ type GuardrailViolation,
487
+ } from 'ai-sdk-guardrails';
488
+
489
+ const violations: GuardrailViolation[] = [];
490
+
491
+ const agent = new Agent({
492
+ model,
493
+ tools: { search: searchTool },
494
+ prepareStep: createAdaptivePrepareStep({
495
+ violations,
496
+ escalateAfter: 3, // Stop after 3 violations
497
+ strategy: (violations) => ({
498
+ temperature: Math.max(0.1, 0.7 - violations.length * 0.1),
499
+ system: `${violations.length} violations detected. Be careful.`,
500
+ }),
501
+ }),
502
+ });
503
+
504
+ // Track violations
505
+ withAgentGuardrails(agent, {
506
+ outputGuardrails: [toxicityFilter()],
507
+ onOutputBlocked: (summary, context, step) => {
508
+ violations.push({ step, summary });
509
+ },
510
+ });
511
+ ```
512
+
513
+ **Features:**
514
+
515
+ - Progressive temperature reduction
516
+ - Custom adaptive strategies
517
+ - Escalation to auto-stop
518
+ - Lookback window configuration
519
+
520
+ ### 5. Tool Execution Abortion
521
+
522
+ Prevent dangerous tool execution before or during execution:
523
+
524
+ ```ts
525
+ import { wrapToolWithAbortion } from 'ai-sdk-guardrails';
526
+
527
+ const safeTool = wrapToolWithAbortion(
528
+ dangerousApiTool,
529
+ [urlValidator, paramValidator],
530
+ {
531
+ checkBefore: true, // Validate before execution
532
+ monitorDuring: true, // Monitor during execution
533
+ monitorInterval: 1000, // Check every second
534
+ checkInputDelta: true, // Monitor streaming inputs
535
+ abortOnSeverity: 'critical',
536
+ },
537
+ );
538
+ ```
539
+
540
+ **Protection:**
541
+
542
+ - Pre-execution validation
543
+ - Real-time monitoring
544
+ - Streaming input checking
545
+ - Manual abortion control
546
+
547
+ ### 6. Finish Reason & Metadata
548
+
549
+ Better observability with proper finish reasons and metadata:
550
+
551
+ ```ts
552
+ import { createFinishReasonEnhancement } from 'ai-sdk-guardrails';
553
+
554
+ // Automatically set in middleware, or manually:
555
+ const enhanced = createFinishReasonEnhancement(summary, result);
556
+
557
+ console.log(enhanced.finishReason); // 'content_filter' for blocks
558
+ console.log(enhanced.providerMetadata.guardrails);
559
+ // {
560
+ // blocked: true,
561
+ // violations: [{ message: '...', severity: 'high', ... }],
562
+ // executionTime: 50,
563
+ // stats: { passed: 2, blocked: 1, failed: 0 }
564
+ // }
565
+ ```
566
+
567
+ **Features:**
568
+
569
+ - Standard `content_filter` finish reason
570
+ - Structured violation metadata
571
+ - Execution statistics
572
+ - Custom metadata preservation
573
+
389
574
  ## MCP Security Guardrails (Advanced)
390
575
 
391
576
  **Production-Ready**: Protect against the ["lethal trifecta" vulnerability](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) when using Model Context Protocol (MCP) tools.
@@ -151,8 +151,6 @@ function extractErrorInfo(error) {
151
151
  message: String(error)
152
152
  };
153
153
  }
154
- var InputBlockedError = GuardrailsInputError;
155
- var OutputBlockedError = GuardrailsOutputError;
156
154
 
157
155
  // src/core.ts
158
156
  function createInputGuardrail(name, description, execute) {
@@ -388,8 +386,6 @@ export {
388
386
  MiddlewareError,
389
387
  isGuardrailsError,
390
388
  extractErrorInfo,
391
- InputBlockedError,
392
- OutputBlockedError,
393
389
  createInputGuardrail,
394
390
  createOutputGuardrail,
395
391
  retry,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createInputGuardrail
3
- } from "./chunk-VKJ5EAS7.js";
3
+ } from "./chunk-CB2WX5S7.js";
4
4
 
5
5
  // src/guardrails/input.ts
6
6
  var SEVERITY_LEVELS = {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createOutputGuardrail
3
- } from "./chunk-VKJ5EAS7.js";
3
+ } from "./chunk-CB2WX5S7.js";
4
4
 
5
5
  // src/guardrails/output.ts
6
6
  var EMPTY_CONTENT = {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  extractContent
3
- } from "./chunk-ND2ICBTR.js";
3
+ } from "./chunk-XWDH2NCM.js";
4
4
  import {
5
5
  createOutputGuardrail
6
- } from "./chunk-VKJ5EAS7.js";
6
+ } from "./chunk-CB2WX5S7.js";
7
7
 
8
8
  // src/guardrails/tools.ts
9
9
  function defaultMarker(tool) {
@@ -1,4 +1,4 @@
1
- import { I as InputGuardrail, a as InputGuardrailContext } from '../types-CeZi2BBN.cjs';
1
+ import { I as InputGuardrail, a as InputGuardrailContext } from '../types-WcM_8Gvq.cjs';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -1,4 +1,4 @@
1
- import { I as InputGuardrail, a as InputGuardrailContext } from '../types-CeZi2BBN.js';
1
+ import { I as InputGuardrail, a as InputGuardrailContext } from '../types-WcM_8Gvq.js';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -15,8 +15,8 @@ import {
15
15
  promptInjectionDetector,
16
16
  rateLimiting,
17
17
  toxicityDetector
18
- } from "../chunk-CSUDFTRH.js";
19
- import "../chunk-VKJ5EAS7.js";
18
+ } from "../chunk-OP5XB2DJ.js";
19
+ import "../chunk-CB2WX5S7.js";
20
20
  export {
21
21
  allowedToolsGuardrail,
22
22
  blockedKeywords,
@@ -1,4 +1,4 @@
1
- import { O as OutputGuardrail, A as AIResult } from '../types-CeZi2BBN.cjs';
1
+ import { O as OutputGuardrail, A as AIResult } from '../types-WcM_8Gvq.cjs';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -1,4 +1,4 @@
1
- import { O as OutputGuardrail, A as AIResult } from '../types-CeZi2BBN.js';
1
+ import { O as OutputGuardrail, A as AIResult } from '../types-WcM_8Gvq.js';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -24,8 +24,8 @@ import {
24
24
  tokenUsageLimit,
25
25
  toxicityFilter,
26
26
  unsafeContentDetector
27
- } from "../chunk-ND2ICBTR.js";
28
- import "../chunk-VKJ5EAS7.js";
27
+ } from "../chunk-XWDH2NCM.js";
28
+ import "../chunk-CB2WX5S7.js";
29
29
  export {
30
30
  biasDetector,
31
31
  blockedContent,
@@ -1,4 +1,4 @@
1
- import { A as AIResult, O as OutputGuardrail } from '../types-CeZi2BBN.cjs';
1
+ import { A as AIResult, O as OutputGuardrail } from '../types-WcM_8Gvq.cjs';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -1,4 +1,4 @@
1
- import { A as AIResult, O as OutputGuardrail } from '../types-CeZi2BBN.js';
1
+ import { A as AIResult, O as OutputGuardrail } from '../types-WcM_8Gvq.js';
2
2
  import 'ai';
3
3
  import '@ai-sdk/provider';
4
4
  import '@opentelemetry/api';
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  expectedToolUse,
3
3
  toolEgressPolicy
4
- } from "../chunk-LVXHWHZC.js";
5
- import "../chunk-ND2ICBTR.js";
6
- import "../chunk-VKJ5EAS7.js";
4
+ } from "../chunk-ZZFNRQAT.js";
5
+ import "../chunk-XWDH2NCM.js";
6
+ import "../chunk-CB2WX5S7.js";
7
7
  export {
8
8
  expectedToolUse,
9
9
  toolEgressPolicy