@vinhnt-sdk/guardrails 0.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nguyen Thanh Vinh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @vinhnt-sdk/guardrails
2
+
3
+ > Version: 0.4.0 | Status: BETA
4
+
5
+ Guardrail tripwires for agent inputs/outputs — pattern-based safety checks.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ # npm
11
+ npm install @vinhnt-sdk/guardrails
12
+
13
+ # pnpm (monorepo)
14
+ pnpm add @vinhnt-sdk/guardrails
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { runGuardrails, maxLengthGuardrail, blocklistGuardrail } from '@vinhnt-sdk/guardrails';
21
+
22
+ const guardrails = [
23
+ maxLengthGuardrail(10000),
24
+ blocklistGuardrail([/ignore previous instructions/gi]),
25
+ ];
26
+
27
+ const result = await runGuardrails(guardrails, {
28
+ direction: 'input',
29
+ content: 'user input here',
30
+ toolName: 'chat',
31
+ });
32
+
33
+ if (result.decision === 'deny') {
34
+ throw new Error(`Blocked: ${result.reason}`);
35
+ }
36
+ ```
37
+
38
+ ## Exports
39
+
40
+ ### Types
41
+
42
+ | Type | Description |
43
+ |------|-------------|
44
+ | `Guardrail` | Guardrail interface |
45
+ | `GuardrailContext` | Context passed to guardrails |
46
+ | `GuardrailResult` | Result of a guardrail check |
47
+ | `GuardrailScope` | When the check runs (`input` / `output` / `both`) |
48
+
49
+ ### Functions
50
+
51
+ | Function | Description |
52
+ |----------|-------------|
53
+ | `runGuardrails(guardrails, ctx)` | Run guardrails in priority order with monotonic semantics |
54
+ | `maxLengthGuardrail(maxChars)` | Maximum input length guardrail |
55
+ | `blocklistGuardrail(patterns)` | Blocklist pattern guardrail |
56
+ | `secretDetectionGuardrail(redactor)` | Secret detection guardrail |
57
+
58
+ ## Dependencies
59
+
60
+ - `@vinhnt-sdk/schema`
61
+ - `@vinhnt-sdk/guard`
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Guardrail tripwires for agent inputs/outputs.
3
+ *
4
+ * Inspired by OpenAI Agents SDK guardrail pattern.
5
+ * Pattern-based safety checks that run before/after tool execution.
6
+ *
7
+ * @module guardrails
8
+ * @packageDocumentation
9
+ */
10
+ import type { GuardDecision } from "@vinhnt-sdk/guard";
11
+ /** Guardrail scope - when the check runs */
12
+ export type GuardrailScope = "input" | "output" | "both";
13
+ /** Priority order - lower runs first */
14
+ export type GuardrailPriority = number;
15
+ /** A guardrail tripwire that checks inputs/outputs */
16
+ export interface Guardrail {
17
+ readonly name: string;
18
+ readonly scope: GuardrailScope;
19
+ readonly priority: GuardrailPriority;
20
+ check: (ctx: GuardrailContext) => Promise<GuardrailResult>;
21
+ }
22
+ /** Context passed to guardrails */
23
+ export interface GuardrailContext {
24
+ readonly direction: "input" | "output";
25
+ readonly toolName?: string;
26
+ readonly content: unknown;
27
+ readonly metadata?: Record<string, unknown>;
28
+ }
29
+ /** Result of a guardrail check */
30
+ export interface GuardrailResult {
31
+ readonly passed: boolean;
32
+ readonly decision: GuardDecision;
33
+ readonly reason?: string;
34
+ /** Optional modified content (e.g., redacted) */
35
+ readonly modifiedContent?: unknown;
36
+ }
37
+ /** Maximum input length guardrail */
38
+ export declare function maxLengthGuardrail(maxChars: number, source?: string): Guardrail;
39
+ /** Blocklist pattern guardrail - blocks content matching patterns */
40
+ export declare function blocklistGuardrail(patterns: RegExp[], name?: string): Guardrail;
41
+ /** Secret detection guardrail - redacts detected secrets */
42
+ export declare function secretDetectionGuardrail(redactor: {
43
+ redact: (text: string) => string;
44
+ }): Guardrail;
45
+ /**
46
+ * Run guardrails in priority order with monotonic semantics.
47
+ * Once a guardrail denies, subsequent guardrails cannot override.
48
+ */
49
+ export declare function runGuardrails(guardrails: Guardrail[], ctx: GuardrailContext): Promise<GuardrailResult>;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMvD,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEzD,wCAAwC;AACxC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEvC,sDAAsD;AACtD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CAC5D;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C;AAED,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAMD,qCAAqC;AACrC,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAY,GAAG,SAAS,CAiBlF;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,SAAc,GAAG,SAAS,CAoBpF;AAED,4DAA4D;AAC5D,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GAAG,SAAS,CAmBlG;AAMD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,SAAS,EAAE,EACvB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
package/dist/index.js ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Guardrail tripwires for agent inputs/outputs.
3
+ *
4
+ * Inspired by OpenAI Agents SDK guardrail pattern.
5
+ * Pattern-based safety checks that run before/after tool execution.
6
+ *
7
+ * @module guardrails
8
+ * @packageDocumentation
9
+ */
10
+ // ---------------------------------------------------------------------------
11
+ // Built-in Guardrails
12
+ // ---------------------------------------------------------------------------
13
+ /** Maximum input length guardrail */
14
+ export function maxLengthGuardrail(maxChars, source = "unknown") {
15
+ return {
16
+ name: "max-length",
17
+ scope: "input",
18
+ priority: 10,
19
+ check: async (ctx) => {
20
+ const text = typeof ctx.content === "string" ? ctx.content : JSON.stringify(ctx.content);
21
+ if (text.length > maxChars) {
22
+ return {
23
+ passed: false,
24
+ decision: "deny",
25
+ reason: `${source}: input exceeds ${maxChars} chars (got ${text.length})`,
26
+ };
27
+ }
28
+ return { passed: true, decision: "allow" };
29
+ },
30
+ };
31
+ }
32
+ /** Blocklist pattern guardrail - blocks content matching patterns */
33
+ export function blocklistGuardrail(patterns, name = "blocklist") {
34
+ return {
35
+ name,
36
+ scope: "both",
37
+ priority: 20,
38
+ check: async (ctx) => {
39
+ const text = typeof ctx.content === "string" ? ctx.content : JSON.stringify(ctx.content);
40
+ for (const pattern of patterns) {
41
+ pattern.lastIndex = 0;
42
+ if (pattern.test(text)) {
43
+ return {
44
+ passed: false,
45
+ decision: "deny",
46
+ reason: `${name}: blocked pattern matched`,
47
+ };
48
+ }
49
+ }
50
+ return { passed: true, decision: "allow" };
51
+ },
52
+ };
53
+ }
54
+ /** Secret detection guardrail - redacts detected secrets */
55
+ export function secretDetectionGuardrail(redactor) {
56
+ return {
57
+ name: "secret-detection",
58
+ scope: "output",
59
+ priority: 30,
60
+ check: async (ctx) => {
61
+ const text = typeof ctx.content === "string" ? ctx.content : JSON.stringify(ctx.content);
62
+ const redacted = redactor.redact(text);
63
+ if (redacted !== text) {
64
+ return {
65
+ passed: true,
66
+ decision: "allow",
67
+ reason: "secrets detected and redacted",
68
+ modifiedContent: redacted,
69
+ };
70
+ }
71
+ return { passed: true, decision: "allow" };
72
+ },
73
+ };
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // Guardrail Runner
77
+ // ---------------------------------------------------------------------------
78
+ /**
79
+ * Run guardrails in priority order with monotonic semantics.
80
+ * Once a guardrail denies, subsequent guardrails cannot override.
81
+ */
82
+ export async function runGuardrails(guardrails, ctx) {
83
+ const sorted = [...guardrails]
84
+ .filter((g) => g.scope === "both" || g.scope === ctx.direction)
85
+ .sort((a, b) => a.priority - b.priority);
86
+ let current = { passed: true, decision: "allow" };
87
+ for (const guardrail of sorted) {
88
+ // Monotonic: once denied, stop
89
+ if (current.decision === "deny")
90
+ break;
91
+ const result = await guardrail.check(ctx);
92
+ // Deny takes precedence
93
+ if (result.decision === "deny") {
94
+ current = result;
95
+ break;
96
+ }
97
+ // Escalate if not already denied
98
+ if (result.decision === "escalate" && current.decision === "allow") {
99
+ current = result;
100
+ }
101
+ // Carry forward modified content
102
+ if (result.modifiedContent !== undefined) {
103
+ current = { ...current, modifiedContent: result.modifiedContent };
104
+ }
105
+ }
106
+ return current;
107
+ }
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@vinhnt-sdk/guardrails",
3
+ "version": "0.4.0",
4
+ "description": "Guardrail tripwires for agent inputs/outputs - pattern-based safety",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "LICENSE",
20
+ "README.md"
21
+ ],
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/vinhnt-develop/vinhnt-sdk.git",
29
+ "directory": "packages/guardrails"
30
+ },
31
+ "homepage": "https://github.com/vinhnt-develop/vinhnt-sdk/tree/main/packages/guardrails",
32
+ "bugs": {
33
+ "url": "https://github.com/vinhnt-develop/vinhnt-sdk/issues"
34
+ },
35
+ "keywords": [
36
+ "vnt",
37
+ "guardrails",
38
+ "safety",
39
+ "input-validation",
40
+ "output-validation"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "dependencies": {
46
+ "@vinhnt-sdk/guard": "0.4.0",
47
+ "@vinhnt-sdk/schema": "0.4.0"
48
+ },
49
+ "devDependencies": {
50
+ "vitest": "^3.2.7"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -b",
54
+ "typecheck": "tsc --noEmit",
55
+ "test": "vitest run"
56
+ }
57
+ }