@cendor/guardrails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `@cendor/guardrails` — a local-first gate for LLM apps: define a check, attach it to a stage.
3
+ * The TS port of `cendor.guardrails`.
4
+ *
5
+ * The **Gate** in the Cendor pipeline (`contextkit → squeeze → tokenguard → guardrails → cassette →
6
+ * acttrace`). Deterministic checks — keyword/regex/URL/length/JSON-schema — run in microseconds for
7
+ * $0, at four intervention points (`input | tool_call | tool_output | output`). Every trip or flag
8
+ * emits a `GuardrailDecision` on the `@cendor/core` bus, so `@cendor/acttrace` chains it as
9
+ * tamper-evident evidence with no import between the two.
10
+ *
11
+ * Imports ONLY `@cendor/core` (constitution rule 2). See docs/guardrails.md.
12
+ */
13
+ import { LLMCall } from '@cendor/core';
14
+ import { type Context, type Guardrail, GuardrailDecision } from './decision.js';
15
+ export { STAGES, ACTIONS, Verdict, GuardrailDecision, GuardrailTripped, defineGuardrail, normalizeStages, } from './decision.js';
16
+ export type { Stage, Action, Context, Check, Guardrail, DefineGuardrailOptions, } from './decision.js';
17
+ export * as rules from './rules.js';
18
+ /** The result of evaluating a stage: the (possibly redacted) payload plus the recorded decisions. */
19
+ export interface EvalResult {
20
+ payload: unknown;
21
+ decisions: GuardrailDecision[];
22
+ }
23
+ /**
24
+ * Run the `stage` guardrails over `payload` **synchronously**. Returns `{ payload, decisions }`
25
+ * with any redactions applied in order; throws `GuardrailTripped` on the first block. An `async`
26
+ * check throws here — use {@link evaluateAsync}.
27
+ */
28
+ export declare function evaluate(guardrails: readonly Guardrail[], stage: string, payload: unknown, ctx?: Context): EvalResult;
29
+ /** Async counterpart of {@link evaluate}: awaits `async` checks, calls sync ones directly. */
30
+ export declare function evaluateAsync(guardrails: readonly Guardrail[], stage: string, payload: unknown, ctx?: Context): Promise<EvalResult>;
31
+ /** Gate `payload` and return the recorded decisions (throws `GuardrailTripped` on a block). */
32
+ export declare function apply(guardrails: readonly Guardrail[], stage: string, payload: unknown, ctx?: Context): GuardrailDecision[];
33
+ /** Async counterpart of {@link apply}. */
34
+ export declare function applyAsync(guardrails: readonly Guardrail[], stage: string, payload: unknown, ctx?: Context): Promise<GuardrailDecision[]>;
35
+ /**
36
+ * Gate every instrumented call by registering ONE `@cendor/core` interceptor (+ an output
37
+ * subscriber). Framework-independent. Input: a block raises (nothing spends), a redact reroutes the
38
+ * cleaned messages, a pass declines. tool_call: a block raises; else record + proceed (tools have
39
+ * no message-rewrite seam). Output: a bus subscriber raises **post-flight** on a block (same
40
+ * overshoot semantics as tokenguard's `onExceed:"raise"`). Runs sync checks only. Call
41
+ * {@link uninstall} to remove.
42
+ */
43
+ export declare function install(guardrails: readonly Guardrail[]): void;
44
+ /** Remove the interceptor + output subscriber registered by {@link install} (idempotent). */
45
+ export declare function uninstall(): void;
46
+ /** Best-effort assistant text off a completed LLMCall for the standalone output stage. */
47
+ export declare function responseText(call: LLMCall): string | null;
48
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,OAAO,EAQR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,iBAAiB,EAGlB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC,qGAAqG;AACrG,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAyCD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,OAAO,GACZ,UAAU,CAaZ;AAED,8FAA8F;AAC9F,wBAAsB,aAAa,CACjC,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,OAAO,GACZ,OAAO,CAAC,UAAU,CAAC,CASrB;AAED,+FAA+F;AAC/F,wBAAgB,KAAK,CACnB,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,OAAO,GACZ,iBAAiB,EAAE,CAErB;AAED,0CAA0C;AAC1C,wBAAsB,UAAU,CAC9B,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,OAAO,GACZ,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAE9B;AAOD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,IAAI,CAoC9D;AAED,6FAA6F;AAC7F,wBAAgB,SAAS,IAAI,IAAI,CAKhC;AAQD,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQzD"}
package/dist/index.js ADDED
@@ -0,0 +1,194 @@
1
+ /**
2
+ * `@cendor/guardrails` — a local-first gate for LLM apps: define a check, attach it to a stage.
3
+ * The TS port of `cendor.guardrails`.
4
+ *
5
+ * The **Gate** in the Cendor pipeline (`contextkit → squeeze → tokenguard → guardrails → cassette →
6
+ * acttrace`). Deterministic checks — keyword/regex/URL/length/JSON-schema — run in microseconds for
7
+ * $0, at four intervention points (`input | tool_call | tool_output | output`). Every trip or flag
8
+ * emits a `GuardrailDecision` on the `@cendor/core` bus, so `@cendor/acttrace` chains it as
9
+ * tamper-evident evidence with no import between the two.
10
+ *
11
+ * Imports ONLY `@cendor/core` (constitution rule 2). See docs/guardrails.md.
12
+ */
13
+ import { LLMCall, MISS, Reroute, ToolCall, addInterceptor, bus, currentTraceId, removeInterceptor, } from '@cendor/core';
14
+ import { GuardrailDecision, GuardrailTripped, } from './decision.js';
15
+ export { STAGES, ACTIONS, Verdict, GuardrailDecision, GuardrailTripped, defineGuardrail, normalizeStages, } from './decision.js';
16
+ export * as rules from './rules.js';
17
+ function applicable(guardrails, stage) {
18
+ return guardrails.filter((g) => g.stages.includes(stage));
19
+ }
20
+ function emit(g, stage, verdict, ctx) {
21
+ const decision = new GuardrailDecision({
22
+ guardrail: g.name,
23
+ stage,
24
+ action: verdict.action,
25
+ reason: verdict.reason,
26
+ agent: ctx.agent ?? '',
27
+ tool: ctx.tool ?? '',
28
+ traceId: ctx.traceId || currentTraceId(),
29
+ ts: new Date(),
30
+ metadata: { ...(ctx.metadata ?? {}) },
31
+ });
32
+ bus.emit(decision); // acttrace (if attached) chains this as a guardrail_decision entry
33
+ return decision;
34
+ }
35
+ function handle(verdict, g, stage, payload, ctx, decisions) {
36
+ if (verdict === null)
37
+ return payload;
38
+ decisions.push(emit(g, stage, verdict, ctx));
39
+ if (verdict.action === 'block')
40
+ throw new GuardrailTripped(decisions);
41
+ if (verdict.action === 'redact' && verdict.replacement != null)
42
+ return verdict.replacement;
43
+ return payload;
44
+ }
45
+ function isPromise(x) {
46
+ return x != null && typeof x.then === 'function';
47
+ }
48
+ /**
49
+ * Run the `stage` guardrails over `payload` **synchronously**. Returns `{ payload, decisions }`
50
+ * with any redactions applied in order; throws `GuardrailTripped` on the first block. An `async`
51
+ * check throws here — use {@link evaluateAsync}.
52
+ */
53
+ export function evaluate(guardrails, stage, payload, ctx) {
54
+ const context = ctx ?? { stage };
55
+ const decisions = [];
56
+ let current = payload;
57
+ for (const g of applicable(guardrails, stage)) {
58
+ const verdict = g.check(current, context);
59
+ if (isPromise(verdict)) {
60
+ void verdict.catch(() => { }); // swallow the rejection of the discarded promise
61
+ throw new TypeError(`guardrail ${JSON.stringify(g.name)} is async; use evaluateAsync`);
62
+ }
63
+ current = handle(verdict, g, stage, current, context, decisions);
64
+ }
65
+ return { payload: current, decisions };
66
+ }
67
+ /** Async counterpart of {@link evaluate}: awaits `async` checks, calls sync ones directly. */
68
+ export async function evaluateAsync(guardrails, stage, payload, ctx) {
69
+ const context = ctx ?? { stage };
70
+ const decisions = [];
71
+ let current = payload;
72
+ for (const g of applicable(guardrails, stage)) {
73
+ const verdict = await g.check(current, context);
74
+ current = handle(verdict, g, stage, current, context, decisions);
75
+ }
76
+ return { payload: current, decisions };
77
+ }
78
+ /** Gate `payload` and return the recorded decisions (throws `GuardrailTripped` on a block). */
79
+ export function apply(guardrails, stage, payload, ctx) {
80
+ return evaluate(guardrails, stage, payload, ctx).decisions;
81
+ }
82
+ /** Async counterpart of {@link apply}. */
83
+ export async function applyAsync(guardrails, stage, payload, ctx) {
84
+ return (await evaluateAsync(guardrails, stage, payload, ctx)).decisions;
85
+ }
86
+ // --------------------------------------------------------------------------- standalone wiring
87
+ let installedInterceptor = null;
88
+ let installedSubscriber = null;
89
+ /**
90
+ * Gate every instrumented call by registering ONE `@cendor/core` interceptor (+ an output
91
+ * subscriber). Framework-independent. Input: a block raises (nothing spends), a redact reroutes the
92
+ * cleaned messages, a pass declines. tool_call: a block raises; else record + proceed (tools have
93
+ * no message-rewrite seam). Output: a bus subscriber raises **post-flight** on a block (same
94
+ * overshoot semantics as tokenguard's `onExceed:"raise"`). Runs sync checks only. Call
95
+ * {@link uninstall} to remove.
96
+ */
97
+ export function install(guardrails) {
98
+ uninstall();
99
+ const gl = [...guardrails];
100
+ const interceptor = (event) => {
101
+ if (event instanceof LLMCall) {
102
+ const ctx = { stage: 'input', traceId: event.traceId };
103
+ const { payload, decisions } = evaluate(gl, 'input', event.messages, ctx);
104
+ if (decisions.some((d) => d.action === 'redact'))
105
+ return new Reroute({ messages: payload });
106
+ return MISS;
107
+ }
108
+ if (event instanceof ToolCall) {
109
+ const ctx = {
110
+ stage: 'tool_call',
111
+ tool: event.name,
112
+ toolArgs: event.arguments,
113
+ traceId: event.traceId,
114
+ };
115
+ evaluate(gl, 'tool_call', event.arguments, ctx); // block throws; else record + proceed
116
+ return MISS;
117
+ }
118
+ return MISS;
119
+ };
120
+ const subscriber = (event) => {
121
+ if (!(event instanceof LLMCall))
122
+ return;
123
+ const text = responseText(event);
124
+ if (text === null)
125
+ return;
126
+ const ctx = { stage: 'output', traceId: event.traceId };
127
+ evaluate(gl, 'output', text, ctx); // block throws post-flight
128
+ };
129
+ addInterceptor(interceptor);
130
+ bus.subscribe(subscriber);
131
+ installedInterceptor = interceptor;
132
+ installedSubscriber = subscriber;
133
+ }
134
+ /** Remove the interceptor + output subscriber registered by {@link install} (idempotent). */
135
+ export function uninstall() {
136
+ if (installedInterceptor)
137
+ removeInterceptor(installedInterceptor);
138
+ if (installedSubscriber)
139
+ bus.unsubscribe(installedSubscriber);
140
+ installedInterceptor = null;
141
+ installedSubscriber = null;
142
+ }
143
+ function get(obj, name) {
144
+ return obj != null && typeof obj === 'object'
145
+ ? obj[name]
146
+ : undefined;
147
+ }
148
+ /** Best-effort assistant text off a completed LLMCall for the standalone output stage. */
149
+ export function responseText(call) {
150
+ const response = call.metadata?.response;
151
+ if (response == null)
152
+ return null;
153
+ try {
154
+ return extractText(response);
155
+ }
156
+ catch {
157
+ return null; // extraction must never break the passthrough
158
+ }
159
+ }
160
+ function extractText(response) {
161
+ const outputText = get(response, 'output_text'); // OpenAI Responses convenience field
162
+ if (typeof outputText === 'string' && outputText)
163
+ return outputText;
164
+ const choices = get(response, 'choices'); // OpenAI/HF Chat Completions
165
+ if (Array.isArray(choices) && choices.length > 0) {
166
+ const content = get(get(choices[0], 'message'), 'content');
167
+ if (typeof content === 'string')
168
+ return content;
169
+ }
170
+ const content = get(response, 'content'); // Anthropic content blocks
171
+ if (Array.isArray(content)) {
172
+ const parts = content.map((b) => get(b, 'text')).filter((t) => t != null);
173
+ if (parts.length > 0)
174
+ return parts.map(String).join('');
175
+ }
176
+ const message = get(response, 'message'); // Ollama
177
+ if (message != null) {
178
+ const text = get(message, 'content');
179
+ if (typeof text === 'string')
180
+ return text;
181
+ }
182
+ const text = get(response, 'text'); // Gemini
183
+ if (typeof text === 'string' && text)
184
+ return text;
185
+ const outMessage = get(get(response, 'output'), 'message'); // Bedrock Converse
186
+ const outContent = get(outMessage, 'content');
187
+ if (Array.isArray(outContent)) {
188
+ const parts = outContent.map((b) => get(b, 'text')).filter((t) => t != null);
189
+ if (parts.length > 0)
190
+ return parts.map(String).join('');
191
+ }
192
+ return null;
193
+ }
194
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { type Check, type Context, type Guardrail, Verdict } from './decision.js';
2
+ type Stage = string | readonly string[];
3
+ /** Flatten a payload (string, chat-message array, or a single message object) to scannable text. */
4
+ export declare function payloadText(payload: unknown): string;
5
+ export interface KeywordDenyOptions {
6
+ stage?: Stage;
7
+ action?: 'block' | 'redact' | 'flag';
8
+ name?: string;
9
+ ignoreCase?: boolean;
10
+ }
11
+ /** Trip when any of `words` appears (substring, case-insensitive by default). */
12
+ export declare function keywordDeny(words: Iterable<string>, opts?: KeywordDenyOptions): Guardrail;
13
+ export interface RegexRuleOptions {
14
+ action?: 'block' | 'redact' | 'flag';
15
+ stage?: Stage;
16
+ name?: string;
17
+ replacement?: string;
18
+ }
19
+ /** Trip when `pattern` matches the payload text. `action:"redact"` substitutes each match. */
20
+ export declare function regexRule(pattern: RegExp | string, opts?: RegexRuleOptions): Guardrail;
21
+ export interface UrlRuleOptions {
22
+ stage?: Stage;
23
+ action?: 'block' | 'redact' | 'flag';
24
+ name?: string;
25
+ }
26
+ /** Trip when a URL's host is NOT on `domains` (or a subdomain of one). */
27
+ export declare function urlAllowlist(domains: Iterable<string>, opts?: UrlRuleOptions): Guardrail;
28
+ /** Trip when a URL's host is on `domains` (or a subdomain of one). */
29
+ export declare function urlDeny(domains: Iterable<string>, opts?: UrlRuleOptions): Guardrail;
30
+ export interface LengthBoundsOptions {
31
+ maxChars?: number;
32
+ maxTokens?: number;
33
+ model?: string;
34
+ stage?: Stage;
35
+ action?: 'block' | 'redact' | 'flag';
36
+ name?: string;
37
+ }
38
+ /** Trip when the payload exceeds `maxChars` and/or `maxTokens` (exact token counts via core). */
39
+ export declare function lengthBounds(opts?: LengthBoundsOptions): Guardrail;
40
+ export interface JsonSchemaOptions {
41
+ stage?: Stage;
42
+ action?: 'block' | 'redact' | 'flag';
43
+ name?: string;
44
+ }
45
+ /**
46
+ * Validate structured output against a minimal JSON Schema (`type`/`required`/`properties`/`items`,
47
+ * recursively). Trips when the payload is not valid JSON or violates the schema. Pass the model's
48
+ * raw text or an already-parsed object. Not the full spec (no `$ref`/`oneOf`/`pattern`).
49
+ */
50
+ export declare function jsonSchema(schema: Record<string, unknown>, opts?: JsonSchemaOptions): Guardrail;
51
+ export interface CustomOptions {
52
+ stage?: Stage;
53
+ name?: string;
54
+ }
55
+ /** Wrap any `fn(payload, ctx) -> Verdict | null` as a `Guardrail` (sync or async). */
56
+ export declare function custom(fn: Check, opts?: CustomOptions): Guardrail;
57
+ export interface LlmJudgeOptions {
58
+ stage?: Stage;
59
+ action?: 'block' | 'redact' | 'flag';
60
+ name?: string;
61
+ }
62
+ /**
63
+ * Adapter **contract** for a bring-your-own model judge — not a built-in classifier. `judge` is
64
+ * *your* (sync or async) callable that makes whatever model call you want and returns a `Verdict`,
65
+ * `true` to trip with the default `action`, a reason string, or `null`/`false` to pass. cendor ships
66
+ * no model here: the extra call costs real tokens and latency — measure it. See "Honest limits".
67
+ */
68
+ export declare function llmJudge(judge: (payload: unknown, ctx: Context) => Verdict | boolean | string | null | Promise<Verdict | boolean | string | null>, opts?: LlmJudgeOptions): Guardrail;
69
+ export {};
70
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
package/dist/rules.js ADDED
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Deterministic, local-first built-in rules — the microsecond, $0 tier. The TS port of
3
+ * `cendor.guardrails.rules`. Regex/arithmetic only: no model, no network, no heavy dependency.
4
+ *
5
+ * Deliberately NOT here: PII/secret detection (that is `@cendor/acttrace`'s detector catalogue —
6
+ * use `guard(Policy…)`), ML classifiers, jailbreak detection. `llmJudge` is an adapter *contract*
7
+ * (you supply the model call), never a bundled classifier. Deterministic checks do not stop a novel
8
+ * adversarial attack — see docs/guardrails.md "Honest limits".
9
+ */
10
+ import { tokens } from '@cendor/core';
11
+ import { Verdict, normalizeStages } from './decision.js';
12
+ // --------------------------------------------------------------------------- payload helpers
13
+ /** Flatten a payload (string, chat-message array, or a single message object) to scannable text. */
14
+ export function payloadText(payload) {
15
+ if (typeof payload === 'string')
16
+ return payload;
17
+ if (Array.isArray(payload)) {
18
+ return payload
19
+ .filter((m) => m != null)
20
+ .map((m) => (isMessageLike(m) ? messageText(m) : String(m)))
21
+ .join('\n');
22
+ }
23
+ if (payload && typeof payload === 'object') {
24
+ const o = payload;
25
+ // a chat message ({role,content}) -> its text; any other object (e.g. tool args) -> its JSON.
26
+ if ('content' in o || 'role' in o)
27
+ return messageText(o);
28
+ return JSON.stringify(o);
29
+ }
30
+ return String(payload);
31
+ }
32
+ function isMessageLike(m) {
33
+ return m != null && typeof m === 'object';
34
+ }
35
+ function messageText(msg) {
36
+ const content = msg.content;
37
+ if (Array.isArray(content)) {
38
+ return content
39
+ .map((p) => (p && typeof p === 'object' ? String(p.text ?? '') : ''))
40
+ .join('');
41
+ }
42
+ return content == null ? '' : String(content);
43
+ }
44
+ /** Apply `sub` to every text field of `payload`, returning a new structure of the same shape. */
45
+ function redactPayload(payload, sub) {
46
+ if (typeof payload === 'string')
47
+ return sub(payload);
48
+ if (Array.isArray(payload)) {
49
+ return payload.map((m) => isMessageLike(m) ? redactMessage(m, sub) : typeof m === 'string' ? sub(m) : m);
50
+ }
51
+ if (payload && typeof payload === 'object')
52
+ return redactMessage(payload, sub);
53
+ return payload;
54
+ }
55
+ function redactMessage(msg, sub) {
56
+ const out = { ...msg };
57
+ const content = out.content;
58
+ if (typeof content === 'string') {
59
+ out.content = sub(content);
60
+ }
61
+ else if (Array.isArray(content)) {
62
+ out.content = content.map((p) => p && typeof p === 'object' && typeof p.text === 'string'
63
+ ? { ...p, text: sub(p.text) }
64
+ : p);
65
+ }
66
+ return out;
67
+ }
68
+ function mkGuardrail(name, stage, check) {
69
+ return { name, stages: normalizeStages(stage), check };
70
+ }
71
+ /** Trip when any of `words` appears (substring, case-insensitive by default). */
72
+ export function keywordDeny(words, opts = {}) {
73
+ const { stage = 'input', action = 'block', name = 'keyword_deny', ignoreCase = true } = opts;
74
+ const terms = [...words].filter(Boolean);
75
+ const pattern = terms.length > 0
76
+ ? new RegExp(terms.map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), ignoreCase ? 'i' : '')
77
+ : null;
78
+ return mkGuardrail(name, stage, (payload) => {
79
+ if (pattern === null)
80
+ return null;
81
+ const match = pattern.exec(payloadText(payload));
82
+ if (match === null)
83
+ return null;
84
+ const reason = `denied keyword: ${JSON.stringify(match[0])}`;
85
+ if (action === 'redact') {
86
+ const g = new RegExp(pattern.source, ignoreCase ? 'gi' : 'g');
87
+ return new Verdict('redact', reason, redactPayload(payload, (s) => s.replace(g, '[redacted]')));
88
+ }
89
+ return new Verdict(action, reason);
90
+ });
91
+ }
92
+ /** Trip when `pattern` matches the payload text. `action:"redact"` substitutes each match. */
93
+ export function regexRule(pattern, opts = {}) {
94
+ const { action = 'flag', stage = 'input', name = 'regex_rule', replacement = '[redacted]', } = opts;
95
+ const flags = typeof pattern === 'string' ? '' : pattern.flags.replace('g', '');
96
+ const source = typeof pattern === 'string' ? pattern : pattern.source;
97
+ const test = new RegExp(source, flags);
98
+ return mkGuardrail(name, stage, (payload) => {
99
+ if (!test.test(payloadText(payload)))
100
+ return null;
101
+ const reason = `matched /${source}/`;
102
+ if (action === 'redact') {
103
+ const g = new RegExp(source, `${flags.replace('g', '')}g`);
104
+ return new Verdict('redact', reason, redactPayload(payload, (s) => s.replace(g, replacement)));
105
+ }
106
+ return new Verdict(action, reason);
107
+ });
108
+ }
109
+ const URL_RE = /https?:\/\/[^\s<>)\]}"']+/gi;
110
+ function* iterHosts(text) {
111
+ for (const match of text.matchAll(URL_RE)) {
112
+ try {
113
+ const host = new URL(match[0]).hostname.toLowerCase();
114
+ if (host)
115
+ yield host;
116
+ }
117
+ catch {
118
+ // not a parseable URL — skip
119
+ }
120
+ }
121
+ }
122
+ function hostMatches(host, domain) {
123
+ const d = domain.toLowerCase().replace(/^\.+/, '');
124
+ return host === d || host.endsWith(`.${d}`);
125
+ }
126
+ /** Trip when a URL's host is NOT on `domains` (or a subdomain of one). */
127
+ export function urlAllowlist(domains, opts = {}) {
128
+ const { stage = 'input', action = 'block', name = 'url_allowlist' } = opts;
129
+ const allowed = [...domains].filter(Boolean);
130
+ return mkGuardrail(name, stage, (payload) => {
131
+ for (const host of iterHosts(payloadText(payload))) {
132
+ if (!allowed.some((d) => hostMatches(host, d))) {
133
+ return new Verdict(action, `URL host not allowlisted: ${host}`);
134
+ }
135
+ }
136
+ return null;
137
+ });
138
+ }
139
+ /** Trip when a URL's host is on `domains` (or a subdomain of one). */
140
+ export function urlDeny(domains, opts = {}) {
141
+ const { stage = 'input', action = 'block', name = 'url_deny' } = opts;
142
+ const denied = [...domains].filter(Boolean);
143
+ return mkGuardrail(name, stage, (payload) => {
144
+ for (const host of iterHosts(payloadText(payload))) {
145
+ if (denied.some((d) => hostMatches(host, d))) {
146
+ return new Verdict(action, `URL host denied: ${host}`);
147
+ }
148
+ }
149
+ return null;
150
+ });
151
+ }
152
+ /** Trip when the payload exceeds `maxChars` and/or `maxTokens` (exact token counts via core). */
153
+ export function lengthBounds(opts = {}) {
154
+ const { maxChars, maxTokens, model = 'gpt-4o', stage = 'input', action = 'block', name = 'length_bounds', } = opts;
155
+ if (maxChars === undefined && maxTokens === undefined) {
156
+ throw new Error('lengthBounds needs at least one of maxChars / maxTokens');
157
+ }
158
+ return mkGuardrail(name, stage, (payload) => {
159
+ const text = payloadText(payload);
160
+ if (maxChars !== undefined && text.length > maxChars) {
161
+ return new Verdict(action, `${text.length} chars exceeds max ${maxChars}`);
162
+ }
163
+ if (maxTokens !== undefined) {
164
+ const countable = (Array.isArray(payload) ? payload : text);
165
+ const n = tokens.count(countable, model);
166
+ if (n > maxTokens)
167
+ return new Verdict(action, `${n} tokens exceeds max ${maxTokens}`);
168
+ }
169
+ return null;
170
+ });
171
+ }
172
+ /**
173
+ * Validate structured output against a minimal JSON Schema (`type`/`required`/`properties`/`items`,
174
+ * recursively). Trips when the payload is not valid JSON or violates the schema. Pass the model's
175
+ * raw text or an already-parsed object. Not the full spec (no `$ref`/`oneOf`/`pattern`).
176
+ */
177
+ export function jsonSchema(schema, opts = {}) {
178
+ const { stage = 'output', action = 'block', name = 'json_schema' } = opts;
179
+ return mkGuardrail(name, stage, (payload) => {
180
+ let data;
181
+ if (payload !== null && typeof payload === 'object') {
182
+ data = payload;
183
+ }
184
+ else {
185
+ try {
186
+ data = JSON.parse(payloadText(payload));
187
+ }
188
+ catch (e) {
189
+ return new Verdict(action, `output is not valid JSON: ${e.message}`);
190
+ }
191
+ }
192
+ const error = validate(data, schema, '$');
193
+ return error === null ? null : new Verdict(action, `schema violation: ${error}`);
194
+ });
195
+ }
196
+ /** Wrap any `fn(payload, ctx) -> Verdict | null` as a `Guardrail` (sync or async). */
197
+ export function custom(fn, opts = {}) {
198
+ return mkGuardrail(opts.name ?? (fn.name || 'custom'), opts.stage ?? 'input', fn);
199
+ }
200
+ /**
201
+ * Adapter **contract** for a bring-your-own model judge — not a built-in classifier. `judge` is
202
+ * *your* (sync or async) callable that makes whatever model call you want and returns a `Verdict`,
203
+ * `true` to trip with the default `action`, a reason string, or `null`/`false` to pass. cendor ships
204
+ * no model here: the extra call costs real tokens and latency — measure it. See "Honest limits".
205
+ */
206
+ export function llmJudge(judge, opts = {}) {
207
+ const { stage = 'output', action = 'block', name = 'llm_judge' } = opts;
208
+ const check = async (payload, ctx) => coerce(await judge(payload, ctx), action);
209
+ return mkGuardrail(name, stage, check);
210
+ }
211
+ function coerce(result, action) {
212
+ if (result === null || result === false)
213
+ return null;
214
+ if (result instanceof Verdict)
215
+ return result;
216
+ if (result === true)
217
+ return new Verdict(action, 'llmJudge tripped');
218
+ if (typeof result === 'string')
219
+ return new Verdict(action, result);
220
+ return new Verdict(action, 'llmJudge tripped');
221
+ }
222
+ // --------------------------------------------------------------------------- minimal JSON Schema
223
+ const TYPE_CHECK = {
224
+ object: (d) => d !== null && typeof d === 'object' && !Array.isArray(d),
225
+ array: (d) => Array.isArray(d),
226
+ string: (d) => typeof d === 'string',
227
+ number: (d) => typeof d === 'number',
228
+ integer: (d) => typeof d === 'number' && Number.isInteger(d),
229
+ boolean: (d) => typeof d === 'boolean',
230
+ null: (d) => d === null,
231
+ };
232
+ function validate(data, schema, path) {
233
+ const expected = schema.type;
234
+ if (expected !== undefined) {
235
+ const checker = TYPE_CHECK[expected];
236
+ if (checker && !checker(data))
237
+ return `${path}: expected ${expected}, got ${typeName(data)}`;
238
+ }
239
+ if (data !== null && typeof data === 'object' && !Array.isArray(data)) {
240
+ const obj = data;
241
+ for (const key of schema.required ?? []) {
242
+ if (!(key in obj))
243
+ return `${path}: missing required key ${JSON.stringify(key)}`;
244
+ }
245
+ const props = schema.properties ?? {};
246
+ for (const [key, sub] of Object.entries(props)) {
247
+ if (key in obj && sub && typeof sub === 'object') {
248
+ const err = validate(obj[key], sub, `${path}.${key}`);
249
+ if (err !== null)
250
+ return err;
251
+ }
252
+ }
253
+ }
254
+ if (Array.isArray(data) && schema.items && typeof schema.items === 'object') {
255
+ for (let i = 0; i < data.length; i++) {
256
+ const err = validate(data[i], schema.items, `${path}[${i}]`);
257
+ if (err !== null)
258
+ return err;
259
+ }
260
+ }
261
+ return null;
262
+ }
263
+ function typeName(d) {
264
+ if (d === null)
265
+ return 'null';
266
+ if (Array.isArray(d))
267
+ return 'array';
268
+ return typeof d;
269
+ }
270
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}