@directive-run/ai 1.20.2 → 1.22.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.
@@ -1,855 +1,4 @@
1
- import { m as GuardrailFn, I as InputGuardrailData, O as OutputGuardrailData, aW as SchemaValidator, T as ToolCallGuardrailData } from './types-DJ09LjZX.cjs';
2
- import { a as Embedding } from './semantic-cache-DM7ev7NQ.cjs';
3
- export { B as BatchedEmbedder, C as CacheEntry, b as CacheLookupResult, c as CacheStats, E as EmbedderFn, S as SemanticCache, d as SemanticCacheConfig, e as SemanticCacheStorage, f as createBatchedEmbedder, g as createInMemoryStorage, h as createSemanticCache, i as createSemanticCacheGuardrail, j as createTestEmbedder } from './semantic-cache-DM7ev7NQ.cjs';
4
- import { Plugin } from '@directive-run/core';
5
-
6
- /**
7
- * Built-in guardrails for AI adapter — PII, moderation, rate limiting, tool allowlists, schema validation.
8
- */
9
-
10
- /**
11
- * Create a PII detection guardrail that scans input text for personally identifiable
12
- * information. Blocks input when PII is detected, or optionally redacts matches and
13
- * passes the sanitized text through.
14
- *
15
- * @param options - Configuration for PII detection: `patterns` sets the RegExp list (defaults to SSN, credit card, email), `redact` replaces matches instead of blocking, `redactReplacement` sets the replacement string (defaults to `"[REDACTED]"`).
16
- * @returns An input guardrail that blocks or redacts PII in user input.
17
- *
18
- * @example
19
- * ```typescript
20
- * const piiGuardrail = createPIIGuardrail({
21
- * patterns: [
22
- * /\b\d{3}-\d{2}-\d{4}\b/, // SSN
23
- * /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i, // Email
24
- * ],
25
- * redact: true,
26
- * });
27
- * ```
28
- *
29
- * @public
30
- */
31
- declare function createPIIGuardrail(options: {
32
- patterns?: RegExp[];
33
- redact?: boolean;
34
- redactReplacement?: string;
35
- }): GuardrailFn<InputGuardrailData>;
36
- /**
37
- * Create a content moderation guardrail that delegates to a user-supplied check function.
38
- * Works on both input and output data — the guardrail extracts the text content
39
- * automatically and passes it to {@link options.checkFn}.
40
- *
41
- * @param options - Configuration for content moderation: `checkFn` returns `true` when content should be flagged (supports async), `message` sets the rejection reason (defaults to `"Content flagged by moderation"`).
42
- * @returns A guardrail that blocks content flagged by the check function.
43
- *
44
- * @example
45
- * ```typescript
46
- * const moderationGuardrail = createModerationGuardrail({
47
- * checkFn: async (text) => {
48
- * const result = await openai.moderations.create({ input: text });
49
- * return result.results[0].flagged;
50
- * },
51
- * });
52
- * ```
53
- *
54
- * @public
55
- */
56
- declare function createModerationGuardrail(options: {
57
- checkFn: (text: string) => boolean | Promise<boolean>;
58
- message?: string;
59
- }): GuardrailFn<InputGuardrailData | OutputGuardrailData>;
60
- /** Rate limiter with reset capability for testing */
61
- interface RateLimitGuardrail extends GuardrailFn<InputGuardrailData> {
62
- reset(): void;
63
- }
64
- /**
65
- * Create a rate limit guardrail that tracks token and request counts over a sliding
66
- * one-minute window. Returns a {@link RateLimitGuardrail} — a guardrail function with
67
- * an additional `reset()` method for testing.
68
- *
69
- * @param options - Configuration for rate limiting: `maxTokensPerMinute` caps tokens in the sliding window (defaults to `100000`), `maxRequestsPerMinute` caps requests (defaults to `60`).
70
- * @returns A rate limit guardrail with an attached `reset()` method.
71
- *
72
- * @example
73
- * ```typescript
74
- * const rateLimiter = createRateLimitGuardrail({
75
- * maxTokensPerMinute: 50000,
76
- * maxRequestsPerMinute: 30,
77
- * });
78
- * ```
79
- *
80
- * @public
81
- */
82
- declare function createRateLimitGuardrail(options: {
83
- maxTokensPerMinute?: number;
84
- maxRequestsPerMinute?: number;
85
- }): RateLimitGuardrail;
86
- /**
87
- * Create a tool-call guardrail that restricts which tools an agent may invoke.
88
- * Supports allowlist mode, denylist mode, or both — when both are provided, a tool
89
- * must appear in the allowlist and not appear in the denylist.
90
- *
91
- * @param options - Configuration for tool filtering: `allowlist` sets permitted tool names, `denylist` sets blocked tool names, `caseSensitive` controls case matching (defaults to `false`).
92
- * @returns A tool-call guardrail that enforces the allowlist/denylist rules.
93
- *
94
- * @example
95
- * ```typescript
96
- * const toolGuardrail = createToolGuardrail({
97
- * allowlist: ["search", "calculate"],
98
- * denylist: ["delete_account"],
99
- * });
100
- * ```
101
- *
102
- * @public
103
- */
104
- declare function createToolGuardrail(options: {
105
- allowlist?: string[];
106
- denylist?: string[];
107
- /** @default false */
108
- caseSensitive?: boolean;
109
- }): GuardrailFn<ToolCallGuardrailData>;
110
- /**
111
- * Create an output guardrail that validates agent output against a schema using
112
- * a user-supplied {@link SchemaValidator}. Compatible with any validation library
113
- * (Zod, Valibot, ArkType, etc.) via the adapter pattern.
114
- *
115
- * @param options - Configuration for schema validation: `validate` checks the output against the expected schema, `errorPrefix` is prepended to error messages (defaults to `"Output schema validation failed"`).
116
- * @returns An output guardrail that rejects output failing schema validation.
117
- *
118
- * @example
119
- * ```typescript
120
- * import { z } from "zod";
121
- *
122
- * const schemaGuardrail = createOutputSchemaGuardrail({
123
- * validate: (value) => {
124
- * const result = z.object({ answer: z.string() }).safeParse(value);
125
- * return { valid: result.success, errors: result.error?.issues.map(i => i.message) };
126
- * },
127
- * });
128
- * ```
129
- *
130
- * @public
131
- */
132
- declare function createOutputSchemaGuardrail<T = unknown>(options: {
133
- validate: SchemaValidator<T>;
134
- errorPrefix?: string;
135
- }): GuardrailFn<OutputGuardrailData>;
136
- /**
137
- * Create an output guardrail that performs lightweight runtime type checks without
138
- * requiring a schema library. Supports `"string"`, `"number"`, `"boolean"`, `"object"`,
139
- * and `"array"` with optional size and field constraints.
140
- *
141
- * @param options - Configuration for type checking: `type` sets the expected JS type, `requiredFields` lists object keys that must exist, `minLength`/`maxLength` constrain array size, `minStringLength`/`maxStringLength` constrain string length.
142
- * @returns An output guardrail that rejects output not matching the expected type or constraints.
143
- *
144
- * @example
145
- * ```typescript
146
- * const typeGuardrail = createOutputTypeGuardrail({
147
- * type: "object",
148
- * requiredFields: ["id", "name"],
149
- * });
150
- * ```
151
- *
152
- * @public
153
- */
154
- declare function createOutputTypeGuardrail(options: {
155
- type: "string" | "number" | "boolean" | "object" | "array";
156
- requiredFields?: string[];
157
- minLength?: number;
158
- maxLength?: number;
159
- minStringLength?: number;
160
- maxStringLength?: number;
161
- }): GuardrailFn<OutputGuardrailData>;
162
- /**
163
- * Create an output guardrail that enforces maximum length constraints on agent output,
164
- * measured in characters or estimated tokens.
165
- *
166
- * @param options - Configuration for length limits: `maxCharacters` caps character count, `maxTokens` caps estimated token count, `estimateTokens` provides a custom token estimator (defaults to `Math.ceil(text.length / 4)`).
167
- * @returns An output guardrail that rejects output exceeding the configured length limits.
168
- *
169
- * @example
170
- * ```typescript
171
- * const lengthGuardrail = createLengthGuardrail({
172
- * maxCharacters: 5000,
173
- * maxTokens: 1200,
174
- * });
175
- * ```
176
- *
177
- * @public
178
- */
179
- declare function createLengthGuardrail(options: {
180
- /** Maximum characters in output */
181
- maxCharacters?: number;
182
- /** Maximum estimated tokens in output */
183
- maxTokens?: number;
184
- /** Custom token estimator (default: chars / 4) */
185
- estimateTokens?: (text: string) => number;
186
- }): GuardrailFn<OutputGuardrailData>;
187
- /**
188
- * Create an output guardrail that blocks content matching any of the provided patterns.
189
- * String patterns are escaped and compiled to RegExp; RegExp patterns are used as-is.
190
- *
191
- * @remarks
192
- * A warning is logged when `blockedPatterns` is empty, since an empty list means no
193
- * content will ever be filtered.
194
- *
195
- * @param options - Configuration for content filtering: `blockedPatterns` lists strings or RegExps to match against output, `caseSensitive` controls case matching for string patterns (defaults to `false`).
196
- * @returns An output guardrail that rejects output containing any blocked pattern.
197
- *
198
- * @example
199
- * ```typescript
200
- * const contentFilter = createContentFilterGuardrail({
201
- * blockedPatterns: [
202
- * /\bpassword\b/i,
203
- * /\bsecret\b/i,
204
- * 'internal-only',
205
- * ],
206
- * });
207
- * ```
208
- *
209
- * @public
210
- */
211
- declare function createContentFilterGuardrail(options: {
212
- /** Patterns to block — strings or RegExp */
213
- blockedPatterns: Array<string | RegExp>;
214
- /** Case-sensitive matching for string patterns (default: false) */
215
- caseSensitive?: boolean;
216
- }): GuardrailFn<OutputGuardrailData>;
217
-
218
- /**
219
- * Fact-PII Guardrail — input guardrail at the fact-store boundary
220
- *
221
- * Closes the source → fact → agent prompt PII bypass surfaced by R5's
222
- * red-team / privacy / AI-integration reviewers: `createPIIGuardrail`
223
- * only inspects the `data.input` string at runStream entry, so PII that
224
- * a source publishes into a fact (a Supabase realtime row carrying a
225
- * customer email, a webhook payload with a SSN, an MCP server's
226
- * resource notification with a card number) reaches the agent's
227
- * prompt — via fact injection — without ever hitting the input
228
- * guardrail chain.
229
- *
230
- * This plugin runs as a Directive plugin (`onFactSet` / `onFactsBatch`),
231
- * scans every write to a pii-tagged fact against a sync regex matcher
232
- * for the three highest-volume PII categories (SSN, credit card, email),
233
- * and either **redacts** the value (the default — safe shipping posture)
234
- * or **rejects** the write (throws so the source's publish handler can
235
- * surface the violation). Operators wire it once at `createSystem`; no
236
- * per-source / per-fact changes are required.
237
- *
238
- * The async PII detector from `pii-enhanced.ts` is unsuitable here:
239
- * `onFactSet` is synchronous and a deferred detection would let the
240
- * raw PII reach observers + breakpoints + audit-ledger before the
241
- * redaction completed. Built-in matching is therefore inlined as
242
- * synchronous regex. Consumers who need richer detection pass a
243
- * synchronous `customDetector`.
244
- *
245
- * ## Observability
246
- *
247
- * Every detection emits a typed `"guardrail.blocked"` `ObservationEvent`
248
- * via `system.observe()` (RFC 0010). Backend wiring (OTel exporters,
249
- * `@directive-run/timeline`, audit-ledger plugins) subscribes to the
250
- * event stream and gets:
251
- *
252
- * ```ts
253
- * {
254
- * type: "guardrail.blocked",
255
- * plugin: "fact-pii-guardrail",
256
- * key: "<fact-key>",
257
- * kind: "redact" | "alert" | "detect",
258
- * count: <number-of-matches>,
259
- * category: "ssn" | "credit_card" | "email" | <customDetector-type>
260
- * }
261
- * ```
262
- *
263
- * The user `onBlocked` callback fires INDEPENDENTLY for backwards
264
- * compatibility and ad-hoc paging (Sentry, Honeycomb). Prefer
265
- * `system.observe()` for new integrations — observers see every
266
- * registered guardrail's activity through the same typed stream.
267
- *
268
- * `kind: "detect"` distinguishes "couldn't redact" from "chose not
269
- * to redact": `Error` instances always surface as `"detect"` because
270
- * the walker matches `Error.message` / `Error.cause` but cannot mint
271
- * a redacted Error with guaranteed `.stack` parity. A subscriber
272
- * counting redactions should sum `kind === "redact" || kind === "detect"`.
273
- *
274
- * @example Defensive (redact PII writes into pii-tagged facts)
275
- * ```ts
276
- * import { createSystem, t } from '@directive-run/core';
277
- * import { createFactPIIGuardrail } from '@directive-run/ai/guardrails';
278
- *
279
- * const customer = createModule('customer', {
280
- * schema: {
281
- * facts: {
282
- * email: t.string().meta({ tags: ['pii'] }),
283
- * ssn: t.string().meta({ tags: ['pii'] }),
284
- * },
285
- * },
286
- * sources: {
287
- * supabase: { attach: (publish) => subscribe(publish) },
288
- * },
289
- * });
290
- *
291
- * const system = createSystem({
292
- * module: customer,
293
- * plugins: [
294
- * createFactPIIGuardrail({
295
- * mode: 'redact',
296
- * onBlocked: (key, detected) => {
297
- * console.warn(`[fact-pii] redacted ${detected.length} match(es) in ${key}`);
298
- * },
299
- * }),
300
- * ],
301
- * });
302
- * ```
303
- *
304
- * @example Monitor-only (alert on every PII match; don't mutate the fact)
305
- * ```ts
306
- * createFactPIIGuardrail({
307
- * mode: 'alert',
308
- * onBlocked: (key) => Sentry.captureException(new Error(`pii match: ${key}`)),
309
- * });
310
- * ```
311
- *
312
- * @example Allow specific keys (not just by tag)
313
- * ```ts
314
- * createFactPIIGuardrail({
315
- * includeKeys: ['customer.email', 'customer.phone'],
316
- * });
317
- * ```
318
- */
319
-
320
- /**
321
- * Public match record for a single PII finding. Mirrors `DetectedPII` from
322
- * `pii-enhanced.ts` so a downstream guardrail can normalize against either
323
- * detection path.
324
- */
325
- interface FactPIIMatch {
326
- type: FactPIICategory;
327
- value: string;
328
- start: number;
329
- end: number;
330
- }
331
- /** PII categories the built-in synchronous detector covers. */
332
- type FactPIICategory = "ssn" | "credit_card" | "email";
333
- /**
334
- * Behavior when a pii-tagged fact's incoming value contains detected PII.
335
- *
336
- * - `"redact"` (default): the fact is rewritten with redacted text (e.g.
337
- * `"[SSN]"`) via a follow-up store write. The system briefly observes
338
- * the raw value during the same microtask the publish landed in, then
339
- * the redacted value overwrites it before any reconcile / agent runs.
340
- * Safe shipping posture for production: the LLM call always sees the
341
- * redacted value.
342
- * - `"alert"`: fire `onBlocked` but DO NOT mutate the fact. The raw value
343
- * stays in the store. Use this for monitoring-only deployments where
344
- * the source's transport is already trusted but a regression detector
345
- * is needed (paging ops on every match).
346
- *
347
- * Note: Directive plugin hooks (`onFactSet`, `onFactsBatch`) are
348
- * wrapped by the plugin manager's `safeCall` so a throw from inside the
349
- * hook is swallowed. The guardrail therefore cannot reject the write
350
- * itself — it can only observe + redact-via-followup-write or alert.
351
- * For hard rejection at the publish boundary, a future RFC will add a
352
- * pre-commit transform hook on the source primitive.
353
- */
354
- type FactPIIGuardrailMode = "redact" | "alert";
355
- interface FactPIIGuardrailOptions {
356
- /** Default: `"redact"` */
357
- mode?: FactPIIGuardrailMode;
358
- /**
359
- * Built-in categories to scan for. Default: all three (`ssn`,
360
- * `credit_card`, `email`). Pass `[]` to opt out of the built-ins and
361
- * rely entirely on `customDetector`.
362
- */
363
- types?: readonly FactPIICategory[];
364
- /**
365
- * Specific fact keys to scan in addition to the auto-detected
366
- * `pii`-tagged set. Useful when a consumer can't change the schema's
367
- * meta but knows the key should be screened.
368
- */
369
- includeKeys?: readonly string[];
370
- /**
371
- * Exclude these fact keys even if they're pii-tagged. Escape hatch for
372
- * a key that's already pre-sanitized upstream of the manager.
373
- */
374
- excludeKeys?: readonly string[];
375
- /**
376
- * Called whenever the guardrail detects PII and acts on it. Receives the
377
- * fact key, the detected matches, and the action that was taken. Fires
378
- * AFTER redact + before any throw in `reject` mode. Use this to alert
379
- * SREs without coupling the guardrail to a specific logging backend.
380
- */
381
- onBlocked?: (key: string, detected: readonly FactPIIMatch[], action: FactPIIGuardrailMode) => void;
382
- /**
383
- * Custom synchronous detector that runs alongside the built-in regex
384
- * scanner. The union of detections is acted on. Useful when the
385
- * consumer ships a domain-specific PII detector (e.g. internal
386
- * account-number format). MUST be synchronous — `onFactSet` cannot
387
- * await deferred work.
388
- */
389
- customDetector?: (text: string) => readonly FactPIIMatch[];
390
- /**
391
- * Maximum nesting depth to walk when scanning a structured fact
392
- * value. Default `2` (raised from `1` in R19 follow-up so the common
393
- * `Error.cause` + shallow-nested-object shapes scan zero-config).
394
- * At depth 2 the scanner inspects top-level strings, recurses into
395
- * nested objects / arrays, AND recurses one more level — enough
396
- * for the Error-with-cause and shallow-nested-object shapes most
397
- * consumers actually ship. Each array level burns one depth slot.
398
- * Maps and Sets are still NOT walked by the built-in scanner; PII
399
- * inside those structures must go through a `customDetector`.
400
- *
401
- * Real-world common shapes and the `walkDepth` they need:
402
- * - **Flat object** (`{ email, ssn }`) — works at any `walkDepth >= 1`.
403
- * - **Nested object** (`{ profile: { email } }`) — needs `walkDepth >= 2`
404
- * (covered by the default).
405
- * - **Error with cause** (`new Error(m, { cause: prev })`) — the cause
406
- * chain is recursed at `depth - 1`, so `walkDepth >= 2` is needed
407
- * to scan one cause level (covered by the default). Deeper cause
408
- * chains (`cause.cause.cause`) need `walkDepth >= 3`.
409
- * - **AggregateError** with nested error PII — `walkDepth >= 2` for
410
- * the first layer; deeper for nested aggregates.
411
- * - **Supabase realtime row payload** (`payload.new = [{ email }]`,
412
- * passed as the fact value) — the fact's value is the object
413
- * `{ new: [...] }`, so the chain is object → array → object →
414
- * string and needs `walkDepth: 4`.
415
- * - **MCP resource notification list** (`{ resources: [{...}] }`) —
416
- * same shape, needs `walkDepth: 4`.
417
- *
418
- * For deeper or non-object structures (Maps, Sets, class instances
419
- * with getters, Symbol-keyed properties), pass a `customDetector`
420
- * that walks the consumer-specific shape and returns concrete
421
- * matches.
422
- *
423
- * **Hard caps for safety:**
424
- * - `walkDepth` clamps to `[1, 5]`. Non-finite values (`NaN`,
425
- * `Infinity`, non-number casts) clamp to `1`.
426
- * - The walker caps any single array's element count at 10,000
427
- * (warns + truncates). Pass a `customDetector` for larger
428
- * payloads.
429
- * - Before walking, the value is passed through `structuredClone`
430
- * to strip any Proxies, exotic getters, Symbol-iterator
431
- * overrides, and functions the consumer might have attached.
432
- * Cyclic inputs throw `DataCloneError` from `structuredClone`
433
- * and the walker treats them as "no match" with a warning.
434
- * Non-cloneable values (functions, DOM nodes, WeakMaps, etc.)
435
- * throw the same way — wire a `customDetector` for those shapes.
436
- *
437
- * Property iteration uses `Object.entries`, which skips
438
- * Symbol-keyed properties and non-enumerable string keys. If you
439
- * store PII under a Symbol key (unusual), a `customDetector` is the
440
- * right escape hatch.
441
- */
442
- walkDepth?: number;
443
- }
444
- /**
445
- * Create a Directive plugin that scans pii-tagged fact writes for PII and
446
- * redacts or rejects them at the manager boundary.
447
- *
448
- * Wire it once at `createSystem({ plugins: [...] })`. The plugin caches
449
- * the pii-tagged key set on `onInit` so per-write hooks are O(1) lookups.
450
- *
451
- * @returns a `Plugin` instance ready to add to `SystemConfig.plugins`.
452
- */
453
- declare function createFactPIIGuardrail(options?: FactPIIGuardrailOptions): Plugin;
454
-
455
- /**
456
- * Enhanced PII Detection Guardrail
457
- *
458
- * Provides comprehensive PII detection beyond basic regex patterns:
459
- * - Multiple PII types (SSN, credit cards, emails, phones, addresses, names)
460
- * - Pluggable detection backends (regex, custom, or external services)
461
- * - Context-aware detection (reduces false positives)
462
- * - Redaction with reversible or irreversible options
463
- *
464
- * @example
465
- * ```typescript
466
- * import { createEnhancedPIIGuardrail } from '@directive-run/ai';
467
- *
468
- * const guardrail = createEnhancedPIIGuardrail({
469
- * types: ['ssn', 'credit_card', 'email'],
470
- * redact: true,
471
- * detector: 'regex', // or 'custom' with custom detector
472
- * });
473
- * ```
474
- */
475
-
476
- /** Supported PII types */
477
- type PIIType = "ssn" | "credit_card" | "email" | "phone" | "address" | "name" | "date_of_birth" | "passport" | "driver_license" | "ip_address" | "bank_account" | "medical_id" | "national_id";
478
- /** Detected PII instance */
479
- interface DetectedPII {
480
- type: PIIType;
481
- value: string;
482
- position: {
483
- start: number;
484
- end: number;
485
- };
486
- confidence: number;
487
- context?: string;
488
- }
489
- /** PII detection result */
490
- interface PIIDetectionResult {
491
- detected: boolean;
492
- items: DetectedPII[];
493
- typeCounts: Partial<Record<PIIType, number>>;
494
- /** Text with PII redacted (if requested) */
495
- redactedText?: string;
496
- }
497
- /** Custom PII detector interface */
498
- interface PIIDetector {
499
- detect(text: string, types: PIIType[]): Promise<DetectedPII[]>;
500
- name: string;
501
- }
502
- /** Redaction style */
503
- type RedactionStyle =
504
- /** Replace with [REDACTED] */
505
- "placeholder"
506
- /** Replace with type-specific placeholder like [EMAIL] */
507
- | "typed"
508
- /**
509
- * Replace with a fixed-width `****` mask plus the last 4 characters
510
- * (e.g. `****6789`). Does not preserve or reveal the original length.
511
- */
512
- | "masked"
513
- /**
514
- * Replace with a deterministic FNV-1a hash.
515
- *
516
- * **WARNING — this is PSEUDONYMIZATION, not anonymization.** FNV-1a is a
517
- * fast, non-cryptographic 32-bit hash. For low-entropy structured PII (SSNs,
518
- * card numbers, phone numbers) the output is trivially RE-IDENTIFIABLE via
519
- * brute force or a precomputed rainbow table. It MUST NOT be relied on for
520
- * GDPR / HIPAA de-identification. Use it only for referential integrity
521
- * (correlating the same value across audit logs).
522
- */
523
- | "hashed";
524
- /** Redact detected PII from text */
525
- declare function redactPII(text: string, items: DetectedPII[], style?: RedactionStyle): string;
526
- /** Options for enhanced PII guardrail */
527
- interface EnhancedPIIGuardrailOptions {
528
- /** PII types to detect (default: all) */
529
- types?: PIIType[];
530
- /** Detection backend (default: 'regex') */
531
- detector?: "regex" | PIIDetector;
532
- /** Redact instead of blocking */
533
- redact?: boolean;
534
- /** Redaction style (default: 'typed') */
535
- redactionStyle?: RedactionStyle;
536
- /** Minimum confidence to flag (0-1, default: 0.7) */
537
- minConfidence?: number;
538
- /** Callback when PII is detected */
539
- onDetected?: (items: DetectedPII[]) => void;
540
- /** Allow specific values (whitelist) */
541
- allowlist?: string[];
542
- /** Block only if count exceeds threshold */
543
- minItemsToBlock?: number;
544
- /** Timeout for custom detector in milliseconds (default: 5000) */
545
- detectorTimeout?: number;
546
- }
547
- /**
548
- * Create an enhanced PII detection guardrail.
549
- *
550
- * @example
551
- * ```typescript
552
- * // Basic usage
553
- * const guardrail = createEnhancedPIIGuardrail();
554
- *
555
- * // Redact instead of blocking
556
- * const redactGuardrail = createEnhancedPIIGuardrail({
557
- * redact: true,
558
- * redactionStyle: 'masked',
559
- * });
560
- *
561
- * // Custom detection with external service
562
- * const customGuardrail = createEnhancedPIIGuardrail({
563
- * detector: myPresidioDetector,
564
- * types: ['ssn', 'credit_card', 'medical_id'],
565
- * });
566
- * ```
567
- */
568
- declare function createEnhancedPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<InputGuardrailData>;
569
- /**
570
- * Create an output PII guardrail (for checking agent responses).
571
- *
572
- * @example
573
- * ```typescript
574
- * const outputGuardrail = createOutputPIIGuardrail({
575
- * types: ['ssn', 'credit_card'],
576
- * redact: true,
577
- * });
578
- * ```
579
- */
580
- declare function createOutputPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<OutputGuardrailData>;
581
- /**
582
- * Detect PII in text without using as a guardrail.
583
- * Useful for analysis and logging.
584
- *
585
- * @example
586
- * ```typescript
587
- * const result = await detectPII('My SSN is 123-45-6789');
588
- * console.log(result.items); // [{ type: 'ssn', value: '123-45-6789', ... }]
589
- *
590
- * // With custom detector and timeout
591
- * const result = await detectPII(text, {
592
- * detector: myPresidioDetector,
593
- * timeout: 10000, // 10 seconds
594
- * });
595
- * ```
596
- */
597
- declare function detectPII(text: string, options?: {
598
- types?: PIIType[];
599
- detector?: "regex" | PIIDetector;
600
- minConfidence?: number;
601
- /** Timeout for custom detectors in milliseconds (default: 5000) */
602
- timeout?: number;
603
- }): Promise<PIIDetectionResult>;
604
- /**
605
- * Detect PII in text and return a result whose `redactedText` is populated.
606
- *
607
- * This composes {@link detectPII} and {@link redactPII} so callers do not have
608
- * to manually wire the two together (and do not have to mutate the detection
609
- * result). When no PII is detected, `redactedText` is left `undefined` — it is
610
- * deliberately NOT defaulted to the raw input.
611
- *
612
- * @example
613
- * ```typescript
614
- * const result = await detectAndRedactPII('My SSN is 123-45-6789', {
615
- * types: ['ssn'],
616
- * style: 'typed',
617
- * });
618
- * console.log(result.detected); // true
619
- * // ssn is a sensitive-category type, so `typed` emits a generic [REDACTED]
620
- * console.log(result.redactedText); // 'My SSN is [REDACTED]'
621
- *
622
- * const clean = await detectAndRedactPII('nothing here', { types: ['ssn'] });
623
- * console.log(clean.detected); // false
624
- * console.log(clean.redactedText); // undefined
625
- * ```
626
- */
627
- declare function detectAndRedactPII(text: string, options?: {
628
- types?: PIIType[];
629
- detector?: "regex" | PIIDetector;
630
- minConfidence?: number;
631
- /** Timeout for custom detectors in milliseconds (default: 5000) */
632
- timeout?: number;
633
- /** Redaction style applied when PII is detected (default: 'typed') */
634
- style?: RedactionStyle;
635
- }): Promise<PIIDetectionResult>;
636
-
637
- /**
638
- * Prompt Injection Detection Guardrail
639
- *
640
- * Detects and blocks prompt injection attacks including:
641
- * - Direct injection attempts ("ignore previous instructions")
642
- * - Jailbreak patterns ("DAN mode", "pretend you can")
643
- * - Indirect injection via external content
644
- * - Encoding-based evasion attempts
645
- *
646
- * @example
647
- * ```typescript
648
- * import { createPromptInjectionGuardrail } from '@directive-run/ai';
649
- *
650
- * const guardrail = createPromptInjectionGuardrail({
651
- * strictMode: true,
652
- * onBlocked: (input, patterns) => logSecurityEvent(input, patterns),
653
- * });
654
- * ```
655
- */
656
-
657
- /** Pattern with metadata for better debugging */
658
- interface InjectionPattern {
659
- pattern: RegExp;
660
- name: string;
661
- severity: "low" | "medium" | "high" | "critical";
662
- category: InjectionCategory;
663
- }
664
- /** Categories of injection attacks */
665
- type InjectionCategory = "instruction_override" | "jailbreak" | "role_manipulation" | "encoding_evasion" | "delimiter_injection" | "context_manipulation" | "indirect_injection";
666
- /** Default injection patterns - well-tested and low false-positive rate */
667
- declare const DEFAULT_INJECTION_PATTERNS: InjectionPattern[];
668
- /** Strict patterns - more aggressive, may have higher false positives */
669
- declare const STRICT_INJECTION_PATTERNS: InjectionPattern[];
670
- /** Detailed detection result */
671
- interface InjectionDetectionResult {
672
- detected: boolean;
673
- patterns: Array<{
674
- name: string;
675
- category: InjectionCategory;
676
- severity: InjectionPattern["severity"];
677
- match: string;
678
- position: number;
679
- }>;
680
- riskScore: number;
681
- sanitizedInput?: string;
682
- }
683
- /**
684
- * Detect prompt injection patterns in text.
685
- * Returns detailed results about what was detected.
686
- *
687
- * @throws Error if input exceeds MAX_INJECTION_INPUT_LENGTH (100KB)
688
- */
689
- declare function detectPromptInjection(text: string, patterns?: InjectionPattern[]): InjectionDetectionResult;
690
- /**
691
- * Sanitize text by removing detected injection patterns.
692
- * Warning: This is a best-effort sanitization, not a security guarantee.
693
- *
694
- * Uses a single-pass approach to prevent infinite loops where a replacement
695
- * could create a new pattern match.
696
- */
697
- declare function sanitizeInjection(text: string, patterns?: InjectionPattern[]): string;
698
- /** Options for prompt injection guardrail */
699
- interface PromptInjectionGuardrailOptions {
700
- /** Additional patterns to check (added to defaults) */
701
- additionalPatterns?: InjectionPattern[];
702
- /** Replace default patterns entirely */
703
- replacePatterns?: InjectionPattern[];
704
- /** Use strict mode with more aggressive detection */
705
- strictMode?: boolean;
706
- /** Minimum risk score to block (0-100, default: 50) */
707
- blockThreshold?: number;
708
- /** Attempt to sanitize instead of blocking */
709
- sanitize?: boolean;
710
- /** Callback when injection is detected */
711
- onBlocked?: (input: string, result: InjectionDetectionResult) => void;
712
- /** Categories to ignore (e.g., allow 'role_manipulation' for roleplay apps) */
713
- ignoreCategories?: InjectionCategory[];
714
- }
715
- /**
716
- * Create a prompt injection detection guardrail.
717
- *
718
- * @example
719
- * ```typescript
720
- * // Basic usage
721
- * const guardrail = createPromptInjectionGuardrail();
722
- *
723
- * // Strict mode for high-security applications
724
- * const strictGuardrail = createPromptInjectionGuardrail({
725
- * strictMode: true,
726
- * blockThreshold: 25,
727
- * });
728
- *
729
- * // Allow role manipulation for roleplay apps
730
- * const roleplayGuardrail = createPromptInjectionGuardrail({
731
- * ignoreCategories: ['role_manipulation'],
732
- * });
733
- * ```
734
- */
735
- declare function createPromptInjectionGuardrail(options?: PromptInjectionGuardrailOptions): GuardrailFn<InputGuardrailData>;
736
- /**
737
- * Mark content as potentially untrusted (from external sources).
738
- * This wraps the content with markers that injection detection will scrutinize more closely.
739
- *
740
- * @example
741
- * ```typescript
742
- * const userUpload = await readFile(path);
743
- * const markedContent = markUntrustedContent(userUpload, 'user-upload');
744
- * const prompt = `Summarize this document: ${markedContent}`;
745
- * ```
746
- */
747
- declare function markUntrustedContent(content: string, source: string): string;
748
- /**
749
- * Create a guardrail that applies stricter checks to marked untrusted content.
750
- *
751
- * @example
752
- * ```typescript
753
- * const guardrail = createUntrustedContentGuardrail({
754
- * baseGuardrail: createPromptInjectionGuardrail({ strictMode: true }),
755
- * });
756
- * ```
757
- */
758
- declare function createUntrustedContentGuardrail(options: {
759
- /** Guardrail to apply to untrusted sections */
760
- baseGuardrail?: GuardrailFn<InputGuardrailData>;
761
- /** Block if untrusted content contains these patterns */
762
- additionalPatterns?: InjectionPattern[];
763
- }): GuardrailFn<InputGuardrailData>;
764
-
765
- /**
766
- * Approximate Nearest Neighbor (ANN) Index for Semantic Cache
767
- *
768
- * Provides pluggable vector search backends for efficient similarity lookups.
769
- * Includes a brute-force exact search and a VP-tree (Vantage Point Tree) for
770
- * fast approximate nearest neighbor queries.
771
- *
772
- * @example
773
- * ```typescript
774
- * import { createSemanticCache } from '@directive-run/ai';
775
- * import { createVPTreeIndex } from '@directive-run/ai';
776
- *
777
- * const index = createVPTreeIndex();
778
- *
779
- * const cache = createSemanticCache({
780
- * embedder: myEmbedder,
781
- * annIndex: index,
782
- * });
783
- * ```
784
- */
785
-
786
- /** Search result from an ANN index */
787
- interface ANNSearchResult {
788
- /** ID of the matched item */
789
- id: number;
790
- /** Similarity score (0-1, higher is more similar) */
791
- similarity: number;
792
- }
793
- /** ANN Index interface - pluggable vector search backend */
794
- interface ANNIndex {
795
- /** Add a vector to the index */
796
- add(id: number, embedding: Embedding): void;
797
- /** Remove a vector from the index */
798
- remove(id: number): void;
799
- /** Search for the k nearest neighbors */
800
- search(query: Embedding, k: number, threshold?: number): ANNSearchResult[];
801
- /** Rebuild the index (call after batch additions) */
802
- rebuild(): void;
803
- /** Get the number of indexed vectors */
804
- size(): number;
805
- /** Clear the index */
806
- clear(): void;
807
- /** Check if the index needs to be rebuilt (e.g., after additions/removals) */
808
- needsRebuild(): boolean;
809
- }
810
- /**
811
- * Create a brute-force exact search index.
812
- *
813
- * O(n) search, O(1) add/remove. Best for small collections (< 10,000 vectors).
814
- *
815
- * @example
816
- * ```typescript
817
- * const index = createBruteForceIndex();
818
- * index.add(0, [0.1, 0.2, 0.3]);
819
- * index.add(1, [0.4, 0.5, 0.6]);
820
- *
821
- * const results = index.search([0.1, 0.2, 0.3], 1);
822
- * // [{ id: 0, similarity: 1.0 }]
823
- * ```
824
- */
825
- declare function createBruteForceIndex(): ANNIndex;
826
- /** VP-Tree index configuration */
827
- interface VPTreeIndexConfig {
828
- /** Optional random number generator for deterministic builds. Returns a number in [0, 1). */
829
- random?: () => number;
830
- }
831
- /**
832
- * Create a VP-Tree (Vantage Point Tree) index for efficient approximate nearest neighbor search.
833
- *
834
- * O(log n) search on average, requires rebuild after batch additions.
835
- * Best for medium collections (1,000 - 100,000 vectors).
836
- *
837
- * @example
838
- * ```typescript
839
- * const index = createVPTreeIndex();
840
- *
841
- * // Add vectors
842
- * for (let i = 0; i < embeddings.length; i++) {
843
- * index.add(i, embeddings[i]);
844
- * }
845
- *
846
- * // Build the tree
847
- * index.rebuild();
848
- *
849
- * // Search
850
- * const results = index.search(queryEmbedding, 5, 0.9);
851
- * ```
852
- */
853
- declare function createVPTreeIndex(vpConfig?: VPTreeIndexConfig): ANNIndex;
854
-
855
- export { type ANNIndex, type ANNSearchResult, DEFAULT_INJECTION_PATTERNS, type DetectedPII, Embedding, type EnhancedPIIGuardrailOptions, type FactPIICategory, type FactPIIGuardrailMode, type FactPIIGuardrailOptions, type FactPIIMatch, type InjectionDetectionResult, type PIIDetectionResult, type PIIDetector, type PIIType, type PromptInjectionGuardrailOptions, type RateLimitGuardrail, type RedactionStyle, STRICT_INJECTION_PATTERNS, type VPTreeIndexConfig, createBruteForceIndex, createContentFilterGuardrail, createEnhancedPIIGuardrail, createFactPIIGuardrail, createLengthGuardrail, createModerationGuardrail, createOutputPIIGuardrail, createOutputSchemaGuardrail, createOutputTypeGuardrail, createPIIGuardrail, createPromptInjectionGuardrail, createRateLimitGuardrail, createToolGuardrail, createUntrustedContentGuardrail, createVPTreeIndex, detectAndRedactPII, detectPII, detectPromptInjection, markUntrustedContent, redactPII, sanitizeInjection };
1
+ export { A as ANNIndex, a as ANNSearchResult, D as DEFAULT_INJECTION_PATTERNS, b as DetectedPII, E as EnhancedPIIGuardrailOptions, F as FactPIICategory, d as FactPIIGuardrailMode, e as FactPIIGuardrailOptions, f as FactPIIMatch, I as InjectionDetectionResult, g as PIIDetectionResult, h as PIIDetector, P as PIIType, i as PromptInjectionGuardrailOptions, j as RateLimitGuardrail, R as RedactionStyle, S as STRICT_INJECTION_PATTERNS, V as VPTreeIndexConfig, k as createBruteForceIndex, l as createContentFilterGuardrail, m as createEnhancedPIIGuardrail, n as createFactPIIGuardrail, o as createLengthGuardrail, p as createModerationGuardrail, q as createOutputPIIGuardrail, r as createOutputSchemaGuardrail, s as createOutputTypeGuardrail, t as createPIIGuardrail, u as createPromptInjectionGuardrail, v as createRateLimitGuardrail, w as createToolGuardrail, x as createUntrustedContentGuardrail, y as createVPTreeIndex, z as detectAndRedactPII, B as detectPII, C as detectPromptInjection, G as markUntrustedContent, H as redactPII, J as sanitizeInjection } from './guardrails-export-D3pKHiPp.cjs';
2
+ export { B as BatchedEmbedder, C as CacheEntry, b as CacheLookupResult, c as CacheStats, E as EmbedderFn, a as Embedding, S as SemanticCache, d as SemanticCacheConfig, e as SemanticCacheStorage, f as createBatchedEmbedder, g as createInMemoryStorage, h as createSemanticCache, i as createSemanticCacheGuardrail, j as createTestEmbedder } from './semantic-cache-DM7ev7NQ.cjs';
3
+ import './types-DJ09LjZX.cjs';
4
+ import '@directive-run/core';