@agent-inspect/guardrails 2.5.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/index.mjs ADDED
@@ -0,0 +1,624 @@
1
+ import crypto from 'crypto';
2
+
3
+ // packages/redact/src/index.ts
4
+ var DEFAULT_REDACT_KEYS = [
5
+ "authorization",
6
+ "cookie",
7
+ "token",
8
+ "apiKey",
9
+ "password",
10
+ "secret",
11
+ "email"
12
+ ];
13
+ var SHARE_PROFILE_EXTRA_KEYS = [
14
+ "userEmail",
15
+ "customerEmail",
16
+ "phone",
17
+ "phoneNumber",
18
+ "address",
19
+ "ip",
20
+ "ipAddress",
21
+ "sessionId",
22
+ "requestId",
23
+ "correlationId",
24
+ "decisionId",
25
+ "groupId",
26
+ "customerId",
27
+ "userId",
28
+ "accountId",
29
+ "tenantId",
30
+ "orgId",
31
+ "organizationId",
32
+ "traceId",
33
+ "spanId",
34
+ "parentSpanId"
35
+ ];
36
+ var STRICT_PROFILE_EXTRA_KEYS = [
37
+ "prompt",
38
+ "completion",
39
+ "input",
40
+ "output",
41
+ "inputPreview",
42
+ "outputPreview",
43
+ "message",
44
+ "messages",
45
+ "transcript",
46
+ "context",
47
+ "document",
48
+ "documents",
49
+ "chunk",
50
+ "chunks",
51
+ "retrieval",
52
+ "query"
53
+ ];
54
+ function isRecord(value) {
55
+ return typeof value === "object" && value !== null && !Array.isArray(value);
56
+ }
57
+ function toKey(key) {
58
+ return key.toLowerCase();
59
+ }
60
+ function stableHash(value) {
61
+ const hash = crypto.createHash("sha256").update(value, "utf8").digest("hex");
62
+ return hash.slice(0, 8);
63
+ }
64
+ function stringifyScalar(value) {
65
+ if (typeof value === "string") return value;
66
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
67
+ return String(value);
68
+ }
69
+ return void 0;
70
+ }
71
+ function patternDetector(options) {
72
+ return {
73
+ id: options.id,
74
+ severity: options.severity ?? "warning",
75
+ matchKind: "value",
76
+ detect(input) {
77
+ if (typeof input.value !== "string") return [];
78
+ options.pattern.lastIndex = 0;
79
+ return options.pattern.test(input.value) ? [{ action: "replace", severity: options.severity ?? "warning", matchKind: "value" }] : [];
80
+ }
81
+ };
82
+ }
83
+ function digitsOnly(value) {
84
+ return value.replace(/\D/g, "");
85
+ }
86
+ function passesLuhn(value) {
87
+ const digits = digitsOnly(value);
88
+ if (digits.length < 13 || digits.length > 19) return false;
89
+ let sum = 0;
90
+ let double = false;
91
+ for (let i = digits.length - 1; i >= 0; i -= 1) {
92
+ let digit = Number(digits[i]);
93
+ if (double) {
94
+ digit *= 2;
95
+ if (digit > 9) digit -= 9;
96
+ }
97
+ sum += digit;
98
+ double = !double;
99
+ }
100
+ return sum % 10 === 0;
101
+ }
102
+ var credentialDetectors = [
103
+ patternDetector({
104
+ id: "value.authorizationHeader",
105
+ pattern: /^(?:basic|bearer|digest|apikey)\s+[a-z0-9._~+/=-]+$/i,
106
+ severity: "error"
107
+ }),
108
+ patternDetector({
109
+ id: "value.bearerToken",
110
+ pattern: /\bbearer\s+[a-z0-9._~+/=-]{12,}\b/i,
111
+ severity: "error"
112
+ }),
113
+ patternDetector({
114
+ id: "value.cookie",
115
+ pattern: /\b[a-z0-9_.-]+=[^;\s]+(?:;\s*[a-z0-9_.-]+=[^;\s]+)+/i,
116
+ severity: "error"
117
+ }),
118
+ patternDetector({
119
+ id: "value.jwt",
120
+ pattern: /\beyJ[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\b/,
121
+ severity: "error"
122
+ }),
123
+ patternDetector({
124
+ id: "value.providerApiKey",
125
+ pattern: /\b(?:sk-(?:proj-)?[a-zA-Z0-9_-]{16,}|sk-ant-[a-zA-Z0-9_-]{16,}|AIza[0-9A-Za-z_-]{20,})\b/,
126
+ severity: "error"
127
+ }),
128
+ patternDetector({
129
+ id: "value.githubToken",
130
+ pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b/,
131
+ severity: "error"
132
+ }),
133
+ patternDetector({
134
+ id: "value.awsAccessKey",
135
+ pattern: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
136
+ severity: "error"
137
+ }),
138
+ patternDetector({
139
+ id: "value.privateKey",
140
+ pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*-----END [A-Z ]*PRIVATE KEY-----/,
141
+ severity: "error"
142
+ }),
143
+ {
144
+ id: "value.creditCard",
145
+ severity: "error",
146
+ matchKind: "value",
147
+ detect(input) {
148
+ if (typeof input.value !== "string") return [];
149
+ const candidatePattern = /(?:\d[ -]?){13,19}/g;
150
+ for (const match of input.value.matchAll(candidatePattern)) {
151
+ const candidate = match[0] ?? "";
152
+ if (passesLuhn(candidate)) {
153
+ return [{ action: "replace", severity: "error", matchKind: "value" }];
154
+ }
155
+ }
156
+ return [];
157
+ }
158
+ }
159
+ ];
160
+ var identifierDetectors = [
161
+ patternDetector({
162
+ id: "value.email",
163
+ pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i
164
+ }),
165
+ patternDetector({
166
+ id: "value.phone",
167
+ pattern: /\b(?:\+\d{1,3}[\s.-]?)?(?:\(?\d{3}\)?[\s.-])\d{3}[\s.-]\d{4}\b/
168
+ }),
169
+ patternDetector({
170
+ id: "value.ipv4",
171
+ pattern: /\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b/
172
+ }),
173
+ patternDetector({
174
+ id: "value.ipv6",
175
+ pattern: /\b(?:[0-9a-f]{1,4}:){2,7}[0-9a-f]{1,4}\b/i
176
+ })
177
+ ];
178
+ function builtInDetectorsForProfile(profile) {
179
+ if (profile === "local") return credentialDetectors;
180
+ return [...credentialDetectors, ...identifierDetectors];
181
+ }
182
+ function compileRules(rules, extraKeys) {
183
+ const out = /* @__PURE__ */ new Map();
184
+ const set = (rule) => {
185
+ const key = toKey(rule.key);
186
+ out.set(key, { ...rule, key });
187
+ };
188
+ for (const key of DEFAULT_REDACT_KEYS) {
189
+ set({ key, strategy: "full" });
190
+ }
191
+ for (const key of extraKeys ?? []) {
192
+ if (typeof key === "string" && key.length > 0) {
193
+ set({ key, strategy: "full" });
194
+ }
195
+ }
196
+ for (const rule of rules ?? []) {
197
+ if (typeof rule === "string") {
198
+ set({ key: rule, strategy: "full" });
199
+ continue;
200
+ }
201
+ if (rule.strategy === "full") set({ key: rule.key, strategy: "full" });
202
+ if (rule.strategy === "hash") set({ key: rule.key, strategy: "hash" });
203
+ if (rule.strategy === "prefix") {
204
+ set({
205
+ key: rule.key,
206
+ strategy: "prefix",
207
+ keep: typeof rule.keep === "number" ? rule.keep : 8
208
+ });
209
+ }
210
+ }
211
+ return [...out.values()];
212
+ }
213
+ function actionForRule(rule) {
214
+ if (rule.strategy === "full") return "replace";
215
+ return rule.strategy;
216
+ }
217
+ function applyRule(rule, value, replacement) {
218
+ if (rule.strategy === "full") return replacement;
219
+ const asString = stringifyScalar(value);
220
+ if (rule.strategy === "prefix") {
221
+ if (asString === void 0) return replacement;
222
+ const keep = Math.max(0, Math.floor(rule.keep));
223
+ return asString.length <= keep ? `${asString}\u2026` : `${asString.slice(0, keep)}\u2026`;
224
+ }
225
+ if (rule.strategy === "hash") {
226
+ if (asString === void 0) return "[HASH:unknown]";
227
+ return `[HASH:${stableHash(asString)}]`;
228
+ }
229
+ return value;
230
+ }
231
+ function childPath(path, key) {
232
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
233
+ return path ? `${path}.${key}` : key;
234
+ }
235
+ return `${path || "$"}[${JSON.stringify(key)}]`;
236
+ }
237
+ function indexPath(path, index) {
238
+ return `${path || "$"}[${index}]`;
239
+ }
240
+ function makeFinding(path, detector, action, matchKind, severity = "warning", preview) {
241
+ return preview === void 0 ? { path, detector, action, severity, matchKind } : { path, detector, action, severity, matchKind, preview };
242
+ }
243
+ function createRedactionProfile(profile = "local") {
244
+ switch (profile) {
245
+ case "local":
246
+ return { profile: "local", extraKeys: [] };
247
+ case "share":
248
+ return {
249
+ profile: "share",
250
+ extraKeys: SHARE_PROFILE_EXTRA_KEYS,
251
+ maxMetadataValueLengthCap: 500,
252
+ maxPreviewLengthCap: 200
253
+ };
254
+ case "strict":
255
+ return {
256
+ profile: "strict",
257
+ extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
258
+ maxMetadataValueLengthCap: 200,
259
+ maxPreviewLengthCap: 80
260
+ };
261
+ }
262
+ }
263
+ var Redactor = class {
264
+ #rules;
265
+ #detectors;
266
+ #profile;
267
+ #replacement;
268
+ #maxDepth;
269
+ #collectFindings;
270
+ constructor(options) {
271
+ const resolved = createRedactionProfile(options?.profile ?? "local");
272
+ this.#profile = resolved.profile;
273
+ this.#rules = compileRules(options?.rules, [
274
+ ...resolved.extraKeys,
275
+ ...options?.extraKeys ?? []
276
+ ]);
277
+ this.#detectors = [
278
+ ...builtInDetectorsForProfile(this.#profile),
279
+ ...options?.detectors ?? []
280
+ ];
281
+ this.#replacement = options?.replacement ?? "[REDACTED]";
282
+ this.#maxDepth = options?.maxDepth ?? 32;
283
+ this.#collectFindings = options?.collectFindings ?? true;
284
+ }
285
+ redactValue(key, value) {
286
+ return this.#redactValue(value, key, key, 0, {
287
+ findings: [],
288
+ seen: /* @__PURE__ */ new WeakMap()
289
+ });
290
+ }
291
+ redactRecord(record) {
292
+ return this.redact(record).value;
293
+ }
294
+ redact(value) {
295
+ const state = {
296
+ findings: [],
297
+ seen: /* @__PURE__ */ new WeakMap()
298
+ };
299
+ const redacted = this.#redactValue(value, void 0, "$", 0, state);
300
+ return {
301
+ value: redacted,
302
+ findings: state.findings,
303
+ redacted: state.findings.some((finding) => finding.action !== "keep"),
304
+ profile: this.#profile
305
+ };
306
+ }
307
+ #recordFinding(state, finding) {
308
+ if (this.#collectFindings) state.findings.push(finding);
309
+ }
310
+ #redactValue(value, key, path, depth, state) {
311
+ if (depth > this.#maxDepth) {
312
+ this.#recordFinding(
313
+ state,
314
+ makeFinding(path, "structure.maxDepth", "truncate", "value", "warning")
315
+ );
316
+ return "[Truncated]";
317
+ }
318
+ if (key !== void 0) {
319
+ const rule = this.#rules.find((candidate) => candidate.key === toKey(key));
320
+ if (rule) {
321
+ this.#recordFinding(
322
+ state,
323
+ makeFinding(path, `key.${rule.key}`, actionForRule(rule), "key", "warning")
324
+ );
325
+ return applyRule(rule, value, this.#replacement);
326
+ }
327
+ }
328
+ for (const detector of this.#detectors) {
329
+ const detections = detector.detect({ path, key, value });
330
+ for (const detection of detections) {
331
+ const action = detection.action ?? "replace";
332
+ this.#recordFinding(
333
+ state,
334
+ makeFinding(
335
+ path,
336
+ detector.id,
337
+ action,
338
+ detection.matchKind ?? detector.matchKind ?? "custom",
339
+ detection.severity ?? detector.severity ?? "warning",
340
+ detection.preview
341
+ )
342
+ );
343
+ if (action !== "keep") {
344
+ return detection.replacement ?? this.#replacement;
345
+ }
346
+ }
347
+ }
348
+ if (Array.isArray(value)) {
349
+ if (state.seen.has(value)) return state.seen.get(value);
350
+ const out = [];
351
+ state.seen.set(value, out);
352
+ value.forEach((item, index) => {
353
+ out[index] = this.#redactValue(item, void 0, indexPath(path, index), depth + 1, state);
354
+ });
355
+ return out;
356
+ }
357
+ if (isRecord(value)) {
358
+ if (state.seen.has(value)) return state.seen.get(value);
359
+ const out = {};
360
+ state.seen.set(value, out);
361
+ for (const [entryKey, entryValue] of Object.entries(value)) {
362
+ out[entryKey] = this.#redactValue(
363
+ entryValue,
364
+ entryKey,
365
+ childPath(path === "$" ? "" : path, entryKey),
366
+ depth + 1,
367
+ state
368
+ );
369
+ }
370
+ return out;
371
+ }
372
+ return value;
373
+ }
374
+ };
375
+ function createRedactor(options) {
376
+ return new Redactor(options);
377
+ }
378
+ function redact(value, options) {
379
+ return createRedactor(options).redact(value);
380
+ }
381
+
382
+ // packages/guardrails/src/rules.ts
383
+ var DEFAULT_INJECTION_PATTERNS = [
384
+ "ignore previous instructions",
385
+ "ignore all prior",
386
+ "disregard your instructions",
387
+ "system prompt",
388
+ "you are now",
389
+ "jailbreak"
390
+ ];
391
+ function pass(ruleId, message) {
392
+ return { ruleId, status: "pass", severity: "info", message, evidence: [] };
393
+ }
394
+ function fail(ruleId, message, evidence, severity = "error") {
395
+ return { ruleId, status: severity === "warning" ? "warn" : "fail", severity, message, evidence };
396
+ }
397
+ function boundedPreview(value, max = 80) {
398
+ if (value.length <= max) return value;
399
+ return `${value.slice(0, max - 3)}...`;
400
+ }
401
+ function evaluateBannedPhrase(text, options) {
402
+ const ruleId = "guardrail.banned-phrase";
403
+ const haystack = options.caseInsensitive !== false ? text.toLowerCase() : text;
404
+ const evidence = [];
405
+ for (const phrase of options.phrases) {
406
+ const needle = options.caseInsensitive !== false ? phrase.toLowerCase() : phrase;
407
+ if (needle.length > 0 && haystack.includes(needle)) {
408
+ evidence.push({ ruleId, match: phrase, preview: boundedPreview(text) });
409
+ }
410
+ }
411
+ if (evidence.length === 0) {
412
+ return pass(ruleId, "No banned phrases matched.");
413
+ }
414
+ return fail(ruleId, `Matched ${evidence.length} banned phrase(s).`, evidence);
415
+ }
416
+ var SEVERITY_RANK = { info: 0, warning: 1, error: 2 };
417
+ function evaluatePiiLeak(value, options = {}) {
418
+ const ruleId = "guardrail.pii-leak";
419
+ const minSeverity = options.minSeverity ?? "warning";
420
+ const result = redact(value, { profile: options.profile ?? "share", collectFindings: true });
421
+ const findings = result.findings.filter(
422
+ (finding) => SEVERITY_RANK[finding.severity] >= SEVERITY_RANK[minSeverity]
423
+ );
424
+ if (findings.length === 0) {
425
+ return pass(ruleId, "No PII-style redaction findings.");
426
+ }
427
+ const evidence = findings.map((finding) => ({
428
+ ruleId,
429
+ path: finding.path,
430
+ detector: finding.detector,
431
+ preview: finding.preview
432
+ }));
433
+ return fail(ruleId, `Detected ${findings.length} PII-style finding(s).`, evidence);
434
+ }
435
+ function measureDepth(value) {
436
+ if (value === null || typeof value !== "object") return 0;
437
+ if (Array.isArray(value)) {
438
+ return 1 + Math.max(0, ...value.map((item) => measureDepth(item)));
439
+ }
440
+ const depths = Object.values(value).map((item) => measureDepth(item));
441
+ return 1 + (depths.length === 0 ? 0 : Math.max(...depths));
442
+ }
443
+ function maxStringLength(value) {
444
+ if (typeof value === "string") return value.length;
445
+ if (value === null || typeof value !== "object") return 0;
446
+ if (Array.isArray(value)) {
447
+ return Math.max(0, ...value.map((item) => maxStringLength(item)));
448
+ }
449
+ return Math.max(0, ...Object.values(value).map((item) => maxStringLength(item)));
450
+ }
451
+ function evaluateUnsafeToolArgs(toolName, toolArgs, options = {}) {
452
+ const ruleId = "guardrail.unsafe-tool-args";
453
+ const blocked = new Set((options.blockedTools ?? []).map((name) => name.toLowerCase()));
454
+ const evidence = [];
455
+ if (blocked.has(toolName.toLowerCase())) {
456
+ evidence.push({ ruleId, preview: toolName, match: toolName });
457
+ }
458
+ const maxDepth = options.maxDepth ?? 12;
459
+ const depth = measureDepth(toolArgs);
460
+ if (depth > maxDepth) {
461
+ evidence.push({ ruleId, path: "args", preview: `depth=${depth}` });
462
+ }
463
+ const maxLen = options.maxStringLength ?? 16384;
464
+ const longest = maxStringLength(toolArgs);
465
+ if (longest > maxLen) {
466
+ evidence.push({ ruleId, path: "args", preview: `maxStringLength=${longest}` });
467
+ }
468
+ if (evidence.length === 0) {
469
+ return pass(ruleId, "Tool arguments within configured bounds.");
470
+ }
471
+ return fail(ruleId, "Unsafe or oversized tool arguments detected.", evidence);
472
+ }
473
+ function evaluatePromptInjection(text, options = {}) {
474
+ const ruleId = "guardrail.prompt-injection";
475
+ const patterns = options.patterns ?? DEFAULT_INJECTION_PATTERNS;
476
+ const haystack = text.toLowerCase();
477
+ const evidence = [];
478
+ for (const pattern of patterns) {
479
+ const needle = pattern.toLowerCase();
480
+ if (needle.length > 0 && haystack.includes(needle)) {
481
+ evidence.push({ ruleId, match: pattern, preview: boundedPreview(text) });
482
+ }
483
+ }
484
+ if (evidence.length === 0) {
485
+ return pass(ruleId, "No prompt-injection patterns matched.");
486
+ }
487
+ return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
488
+ }
489
+ function validateSchemaField(value, field, path, evidence) {
490
+ const ruleId = "guardrail.structured-output";
491
+ if (field.type) {
492
+ const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
493
+ if (actual !== field.type) {
494
+ evidence.push({ ruleId, path, preview: `expected ${field.type}, got ${actual}` });
495
+ return;
496
+ }
497
+ }
498
+ if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
499
+ evidence.push({ ruleId, path, preview: "value not in enum" });
500
+ }
501
+ if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
502
+ const record = value;
503
+ for (const key of field.required) {
504
+ if (!(key in record)) {
505
+ evidence.push({ ruleId, path: `${path}.${key}`, preview: "missing required key" });
506
+ }
507
+ }
508
+ }
509
+ }
510
+ function evaluateStructuredOutput(value, options) {
511
+ const ruleId = "guardrail.structured-output";
512
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
513
+ return fail(ruleId, "Structured output must be an object.", [
514
+ { ruleId, preview: typeof value }
515
+ ]);
516
+ }
517
+ const record = value;
518
+ const evidence = [];
519
+ for (const [key, field] of Object.entries(options.schema)) {
520
+ validateSchemaField(record[key], field, key, evidence);
521
+ }
522
+ if (evidence.length === 0) {
523
+ return pass(ruleId, "Structured output matches schema subset.");
524
+ }
525
+ return fail(ruleId, "Structured output schema violation.", evidence);
526
+ }
527
+ function evaluateOversizeOutput(value, options = {}) {
528
+ const ruleId = "guardrail.oversize-output";
529
+ const text = typeof value === "string" ? value : JSON.stringify(value);
530
+ const maxLength = options.maxLength ?? options.maxSerializedLength ?? 32768;
531
+ if (text.length <= maxLength) {
532
+ return pass(ruleId, "Output within size limits.");
533
+ }
534
+ return fail(ruleId, `Output exceeds max length (${text.length} > ${maxLength}).`, [
535
+ { ruleId, preview: `length=${text.length}` }
536
+ ]);
537
+ }
538
+ function evaluateRequiredJsonShape(value, options) {
539
+ const ruleId = "guardrail.required-json-shape";
540
+ let parsed = value;
541
+ if (typeof value === "string") {
542
+ try {
543
+ parsed = JSON.parse(value);
544
+ } catch {
545
+ return fail(ruleId, "Value is not valid JSON.", [{ ruleId, preview: boundedPreview(value) }]);
546
+ }
547
+ }
548
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
549
+ return fail(ruleId, "JSON value must be an object.", [{ ruleId, preview: typeof parsed }]);
550
+ }
551
+ const record = parsed;
552
+ const evidence = [];
553
+ for (const key of options.requiredKeys) {
554
+ if (!(key in record)) {
555
+ evidence.push({ ruleId, path: key, preview: "missing required key" });
556
+ }
557
+ }
558
+ if (evidence.length === 0) {
559
+ return pass(ruleId, "Required JSON keys present.");
560
+ }
561
+ return fail(ruleId, "Missing required JSON keys.", evidence);
562
+ }
563
+
564
+ // packages/guardrails/src/run.ts
565
+ var ALL_RULES = [
566
+ "guardrail.banned-phrase",
567
+ "guardrail.pii-leak",
568
+ "guardrail.unsafe-tool-args",
569
+ "guardrail.prompt-injection",
570
+ "guardrail.structured-output",
571
+ "guardrail.oversize-output",
572
+ "guardrail.required-json-shape"
573
+ ];
574
+ function isErrorFailure(result) {
575
+ return result.status === "fail" && result.severity === "error";
576
+ }
577
+ function runRule(ruleId, input, options) {
578
+ switch (ruleId) {
579
+ case "guardrail.banned-phrase": {
580
+ if (!options.bannedPhrase || input.text === void 0) return void 0;
581
+ return evaluateBannedPhrase(input.text, options.bannedPhrase);
582
+ }
583
+ case "guardrail.pii-leak": {
584
+ if (input.value === void 0 && input.text === void 0) return void 0;
585
+ return evaluatePiiLeak(input.value ?? input.text, options.piiLeak);
586
+ }
587
+ case "guardrail.unsafe-tool-args": {
588
+ if (!input.toolName) return void 0;
589
+ return evaluateUnsafeToolArgs(input.toolName, input.toolArgs ?? {}, options.unsafeToolArgs);
590
+ }
591
+ case "guardrail.prompt-injection": {
592
+ if (input.text === void 0) return void 0;
593
+ return evaluatePromptInjection(input.text, options.promptInjection);
594
+ }
595
+ case "guardrail.structured-output": {
596
+ if (!options.structuredOutput || input.value === void 0) return void 0;
597
+ return evaluateStructuredOutput(input.value, options.structuredOutput);
598
+ }
599
+ case "guardrail.oversize-output": {
600
+ if (input.value === void 0 && input.text === void 0) return void 0;
601
+ return evaluateOversizeOutput(input.value ?? input.text, options.oversizeOutput);
602
+ }
603
+ case "guardrail.required-json-shape": {
604
+ if (!options.requiredJsonShape || input.value === void 0 && input.text === void 0) return void 0;
605
+ return evaluateRequiredJsonShape(input.value ?? input.text, options.requiredJsonShape);
606
+ }
607
+ default:
608
+ return void 0;
609
+ }
610
+ }
611
+ function runGuardrails(input, options = {}) {
612
+ const selected = options.rules ?? ALL_RULES;
613
+ const results = [];
614
+ for (const ruleId of selected) {
615
+ const result = runRule(ruleId, input, options);
616
+ if (result) results.push(result);
617
+ }
618
+ const ok = !results.some(isErrorFailure);
619
+ return { ok, results };
620
+ }
621
+
622
+ export { ALL_RULES as DEFAULT_GUARDRAIL_RULES, evaluateBannedPhrase, evaluateOversizeOutput, evaluatePiiLeak, evaluatePromptInjection, evaluateRequiredJsonShape, evaluateStructuredOutput, evaluateUnsafeToolArgs, runGuardrails };
623
+ //# sourceMappingURL=index.mjs.map
624
+ //# sourceMappingURL=index.mjs.map