@directive-run/ai 1.18.0 → 1.19.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/dist/ann-index-27QV9tPC.d.ts +616 -0
- package/dist/ann-index-HoZFIUA-.d.cts +616 -0
- package/dist/anthropic.d.cts +1 -1
- package/dist/anthropic.d.ts +1 -1
- package/dist/{chunk-UZKM276C.cjs → chunk-2PG26JZU.cjs} +4 -4
- package/dist/chunk-2PG26JZU.cjs.map +1 -0
- package/dist/chunk-MIHH5GPT.js +16 -0
- package/dist/chunk-MIHH5GPT.js.map +1 -0
- package/dist/{debug-timeline-L13P-U2I.d.ts → debug-timeline-BGcPa0JO.d.ts} +1 -1
- package/dist/{debug-timeline-DpnRMnLU.d.cts → debug-timeline-Dn1lC_gK.d.cts} +1 -1
- package/dist/devtools.d.cts +5 -5
- package/dist/devtools.d.ts +5 -5
- package/dist/evals.d.cts +2 -2
- package/dist/evals.d.ts +2 -2
- package/dist/gemini.d.cts +1 -1
- package/dist/gemini.d.ts +1 -1
- package/dist/guardrails.cjs +1 -1
- package/dist/guardrails.cjs.map +1 -1
- package/dist/guardrails.d.cts +164 -592
- package/dist/guardrails.d.ts +164 -592
- package/dist/guardrails.js +1 -1
- package/dist/guardrails.js.map +1 -1
- package/dist/{health-monitor-C6xoXrQz.d.cts → health-monitor-Cq5sDvid.d.cts} +1 -1
- package/dist/{health-monitor-qL9RNMH3.d.ts → health-monitor-DtwmIJkb.d.ts} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +1 -1
- package/dist/multi-agent.d.cts +6 -6
- package/dist/multi-agent.d.ts +6 -6
- package/dist/ollama.d.cts +1 -1
- package/dist/ollama.d.ts +1 -1
- package/dist/openai.d.cts +2 -2
- package/dist/openai.d.ts +2 -2
- package/dist/{orchestrator-types-D5cFRt3s.d.ts → orchestrator-types-C5D5JZUj.d.ts} +8 -23
- package/dist/{orchestrator-types-Dlfcvdxw.d.cts → orchestrator-types-s0766dDB.d.cts} +8 -23
- package/dist/predicate.d.cts +1 -1
- package/dist/predicate.d.ts +1 -1
- package/dist/{semantic-cache-DM7ev7NQ.d.cts → semantic-cache-Ba0-jEwb.d.cts} +1 -1
- package/dist/{semantic-cache-DM7ev7NQ.d.ts → semantic-cache-Ba0-jEwb.d.ts} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +4 -4
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +1 -1
- package/dist/{types-DJ09LjZX.d.cts → types-CUp1N0uU.d.cts} +1 -1
- package/dist/{types-DJ09LjZX.d.ts → types-CUp1N0uU.d.ts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-D72LIBH2.js +0 -16
- package/dist/chunk-D72LIBH2.js.map +0 -1
- package/dist/chunk-UZKM276C.cjs.map +0 -1
package/dist/guardrails.d.ts
CHANGED
|
@@ -1,618 +1,190 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
export { B as BatchedEmbedder, C as CacheEntry,
|
|
4
|
-
import '
|
|
1
|
+
export { A as ANNIndex, a as ANNSearchResult, D as DEFAULT_INJECTION_PATTERNS, b as DetectedPII, E as EnhancedPIIGuardrailOptions, I as InjectionDetectionResult, P as PIIDetectionResult, c as PIIDetector, d as PIIType, e as PromptInjectionGuardrailOptions, R as RateLimitGuardrail, f as RedactionStyle, S as STRICT_INJECTION_PATTERNS, V as VPTreeIndexConfig, g as createBruteForceIndex, h as createContentFilterGuardrail, i as createEnhancedPIIGuardrail, j as createLengthGuardrail, k as createModerationGuardrail, l as createOutputPIIGuardrail, m as createOutputSchemaGuardrail, n as createOutputTypeGuardrail, o as createPIIGuardrail, p as createPromptInjectionGuardrail, q as createRateLimitGuardrail, r as createToolGuardrail, s as createUntrustedContentGuardrail, t as createVPTreeIndex, u as detectAndRedactPII, v as detectPII, w as detectPromptInjection, x as markUntrustedContent, y as redactPII, z as sanitizeInjection } from './ann-index-27QV9tPC.js';
|
|
2
|
+
import { Plugin } from '@directive-run/core';
|
|
3
|
+
export { B as BatchedEmbedder, C as CacheEntry, a as CacheLookupResult, b as CacheStats, E as EmbedderFn, c 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-Ba0-jEwb.js';
|
|
4
|
+
import './types-CUp1N0uU.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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;
|
|
7
|
+
* Fact-PII Guardrail — input guardrail at the fact-store boundary
|
|
8
|
+
*
|
|
9
|
+
* Closes the source → fact → agent prompt PII bypass surfaced by R5's
|
|
10
|
+
* red-team / privacy / AI-integration reviewers: `createPIIGuardrail`
|
|
11
|
+
* only inspects the `data.input` string at runStream entry, so PII that
|
|
12
|
+
* a source publishes into a fact (a Supabase realtime row carrying a
|
|
13
|
+
* customer email, a webhook payload with a SSN, an MCP server's
|
|
14
|
+
* resource notification with a card number) reaches the agent's
|
|
15
|
+
* prompt — via fact injection — without ever hitting the input
|
|
16
|
+
* guardrail chain.
|
|
17
|
+
*
|
|
18
|
+
* This plugin runs as a Directive plugin (`onFactSet` / `onFactsBatch`),
|
|
19
|
+
* scans every write to a pii-tagged fact against a sync regex matcher
|
|
20
|
+
* for the three highest-volume PII categories (SSN, credit card, email),
|
|
21
|
+
* and either **redacts** the value (the default — safe shipping posture)
|
|
22
|
+
* or **rejects** the write (throws so the source's publish handler can
|
|
23
|
+
* surface the violation). Operators wire it once at `createSystem`; no
|
|
24
|
+
* per-source / per-fact changes are required.
|
|
25
|
+
*
|
|
26
|
+
* The async PII detector from `pii-enhanced.ts` is unsuitable here:
|
|
27
|
+
* `onFactSet` is synchronous and a deferred detection would let the
|
|
28
|
+
* raw PII reach observers + breakpoints + audit-ledger before the
|
|
29
|
+
* redaction completed. Built-in matching is therefore inlined as
|
|
30
|
+
* synchronous regex. Consumers who need richer detection pass a
|
|
31
|
+
* synchronous `customDetector`.
|
|
32
|
+
*
|
|
33
|
+
* @example Defensive (redact PII writes into pii-tagged facts)
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { createSystem, t } from '@directive-run/core';
|
|
36
|
+
* import { createFactPIIGuardrail } from '@directive-run/ai/guardrails';
|
|
37
|
+
*
|
|
38
|
+
* const customer = createModule('customer', {
|
|
39
|
+
* schema: {
|
|
40
|
+
* facts: {
|
|
41
|
+
* email: t.string().meta({ tags: ['pii'] }),
|
|
42
|
+
* ssn: t.string().meta({ tags: ['pii'] }),
|
|
43
|
+
* },
|
|
50
44
|
* },
|
|
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) };
|
|
45
|
+
* sources: {
|
|
46
|
+
* supabase: { attach: (publish) => subscribe(publish) },
|
|
126
47
|
* },
|
|
127
48
|
* });
|
|
128
|
-
* ```
|
|
129
49
|
*
|
|
130
|
-
*
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*
|
|
138
|
-
*
|
|
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',
|
|
50
|
+
* const system = createSystem({
|
|
51
|
+
* module: customer,
|
|
52
|
+
* plugins: [
|
|
53
|
+
* createFactPIIGuardrail({
|
|
54
|
+
* mode: 'redact',
|
|
55
|
+
* onBlocked: (key, detected) => {
|
|
56
|
+
* console.warn(`[fact-pii] redacted ${detected.length} match(es) in ${key}`);
|
|
57
|
+
* },
|
|
58
|
+
* }),
|
|
205
59
|
* ],
|
|
206
60
|
* });
|
|
207
61
|
* ```
|
|
208
62
|
*
|
|
209
|
-
* @
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
/** Case-sensitive matching for string patterns (default: false) */
|
|
215
|
-
caseSensitive?: boolean;
|
|
216
|
-
}): GuardrailFn<OutputGuardrailData>;
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Enhanced PII Detection Guardrail
|
|
220
|
-
*
|
|
221
|
-
* Provides comprehensive PII detection beyond basic regex patterns:
|
|
222
|
-
* - Multiple PII types (SSN, credit cards, emails, phones, addresses, names)
|
|
223
|
-
* - Pluggable detection backends (regex, custom, or external services)
|
|
224
|
-
* - Context-aware detection (reduces false positives)
|
|
225
|
-
* - Redaction with reversible or irreversible options
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* ```typescript
|
|
229
|
-
* import { createEnhancedPIIGuardrail } from '@directive-run/ai';
|
|
230
|
-
*
|
|
231
|
-
* const guardrail = createEnhancedPIIGuardrail({
|
|
232
|
-
* types: ['ssn', 'credit_card', 'email'],
|
|
233
|
-
* redact: true,
|
|
234
|
-
* detector: 'regex', // or 'custom' with custom detector
|
|
235
|
-
* });
|
|
236
|
-
* ```
|
|
237
|
-
*/
|
|
238
|
-
|
|
239
|
-
/** Supported PII types */
|
|
240
|
-
type PIIType = "ssn" | "credit_card" | "email" | "phone" | "address" | "name" | "date_of_birth" | "passport" | "driver_license" | "ip_address" | "bank_account" | "medical_id" | "national_id";
|
|
241
|
-
/** Detected PII instance */
|
|
242
|
-
interface DetectedPII {
|
|
243
|
-
type: PIIType;
|
|
244
|
-
value: string;
|
|
245
|
-
position: {
|
|
246
|
-
start: number;
|
|
247
|
-
end: number;
|
|
248
|
-
};
|
|
249
|
-
confidence: number;
|
|
250
|
-
context?: string;
|
|
251
|
-
}
|
|
252
|
-
/** PII detection result */
|
|
253
|
-
interface PIIDetectionResult {
|
|
254
|
-
detected: boolean;
|
|
255
|
-
items: DetectedPII[];
|
|
256
|
-
typeCounts: Partial<Record<PIIType, number>>;
|
|
257
|
-
/** Text with PII redacted (if requested) */
|
|
258
|
-
redactedText?: string;
|
|
259
|
-
}
|
|
260
|
-
/** Custom PII detector interface */
|
|
261
|
-
interface PIIDetector {
|
|
262
|
-
detect(text: string, types: PIIType[]): Promise<DetectedPII[]>;
|
|
263
|
-
name: string;
|
|
264
|
-
}
|
|
265
|
-
/** Redaction style */
|
|
266
|
-
type RedactionStyle =
|
|
267
|
-
/** Replace with [REDACTED] */
|
|
268
|
-
"placeholder"
|
|
269
|
-
/** Replace with type-specific placeholder like [EMAIL] */
|
|
270
|
-
| "typed"
|
|
271
|
-
/**
|
|
272
|
-
* Replace with a fixed-width `****` mask plus the last 4 characters
|
|
273
|
-
* (e.g. `****6789`). Does not preserve or reveal the original length.
|
|
274
|
-
*/
|
|
275
|
-
| "masked"
|
|
276
|
-
/**
|
|
277
|
-
* Replace with a deterministic FNV-1a hash.
|
|
278
|
-
*
|
|
279
|
-
* **WARNING — this is PSEUDONYMIZATION, not anonymization.** FNV-1a is a
|
|
280
|
-
* fast, non-cryptographic 32-bit hash. For low-entropy structured PII (SSNs,
|
|
281
|
-
* card numbers, phone numbers) the output is trivially RE-IDENTIFIABLE via
|
|
282
|
-
* brute force or a precomputed rainbow table. It MUST NOT be relied on for
|
|
283
|
-
* GDPR / HIPAA de-identification. Use it only for referential integrity
|
|
284
|
-
* (correlating the same value across audit logs).
|
|
285
|
-
*/
|
|
286
|
-
| "hashed";
|
|
287
|
-
/** Redact detected PII from text */
|
|
288
|
-
declare function redactPII(text: string, items: DetectedPII[], style?: RedactionStyle): string;
|
|
289
|
-
/** Options for enhanced PII guardrail */
|
|
290
|
-
interface EnhancedPIIGuardrailOptions {
|
|
291
|
-
/** PII types to detect (default: all) */
|
|
292
|
-
types?: PIIType[];
|
|
293
|
-
/** Detection backend (default: 'regex') */
|
|
294
|
-
detector?: "regex" | PIIDetector;
|
|
295
|
-
/** Redact instead of blocking */
|
|
296
|
-
redact?: boolean;
|
|
297
|
-
/** Redaction style (default: 'typed') */
|
|
298
|
-
redactionStyle?: RedactionStyle;
|
|
299
|
-
/** Minimum confidence to flag (0-1, default: 0.7) */
|
|
300
|
-
minConfidence?: number;
|
|
301
|
-
/** Callback when PII is detected */
|
|
302
|
-
onDetected?: (items: DetectedPII[]) => void;
|
|
303
|
-
/** Allow specific values (whitelist) */
|
|
304
|
-
allowlist?: string[];
|
|
305
|
-
/** Block only if count exceeds threshold */
|
|
306
|
-
minItemsToBlock?: number;
|
|
307
|
-
/** Timeout for custom detector in milliseconds (default: 5000) */
|
|
308
|
-
detectorTimeout?: number;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Create an enhanced PII detection guardrail.
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```typescript
|
|
315
|
-
* // Basic usage
|
|
316
|
-
* const guardrail = createEnhancedPIIGuardrail();
|
|
317
|
-
*
|
|
318
|
-
* // Redact instead of blocking
|
|
319
|
-
* const redactGuardrail = createEnhancedPIIGuardrail({
|
|
320
|
-
* redact: true,
|
|
321
|
-
* redactionStyle: 'masked',
|
|
322
|
-
* });
|
|
323
|
-
*
|
|
324
|
-
* // Custom detection with external service
|
|
325
|
-
* const customGuardrail = createEnhancedPIIGuardrail({
|
|
326
|
-
* detector: myPresidioDetector,
|
|
327
|
-
* types: ['ssn', 'credit_card', 'medical_id'],
|
|
328
|
-
* });
|
|
329
|
-
* ```
|
|
330
|
-
*/
|
|
331
|
-
declare function createEnhancedPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<InputGuardrailData>;
|
|
332
|
-
/**
|
|
333
|
-
* Create an output PII guardrail (for checking agent responses).
|
|
334
|
-
*
|
|
335
|
-
* @example
|
|
336
|
-
* ```typescript
|
|
337
|
-
* const outputGuardrail = createOutputPIIGuardrail({
|
|
338
|
-
* types: ['ssn', 'credit_card'],
|
|
339
|
-
* redact: true,
|
|
340
|
-
* });
|
|
341
|
-
* ```
|
|
342
|
-
*/
|
|
343
|
-
declare function createOutputPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<OutputGuardrailData>;
|
|
344
|
-
/**
|
|
345
|
-
* Detect PII in text without using as a guardrail.
|
|
346
|
-
* Useful for analysis and logging.
|
|
347
|
-
*
|
|
348
|
-
* @example
|
|
349
|
-
* ```typescript
|
|
350
|
-
* const result = await detectPII('My SSN is 123-45-6789');
|
|
351
|
-
* console.log(result.items); // [{ type: 'ssn', value: '123-45-6789', ... }]
|
|
352
|
-
*
|
|
353
|
-
* // With custom detector and timeout
|
|
354
|
-
* const result = await detectPII(text, {
|
|
355
|
-
* detector: myPresidioDetector,
|
|
356
|
-
* timeout: 10000, // 10 seconds
|
|
357
|
-
* });
|
|
358
|
-
* ```
|
|
359
|
-
*/
|
|
360
|
-
declare function detectPII(text: string, options?: {
|
|
361
|
-
types?: PIIType[];
|
|
362
|
-
detector?: "regex" | PIIDetector;
|
|
363
|
-
minConfidence?: number;
|
|
364
|
-
/** Timeout for custom detectors in milliseconds (default: 5000) */
|
|
365
|
-
timeout?: number;
|
|
366
|
-
}): Promise<PIIDetectionResult>;
|
|
367
|
-
/**
|
|
368
|
-
* Detect PII in text and return a result whose `redactedText` is populated.
|
|
369
|
-
*
|
|
370
|
-
* This composes {@link detectPII} and {@link redactPII} so callers do not have
|
|
371
|
-
* to manually wire the two together (and do not have to mutate the detection
|
|
372
|
-
* result). When no PII is detected, `redactedText` is left `undefined` — it is
|
|
373
|
-
* deliberately NOT defaulted to the raw input.
|
|
374
|
-
*
|
|
375
|
-
* @example
|
|
376
|
-
* ```typescript
|
|
377
|
-
* const result = await detectAndRedactPII('My SSN is 123-45-6789', {
|
|
378
|
-
* types: ['ssn'],
|
|
379
|
-
* style: 'typed',
|
|
63
|
+
* @example Monitor-only (alert on every PII match; don't mutate the fact)
|
|
64
|
+
* ```ts
|
|
65
|
+
* createFactPIIGuardrail({
|
|
66
|
+
* mode: 'alert',
|
|
67
|
+
* onBlocked: (key) => Sentry.captureException(new Error(`pii match: ${key}`)),
|
|
380
68
|
* });
|
|
381
|
-
* console.log(result.detected); // true
|
|
382
|
-
* // ssn is a sensitive-category type, so `typed` emits a generic [REDACTED]
|
|
383
|
-
* console.log(result.redactedText); // 'My SSN is [REDACTED]'
|
|
384
|
-
*
|
|
385
|
-
* const clean = await detectAndRedactPII('nothing here', { types: ['ssn'] });
|
|
386
|
-
* console.log(clean.detected); // false
|
|
387
|
-
* console.log(clean.redactedText); // undefined
|
|
388
69
|
* ```
|
|
389
|
-
*/
|
|
390
|
-
declare function detectAndRedactPII(text: string, options?: {
|
|
391
|
-
types?: PIIType[];
|
|
392
|
-
detector?: "regex" | PIIDetector;
|
|
393
|
-
minConfidence?: number;
|
|
394
|
-
/** Timeout for custom detectors in milliseconds (default: 5000) */
|
|
395
|
-
timeout?: number;
|
|
396
|
-
/** Redaction style applied when PII is detected (default: 'typed') */
|
|
397
|
-
style?: RedactionStyle;
|
|
398
|
-
}): Promise<PIIDetectionResult>;
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Prompt Injection Detection Guardrail
|
|
402
|
-
*
|
|
403
|
-
* Detects and blocks prompt injection attacks including:
|
|
404
|
-
* - Direct injection attempts ("ignore previous instructions")
|
|
405
|
-
* - Jailbreak patterns ("DAN mode", "pretend you can")
|
|
406
|
-
* - Indirect injection via external content
|
|
407
|
-
* - Encoding-based evasion attempts
|
|
408
|
-
*
|
|
409
|
-
* @example
|
|
410
|
-
* ```typescript
|
|
411
|
-
* import { createPromptInjectionGuardrail } from '@directive-run/ai';
|
|
412
70
|
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
71
|
+
* @example Allow specific keys (not just by tag)
|
|
72
|
+
* ```ts
|
|
73
|
+
* createFactPIIGuardrail({
|
|
74
|
+
* includeKeys: ['customer.email', 'customer.phone'],
|
|
416
75
|
* });
|
|
417
76
|
* ```
|
|
418
77
|
*/
|
|
419
78
|
|
|
420
|
-
/** Pattern with metadata for better debugging */
|
|
421
|
-
interface InjectionPattern {
|
|
422
|
-
pattern: RegExp;
|
|
423
|
-
name: string;
|
|
424
|
-
severity: "low" | "medium" | "high" | "critical";
|
|
425
|
-
category: InjectionCategory;
|
|
426
|
-
}
|
|
427
|
-
/** Categories of injection attacks */
|
|
428
|
-
type InjectionCategory = "instruction_override" | "jailbreak" | "role_manipulation" | "encoding_evasion" | "delimiter_injection" | "context_manipulation" | "indirect_injection";
|
|
429
|
-
/** Default injection patterns - well-tested and low false-positive rate */
|
|
430
|
-
declare const DEFAULT_INJECTION_PATTERNS: InjectionPattern[];
|
|
431
|
-
/** Strict patterns - more aggressive, may have higher false positives */
|
|
432
|
-
declare const STRICT_INJECTION_PATTERNS: InjectionPattern[];
|
|
433
|
-
/** Detailed detection result */
|
|
434
|
-
interface InjectionDetectionResult {
|
|
435
|
-
detected: boolean;
|
|
436
|
-
patterns: Array<{
|
|
437
|
-
name: string;
|
|
438
|
-
category: InjectionCategory;
|
|
439
|
-
severity: InjectionPattern["severity"];
|
|
440
|
-
match: string;
|
|
441
|
-
position: number;
|
|
442
|
-
}>;
|
|
443
|
-
riskScore: number;
|
|
444
|
-
sanitizedInput?: string;
|
|
445
|
-
}
|
|
446
79
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
* @throws Error if input exceeds MAX_INJECTION_INPUT_LENGTH (100KB)
|
|
80
|
+
* Public match record for a single PII finding. Mirrors `DetectedPII` from
|
|
81
|
+
* `pii-enhanced.ts` so a downstream guardrail can normalize against either
|
|
82
|
+
* detection path.
|
|
451
83
|
*/
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
* Uses a single-pass approach to prevent infinite loops where a replacement
|
|
458
|
-
* could create a new pattern match.
|
|
459
|
-
*/
|
|
460
|
-
declare function sanitizeInjection(text: string, patterns?: InjectionPattern[]): string;
|
|
461
|
-
/** Options for prompt injection guardrail */
|
|
462
|
-
interface PromptInjectionGuardrailOptions {
|
|
463
|
-
/** Additional patterns to check (added to defaults) */
|
|
464
|
-
additionalPatterns?: InjectionPattern[];
|
|
465
|
-
/** Replace default patterns entirely */
|
|
466
|
-
replacePatterns?: InjectionPattern[];
|
|
467
|
-
/** Use strict mode with more aggressive detection */
|
|
468
|
-
strictMode?: boolean;
|
|
469
|
-
/** Minimum risk score to block (0-100, default: 50) */
|
|
470
|
-
blockThreshold?: number;
|
|
471
|
-
/** Attempt to sanitize instead of blocking */
|
|
472
|
-
sanitize?: boolean;
|
|
473
|
-
/** Callback when injection is detected */
|
|
474
|
-
onBlocked?: (input: string, result: InjectionDetectionResult) => void;
|
|
475
|
-
/** Categories to ignore (e.g., allow 'role_manipulation' for roleplay apps) */
|
|
476
|
-
ignoreCategories?: InjectionCategory[];
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Create a prompt injection detection guardrail.
|
|
480
|
-
*
|
|
481
|
-
* @example
|
|
482
|
-
* ```typescript
|
|
483
|
-
* // Basic usage
|
|
484
|
-
* const guardrail = createPromptInjectionGuardrail();
|
|
485
|
-
*
|
|
486
|
-
* // Strict mode for high-security applications
|
|
487
|
-
* const strictGuardrail = createPromptInjectionGuardrail({
|
|
488
|
-
* strictMode: true,
|
|
489
|
-
* blockThreshold: 25,
|
|
490
|
-
* });
|
|
491
|
-
*
|
|
492
|
-
* // Allow role manipulation for roleplay apps
|
|
493
|
-
* const roleplayGuardrail = createPromptInjectionGuardrail({
|
|
494
|
-
* ignoreCategories: ['role_manipulation'],
|
|
495
|
-
* });
|
|
496
|
-
* ```
|
|
497
|
-
*/
|
|
498
|
-
declare function createPromptInjectionGuardrail(options?: PromptInjectionGuardrailOptions): GuardrailFn<InputGuardrailData>;
|
|
499
|
-
/**
|
|
500
|
-
* Mark content as potentially untrusted (from external sources).
|
|
501
|
-
* This wraps the content with markers that injection detection will scrutinize more closely.
|
|
502
|
-
*
|
|
503
|
-
* @example
|
|
504
|
-
* ```typescript
|
|
505
|
-
* const userUpload = await readFile(path);
|
|
506
|
-
* const markedContent = markUntrustedContent(userUpload, 'user-upload');
|
|
507
|
-
* const prompt = `Summarize this document: ${markedContent}`;
|
|
508
|
-
* ```
|
|
509
|
-
*/
|
|
510
|
-
declare function markUntrustedContent(content: string, source: string): string;
|
|
511
|
-
/**
|
|
512
|
-
* Create a guardrail that applies stricter checks to marked untrusted content.
|
|
513
|
-
*
|
|
514
|
-
* @example
|
|
515
|
-
* ```typescript
|
|
516
|
-
* const guardrail = createUntrustedContentGuardrail({
|
|
517
|
-
* baseGuardrail: createPromptInjectionGuardrail({ strictMode: true }),
|
|
518
|
-
* });
|
|
519
|
-
* ```
|
|
520
|
-
*/
|
|
521
|
-
declare function createUntrustedContentGuardrail(options: {
|
|
522
|
-
/** Guardrail to apply to untrusted sections */
|
|
523
|
-
baseGuardrail?: GuardrailFn<InputGuardrailData>;
|
|
524
|
-
/** Block if untrusted content contains these patterns */
|
|
525
|
-
additionalPatterns?: InjectionPattern[];
|
|
526
|
-
}): GuardrailFn<InputGuardrailData>;
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Approximate Nearest Neighbor (ANN) Index for Semantic Cache
|
|
530
|
-
*
|
|
531
|
-
* Provides pluggable vector search backends for efficient similarity lookups.
|
|
532
|
-
* Includes a brute-force exact search and a VP-tree (Vantage Point Tree) for
|
|
533
|
-
* fast approximate nearest neighbor queries.
|
|
534
|
-
*
|
|
535
|
-
* @example
|
|
536
|
-
* ```typescript
|
|
537
|
-
* import { createSemanticCache } from '@directive-run/ai';
|
|
538
|
-
* import { createVPTreeIndex } from '@directive-run/ai';
|
|
539
|
-
*
|
|
540
|
-
* const index = createVPTreeIndex();
|
|
541
|
-
*
|
|
542
|
-
* const cache = createSemanticCache({
|
|
543
|
-
* embedder: myEmbedder,
|
|
544
|
-
* annIndex: index,
|
|
545
|
-
* });
|
|
546
|
-
* ```
|
|
547
|
-
*/
|
|
548
|
-
|
|
549
|
-
/** Search result from an ANN index */
|
|
550
|
-
interface ANNSearchResult {
|
|
551
|
-
/** ID of the matched item */
|
|
552
|
-
id: number;
|
|
553
|
-
/** Similarity score (0-1, higher is more similar) */
|
|
554
|
-
similarity: number;
|
|
555
|
-
}
|
|
556
|
-
/** ANN Index interface - pluggable vector search backend */
|
|
557
|
-
interface ANNIndex {
|
|
558
|
-
/** Add a vector to the index */
|
|
559
|
-
add(id: number, embedding: Embedding): void;
|
|
560
|
-
/** Remove a vector from the index */
|
|
561
|
-
remove(id: number): void;
|
|
562
|
-
/** Search for the k nearest neighbors */
|
|
563
|
-
search(query: Embedding, k: number, threshold?: number): ANNSearchResult[];
|
|
564
|
-
/** Rebuild the index (call after batch additions) */
|
|
565
|
-
rebuild(): void;
|
|
566
|
-
/** Get the number of indexed vectors */
|
|
567
|
-
size(): number;
|
|
568
|
-
/** Clear the index */
|
|
569
|
-
clear(): void;
|
|
570
|
-
/** Check if the index needs to be rebuilt (e.g., after additions/removals) */
|
|
571
|
-
needsRebuild(): boolean;
|
|
84
|
+
interface FactPIIMatch {
|
|
85
|
+
type: FactPIICategory;
|
|
86
|
+
value: string;
|
|
87
|
+
start: number;
|
|
88
|
+
end: number;
|
|
572
89
|
}
|
|
573
|
-
/**
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
90
|
+
/** PII categories the built-in synchronous detector covers. */
|
|
91
|
+
type FactPIICategory = "ssn" | "credit_card" | "email";
|
|
92
|
+
/**
|
|
93
|
+
* Behavior when a pii-tagged fact's incoming value contains detected PII.
|
|
94
|
+
*
|
|
95
|
+
* - `"redact"` (default): the fact is rewritten with redacted text (e.g.
|
|
96
|
+
* `"[SSN]"`) via a follow-up store write. The system briefly observes
|
|
97
|
+
* the raw value during the same microtask the publish landed in, then
|
|
98
|
+
* the redacted value overwrites it before any reconcile / agent runs.
|
|
99
|
+
* Safe shipping posture for production: the LLM call always sees the
|
|
100
|
+
* redacted value.
|
|
101
|
+
* - `"alert"`: fire `onBlocked` but DO NOT mutate the fact. The raw value
|
|
102
|
+
* stays in the store. Use this for monitoring-only deployments where
|
|
103
|
+
* the source's transport is already trusted but a regression detector
|
|
104
|
+
* is needed (paging ops on every match).
|
|
105
|
+
*
|
|
106
|
+
* Note: Directive plugin hooks (`onFactSet`, `onFactsBatch`) are
|
|
107
|
+
* wrapped by the plugin manager's `safeCall` so a throw from inside the
|
|
108
|
+
* hook is swallowed. The guardrail therefore cannot reject the write
|
|
109
|
+
* itself — it can only observe + redact-via-followup-write or alert.
|
|
110
|
+
* For hard rejection at the publish boundary, a future RFC will add a
|
|
111
|
+
* pre-commit transform hook on the source primitive.
|
|
112
|
+
*/
|
|
113
|
+
type FactPIIGuardrailMode = "redact" | "alert";
|
|
114
|
+
interface FactPIIGuardrailOptions {
|
|
115
|
+
/** Default: `"redact"` */
|
|
116
|
+
mode?: FactPIIGuardrailMode;
|
|
117
|
+
/**
|
|
118
|
+
* Built-in categories to scan for. Default: all three (`ssn`,
|
|
119
|
+
* `credit_card`, `email`). Pass `[]` to opt out of the built-ins and
|
|
120
|
+
* rely entirely on `customDetector`.
|
|
121
|
+
*/
|
|
122
|
+
types?: readonly FactPIICategory[];
|
|
123
|
+
/**
|
|
124
|
+
* Specific fact keys to scan in addition to the auto-detected
|
|
125
|
+
* `pii`-tagged set. Useful when a consumer can't change the schema's
|
|
126
|
+
* meta but knows the key should be screened.
|
|
127
|
+
*/
|
|
128
|
+
includeKeys?: readonly string[];
|
|
129
|
+
/**
|
|
130
|
+
* Exclude these fact keys even if they're pii-tagged. Escape hatch for
|
|
131
|
+
* a key that's already pre-sanitized upstream of the manager.
|
|
132
|
+
*/
|
|
133
|
+
excludeKeys?: readonly string[];
|
|
134
|
+
/**
|
|
135
|
+
* Called whenever the guardrail detects PII and acts on it. Receives the
|
|
136
|
+
* fact key, the detected matches, and the action that was taken. Fires
|
|
137
|
+
* AFTER redact + before any throw in `reject` mode. Use this to alert
|
|
138
|
+
* SREs without coupling the guardrail to a specific logging backend.
|
|
139
|
+
*/
|
|
140
|
+
onBlocked?: (key: string, detected: readonly FactPIIMatch[], action: FactPIIGuardrailMode) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Custom synchronous detector that runs alongside the built-in regex
|
|
143
|
+
* scanner. The union of detections is acted on. Useful when the
|
|
144
|
+
* consumer ships a domain-specific PII detector (e.g. internal
|
|
145
|
+
* account-number format). MUST be synchronous — `onFactSet` cannot
|
|
146
|
+
* await deferred work.
|
|
147
|
+
*/
|
|
148
|
+
customDetector?: (text: string) => readonly FactPIIMatch[];
|
|
149
|
+
/**
|
|
150
|
+
* Maximum nesting depth to walk when scanning a structured fact
|
|
151
|
+
* value. Default `1` — the scanner inspects top-level strings, then
|
|
152
|
+
* descends one level into the object/array. Arrays and plain objects
|
|
153
|
+
* count as one depth level each. Maps and Sets are still NOT walked
|
|
154
|
+
* by the built-in scanner; PII inside those structures must go
|
|
155
|
+
* through a `customDetector`.
|
|
156
|
+
*
|
|
157
|
+
* Per R13-C6 the walker recurses into arrays (Supabase realtime
|
|
158
|
+
* payloads ship as `payload.new = [{...}]`, MCP resource lists ship
|
|
159
|
+
* as arrays — those shapes silently bypassed the Tier 0 guard before).
|
|
160
|
+
*
|
|
161
|
+
* Consumers with deeply-nested PII shapes have two options:
|
|
162
|
+
* 1. Pass `walkDepth: 2` (or higher) — the scanner walks plain
|
|
163
|
+
* objects and arrays to that depth. Maps and Sets are still
|
|
164
|
+
* skipped.
|
|
165
|
+
* 2. Pass a `customDetector` that walks the consumer-specific shape
|
|
166
|
+
* and returns concrete matches — the right answer for
|
|
167
|
+
* domain-specific structures (Maps, Sets, getters, Symbol keys).
|
|
168
|
+
*
|
|
169
|
+
* Maximum is `5` to prevent pathological recursion on cyclic
|
|
170
|
+
* structures. Passing anything higher clamps to `5`.
|
|
171
|
+
*
|
|
172
|
+
* Property iteration uses `Object.entries`, which skips
|
|
173
|
+
* Symbol-keyed properties and non-enumerable string keys. If you
|
|
174
|
+
* store PII under a Symbol key (unusual), a `customDetector` is the
|
|
175
|
+
* right escape hatch.
|
|
176
|
+
*/
|
|
177
|
+
walkDepth?: number;
|
|
593
178
|
}
|
|
594
179
|
/**
|
|
595
|
-
* Create a
|
|
180
|
+
* Create a Directive plugin that scans pii-tagged fact writes for PII and
|
|
181
|
+
* redacts or rejects them at the manager boundary.
|
|
596
182
|
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
183
|
+
* Wire it once at `createSystem({ plugins: [...] })`. The plugin caches
|
|
184
|
+
* the pii-tagged key set on `onInit` so per-write hooks are O(1) lookups.
|
|
599
185
|
*
|
|
600
|
-
* @
|
|
601
|
-
* ```typescript
|
|
602
|
-
* const index = createVPTreeIndex();
|
|
603
|
-
*
|
|
604
|
-
* // Add vectors
|
|
605
|
-
* for (let i = 0; i < embeddings.length; i++) {
|
|
606
|
-
* index.add(i, embeddings[i]);
|
|
607
|
-
* }
|
|
608
|
-
*
|
|
609
|
-
* // Build the tree
|
|
610
|
-
* index.rebuild();
|
|
611
|
-
*
|
|
612
|
-
* // Search
|
|
613
|
-
* const results = index.search(queryEmbedding, 5, 0.9);
|
|
614
|
-
* ```
|
|
186
|
+
* @returns a `Plugin` instance ready to add to `SystemConfig.plugins`.
|
|
615
187
|
*/
|
|
616
|
-
declare function
|
|
188
|
+
declare function createFactPIIGuardrail(options?: FactPIIGuardrailOptions): Plugin;
|
|
617
189
|
|
|
618
|
-
export { type
|
|
190
|
+
export { type FactPIICategory, type FactPIIGuardrailMode, type FactPIIGuardrailOptions, type FactPIIMatch, createFactPIIGuardrail };
|