@cendor/guardrails 0.1.0 → 0.3.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,414 @@
1
+ /**
2
+ * Opt-in detection-tier adapters — beyond the deterministic tier-0 built-ins in `./rules`. The TS
3
+ * port of `cendor.guardrails.adapters`.
4
+ *
5
+ * These reach past regex/arithmetic to a **local ML classifier**, a **language detector**, a
6
+ * **hosted moderation endpoint**, and the three **hosted rails** (AWS Bedrock, Azure AI Content
7
+ * Safety, Google Model Armor) — the detection tier of docs/guardrails.md "Threat model". Each rides a
8
+ * **bring-your-own** dependency or client — never a hard dependency of this package: a classifier
9
+ * callable, a `detect` callable, or a provider client you pass in. They are re-exported through
10
+ * `./rules` (`rules.classifier` / `rules.language` / `rules.openaiModeration` /
11
+ * `rules.bedrockGuardrail` / `rules.azureContentSafety` / `rules.modelArmor`) and at the package root
12
+ * (`import { adapters } from '@cendor/guardrails'`).
13
+ *
14
+ * **Cloud check, local evidence.** The hosted rails call *your* cloud account (metered by the vendor
15
+ * — the base package stays local-first and free), but the verdict still runs through the same engine:
16
+ * every trip emits a local `GuardrailDecision` on the `@cendor/core` bus, so `@cendor/acttrace` chains
17
+ * it as tamper-evident evidence exactly like a deterministic rule. The reason records only which cloud
18
+ * policy fired — never the payload. The cloud clients are **duck-typed** (nothing here imports an AWS
19
+ * / Azure / Google SDK); construct the client and pass it in.
20
+ *
21
+ * **Honest claims.** There is **no jailbreak-detection claim** anywhere here. `classifier` is a
22
+ * generic, license-agnostic contract around a local classifier *you* supply (a prompt-injection
23
+ * classifier such as PromptGuard, an ONNX model, or a heuristic wires through it). Reproduce a
24
+ * model's public eval and publish the numbers before citing any detection rate — classifiers are
25
+ * beaten by mutation/obfuscation attacks, so layer them, don't trust one. See the "Threat model".
26
+ *
27
+ * This module imports only `./decision` and reuses `payloadText` from `./rules` (a hoisted function,
28
+ * so the `rules` ↔ `adapters` re-export cycle is safe at runtime).
29
+ */
30
+ import { Verdict, defineGuardrail, } from './decision.js';
31
+ import { payloadText } from './rules.js';
32
+ /**
33
+ * Default the error policy from a guardrail's action: a `block` gate fails **closed**; a `flag`
34
+ * degrades to advisory (`fail_open`). An explicit `onError` always wins. (Same rule as `rules`.)
35
+ */
36
+ function resolveOnError(action, onError) {
37
+ if (onError !== undefined)
38
+ return onError;
39
+ return action === 'flag' ? 'fail_open' : 'fail_closed';
40
+ }
41
+ /** Build an adapter's `Guardrail` via the leaf `defineGuardrail`, resolving the error policy. */
42
+ function mk(check, opts) {
43
+ return defineGuardrail(check, {
44
+ name: opts.name,
45
+ stage: opts.stage,
46
+ timeout: opts.timeout,
47
+ onError: resolveOnError(opts.action, opts.onError),
48
+ });
49
+ }
50
+ function get(obj, name, dflt = undefined) {
51
+ if (obj == null)
52
+ return dflt;
53
+ if (obj instanceof Map)
54
+ return obj.has(name) ? obj.get(name) : dflt;
55
+ if (typeof obj !== 'object' && typeof obj !== 'function')
56
+ return dflt;
57
+ const v = obj[name];
58
+ return v === undefined ? dflt : v;
59
+ }
60
+ /**
61
+ * Build a `Verdict.metadata` dict from the **reserved annotation keys** (`severity` / `detected` /
62
+ * `filtered` / `redacted` / `citation` / `license` — documented in docs/specs/bus-events.md),
63
+ * dropping any that are `undefined`. Adapters use it so a vendor's detected/severity signal rides
64
+ * the decision's metadata into the acttrace chain — no shape change, no acttrace edit.
65
+ */
66
+ function annotation(keys) {
67
+ const out = {};
68
+ for (const [k, v] of Object.entries(keys))
69
+ if (v !== undefined)
70
+ out[k] = v;
71
+ return out;
72
+ }
73
+ // --------------------------------------------------------------------------- classifier
74
+ /** Normalise a classifier result (bool / number / `{label: score}`) to `[score, tripped]`. */
75
+ function score(result, label, threshold) {
76
+ if (typeof result === 'boolean')
77
+ return [result ? 1 : 0, result];
78
+ if (typeof result === 'number')
79
+ return [result, result >= threshold];
80
+ if (result !== null && typeof result === 'object') {
81
+ const rec = result;
82
+ let s;
83
+ if (label !== undefined) {
84
+ s = Number(rec[label] ?? 0);
85
+ }
86
+ else {
87
+ const vals = Object.values(rec).map((v) => Number(v));
88
+ s = vals.length > 0 ? Math.max(...vals) : 0;
89
+ }
90
+ return [s, s >= threshold];
91
+ }
92
+ throw new TypeError(`classifier returned ${result === null ? 'null' : typeof result}; expected bool, number, or mapping`);
93
+ }
94
+ /**
95
+ * Wrap a **local classifier** as a guardrail — the generic, license-agnostic contract.
96
+ *
97
+ * `classify(text)` returns a float score in `[0, 1]`, a `{label: score}` mapping, or a bool. The
98
+ * guardrail trips when the (selected `label`'s, else the max) score `>= threshold` (or the bool is
99
+ * `true`). Bring **any** local classifier — an ONNX model, a transformers.js pipeline, a heuristic,
100
+ * or a prompt-injection classifier (PromptGuard-class). A remote classifier can hang, so set
101
+ * `timeout` / `onError` for it. No jailbreak-detection claim — see the module "Threat model" note.
102
+ */
103
+ export function classifier(classify, opts = {}) {
104
+ const { threshold = 0.5, label, stage = 'input', action = 'block', name = 'classifier', reason, timeout, onError, } = opts;
105
+ const check = (payload, _ctx) => {
106
+ const [s, tripped] = score(classify(payloadText(payload)), label, threshold);
107
+ if (!tripped)
108
+ return null;
109
+ return new Verdict(action, reason ?? `${name}: score ${s.toFixed(2)} >= ${threshold}`);
110
+ };
111
+ return mk(check, { name, stage, action, timeout, onError });
112
+ }
113
+ /**
114
+ * Trip when the payload's detected language is **not** in `allowed` (ISO codes; case-insensitive) —
115
+ * a guard against the language-switch bypass (smuggling disallowed content in another language). See
116
+ * the "Threat model".
117
+ *
118
+ * `detect(text) -> isoCode` is **bring-your-own**: the TS port bundles no language detector (adding
119
+ * one would be a heavy dependency), so `detect` is required. Without it the check throws a clear
120
+ * error, which the guardrail's `onError` policy turns into a block (default) or flag. Language ID on
121
+ * short/mixed text is unreliable — keep this advisory (`action: 'flag'`) unless you control the input.
122
+ */
123
+ export function language(allowed, opts = {}) {
124
+ const { detect, stage = 'input', action = 'block', name = 'language', timeout, onError } = opts;
125
+ const allow = new Set([...allowed].map((a) => a.toLowerCase()));
126
+ const defaultDetect = (_text) => {
127
+ throw new Error('language() needs a detector: pass detect=(text) => isoCode. The TS port bundles no ' +
128
+ 'language detector — wire your own (a small langid model, an ONNX/transformers.js classifier).');
129
+ };
130
+ const det = detect ?? defaultDetect;
131
+ const check = (payload, _ctx) => {
132
+ const text = payloadText(payload).trim();
133
+ if (!text)
134
+ return null;
135
+ const lang = det(text);
136
+ if (lang && !allow.has(lang.toLowerCase())) {
137
+ const listed = [...allow]
138
+ .sort()
139
+ .map((a) => `'${a}'`)
140
+ .join(', ');
141
+ return new Verdict(action, `language '${lang}' not in allowed [${listed}]`);
142
+ }
143
+ return null;
144
+ };
145
+ return mk(check, { name, stage, action, timeout, onError });
146
+ }
147
+ // --------------------------------------------------------------------------- openai_moderation
148
+ /** The category names an OpenAI moderation result flagged truthy (plain object or class instance). */
149
+ function flaggedCategories(categories) {
150
+ if (categories == null)
151
+ return [];
152
+ let entries;
153
+ if (categories instanceof Map) {
154
+ entries = [...categories.entries()];
155
+ }
156
+ else if (typeof categories === 'object') {
157
+ entries = Object.entries(categories);
158
+ }
159
+ else {
160
+ return [];
161
+ }
162
+ return entries
163
+ .filter(([, v]) => Boolean(v))
164
+ .map(([k]) => k)
165
+ .sort();
166
+ }
167
+ /**
168
+ * Trip when OpenAI's **free, non-LLM** moderation endpoint flags the payload — the cheapest hosted
169
+ * tier. `client` is *your* OpenAI client (needs a key); this calls `client.moderations.create(...)`.
170
+ *
171
+ * Restrict to specific `categories` (e.g. `['violence', 'hate']`) or trip on any flag. It is a
172
+ * network call — bound it with `timeout` and pick an `onError` policy (fail-closed by default for a
173
+ * block gate). This library stores nothing; the request goes to OpenAI. The client/response are
174
+ * duck-typed, so any OpenAI-shaped client works.
175
+ */
176
+ export function openaiModeration(client, opts = {}) {
177
+ const { model = 'omni-moderation-latest', categories, stage = 'input', action = 'block', name = 'openai_moderation', timeout, onError, } = opts;
178
+ const cats = categories ? new Set([...categories].map((c) => c.toLowerCase())) : null;
179
+ const check = async (payload, _ctx) => {
180
+ const moderations = get(client, 'moderations');
181
+ if (moderations == null || typeof moderations.create !== 'function') {
182
+ throw new TypeError('openaiModeration client has no moderations.create()');
183
+ }
184
+ const resp = await moderations.create({ model, input: payloadText(payload) });
185
+ const results = get(resp, 'results') ?? [];
186
+ if (results.length === 0)
187
+ return null;
188
+ const result = results[0];
189
+ const flagged = flaggedCategories(get(result, 'categories', {}));
190
+ const ann = annotation({ detected: true, filtered: action !== 'flag' });
191
+ if (cats !== null) {
192
+ const hit = flagged.filter((c) => cats.has(c.toLowerCase())).sort();
193
+ return hit.length > 0
194
+ ? new Verdict(action, `moderation flagged: ${hit.join(', ')}`, null, ann)
195
+ : null;
196
+ }
197
+ if (get(result, 'flagged', false)) {
198
+ const names = flagged.join(', ') || 'policy';
199
+ return new Verdict(action, `moderation flagged: ${names}`, null, ann);
200
+ }
201
+ return null;
202
+ };
203
+ return mk(check, { name, stage, action, timeout, onError });
204
+ }
205
+ // --------------------------------------------------------------------------- hosted rails
206
+ //
207
+ // Each calls *your* cloud account (metered — cite the vendor's pricing page in the docs) and turns the
208
+ // vendor's verdict into a LOCAL GuardrailDecision → acttrace evidence: "cloud check, local evidence".
209
+ // The clients are duck-typed (no AWS/Azure/Google import here); the JS cloud SDKs are async, so these
210
+ // checks are async — use them via the SDK loop / evaluateAsync (the sync `install()` seam can't run them).
211
+ function uniq(items) {
212
+ const seen = [];
213
+ for (const x of items)
214
+ if (x && !seen.includes(x))
215
+ seen.push(x);
216
+ return seen;
217
+ }
218
+ function getList(obj, name) {
219
+ const v = get(obj, name);
220
+ return Array.isArray(v) ? v : [];
221
+ }
222
+ /**
223
+ * AWS Bedrock **`ApplyGuardrail`** as a guardrail — the flagship hosted rail: it evaluates any text
224
+ * against your pre-configured Bedrock guardrail **independently of any model**, so it works with any
225
+ * provider. `client` is duck-typed on `applyGuardrail(params) => Promise<resp>` (with aws-sdk v3, pass
226
+ * `{ applyGuardrail: (p) => client.send(new ApplyGuardrailCommand(p)) }`). `source` is chosen from the
227
+ * stage (`INPUT`/`OUTPUT`); `action: 'redact'` substitutes Bedrock's masked `outputs` text. Metered
228
+ * per text unit — set `timeout` / `onError`.
229
+ */
230
+ export function bedrockGuardrail(client, guardrailId, opts = {}) {
231
+ const { stage = 'input', action = 'block', name = 'bedrock_guardrail', timeout, onError } = opts;
232
+ const check = async (payload, ctx) => {
233
+ const source = opts.source ?? (ctx.stage === 'output' || ctx.stage === 'tool_output' ? 'OUTPUT' : 'INPUT');
234
+ const apply = get(client, 'applyGuardrail');
235
+ if (typeof apply !== 'function') {
236
+ throw new TypeError('bedrockGuardrail client has no applyGuardrail(params) method');
237
+ }
238
+ const resp = await apply.call(client, {
239
+ guardrailIdentifier: guardrailId,
240
+ guardrailVersion: opts.guardrailVersion ?? 'DRAFT',
241
+ source,
242
+ content: [{ text: { text: payloadText(payload) } }],
243
+ });
244
+ if (get(resp, 'action') !== 'GUARDRAIL_INTERVENED')
245
+ return null;
246
+ const reason = bedrockReason(resp);
247
+ if (action === 'redact') {
248
+ const masked = bedrockMasked(resp);
249
+ if (masked != null) {
250
+ return new Verdict('redact', reason, masked, {
251
+ detected: true,
252
+ filtered: true,
253
+ redacted: true,
254
+ });
255
+ }
256
+ }
257
+ return new Verdict(action, reason, null, { detected: true, filtered: true });
258
+ };
259
+ return mk(check, { name, stage, action, timeout, onError });
260
+ }
261
+ function bedrockReason(resp) {
262
+ const actionReason = get(resp, 'actionReason');
263
+ if (typeof actionReason === 'string' && actionReason) {
264
+ return `Bedrock guardrail intervened: ${actionReason}`;
265
+ }
266
+ const labels = bedrockAssessmentLabels(resp);
267
+ return `Bedrock guardrail intervened: ${labels.length ? labels.join(', ') : 'policy'}`;
268
+ }
269
+ function bedrockAssessmentLabels(resp) {
270
+ const labels = [];
271
+ for (const a of getList(resp, 'assessments')) {
272
+ for (const t of getList(get(a, 'topicPolicy'), 'topics')) {
273
+ if (get(t, 'name'))
274
+ labels.push(`topic:${get(t, 'name')}`);
275
+ }
276
+ for (const f of getList(get(a, 'contentPolicy'), 'filters')) {
277
+ if (get(f, 'type'))
278
+ labels.push(`content:${get(f, 'type')}`);
279
+ }
280
+ const sp = get(a, 'sensitiveInformationPolicy');
281
+ for (const e of getList(sp, 'piiEntities')) {
282
+ if (get(e, 'type'))
283
+ labels.push(`pii:${get(e, 'type')}`);
284
+ }
285
+ for (const r of getList(sp, 'regexes')) {
286
+ if (get(r, 'name'))
287
+ labels.push(`regex:${get(r, 'name')}`);
288
+ }
289
+ const wp = get(a, 'wordPolicy');
290
+ if (getList(wp, 'customWords').length)
291
+ labels.push('word:custom');
292
+ for (const m of getList(wp, 'managedWordLists')) {
293
+ if (get(m, 'type'))
294
+ labels.push(`word:${get(m, 'type')}`);
295
+ }
296
+ }
297
+ return uniq(labels);
298
+ }
299
+ function bedrockMasked(resp) {
300
+ for (const o of getList(resp, 'outputs')) {
301
+ const t = get(o, 'text');
302
+ if (typeof t === 'string' && t)
303
+ return t;
304
+ }
305
+ return null;
306
+ }
307
+ /**
308
+ * Azure AI Content Safety **Prompt Shields** as a guardrail — detects user-prompt/document
309
+ * injection & jailbreak attacks. `client` is duck-typed on
310
+ * `shieldPrompt({ userPrompt, documents }) => Promise<resp>` and trips when the response's
311
+ * `userPromptAnalysis.attackDetected` (or any `documentsAnalysis[].attackDetected`) is true — a binary
312
+ * signal, so `block` / `flag` are the meaningful actions. Metered per text record — set `timeout`.
313
+ */
314
+ export function azureContentSafety(client, opts = {}) {
315
+ const { stage = 'input', action = 'block', name = 'azure_content_safety', timeout, onError, } = opts;
316
+ const documents = opts.documents ? [...opts.documents] : [];
317
+ const check = async (payload, _ctx) => {
318
+ const shield = get(client, 'shieldPrompt');
319
+ if (typeof shield !== 'function') {
320
+ throw new TypeError('azureContentSafety client has no shieldPrompt(options) method');
321
+ }
322
+ const resp = await shield.call(client, {
323
+ userPrompt: payloadText(payload),
324
+ documents,
325
+ });
326
+ const hits = azureAttacks(resp);
327
+ if (hits.length === 0)
328
+ return null;
329
+ return new Verdict(action, `Azure Prompt Shields: attack detected (${hits.join(', ')})`, null, annotation({ detected: true, filtered: action !== 'flag' }));
330
+ };
331
+ return mk(check, { name, stage, action, timeout, onError });
332
+ }
333
+ function azureAttacks(resp) {
334
+ const hits = [];
335
+ const upa = get(resp, 'userPromptAnalysis') ?? get(resp, 'user_prompt_analysis');
336
+ if (upa != null && (get(upa, 'attackDetected') || get(upa, 'attack_detected'))) {
337
+ hits.push('user prompt');
338
+ }
339
+ const da = get(resp, 'documentsAnalysis') ?? get(resp, 'documents_analysis');
340
+ if (Array.isArray(da)) {
341
+ da.forEach((d, i) => {
342
+ if (get(d, 'attackDetected') || get(d, 'attack_detected'))
343
+ hits.push(`document[${i}]`);
344
+ });
345
+ }
346
+ return hits;
347
+ }
348
+ /**
349
+ * Google Cloud **Model Armor** as a guardrail — screens prompts/responses against a template
350
+ * (prompt-injection & jailbreak, Sensitive Data Protection, malicious URIs, responsible-AI). `client`
351
+ * is duck-typed on `sanitizeUserPrompt(request)` / `sanitizeModelResponse(request)`; `template` is the
352
+ * full resource path `projects/{p}/locations/{l}/templates/{t}`. Trips when
353
+ * `sanitizationResult.filterMatchState` is `MATCH_FOUND`; the reason lists which filters matched.
354
+ * Metered per token — set `timeout`.
355
+ */
356
+ export function modelArmor(client, template, opts = {}) {
357
+ const { stage = 'input', action = 'block', name = 'model_armor', timeout, onError } = opts;
358
+ const check = async (payload, ctx) => {
359
+ const text = payloadText(payload);
360
+ const isOutput = ctx.stage === 'output' || ctx.stage === 'tool_output';
361
+ const method = get(client, isOutput ? 'sanitizeModelResponse' : 'sanitizeUserPrompt');
362
+ if (typeof method !== 'function') {
363
+ throw new TypeError('modelArmor client is missing sanitizeUserPrompt/sanitizeModelResponse');
364
+ }
365
+ const request = isOutput
366
+ ? { name: template, modelResponseData: { text } }
367
+ : { name: template, userPromptData: { text } };
368
+ const resp = await method.call(client, request);
369
+ const matched = modelArmorMatches(resp);
370
+ if (matched.length === 0)
371
+ return null;
372
+ return new Verdict(action, `Model Armor matched: ${matched.join(', ')}`, null, annotation({ detected: true, filtered: action !== 'flag' }));
373
+ };
374
+ return mk(check, { name, stage, action, timeout, onError });
375
+ }
376
+ const MATCH_FOUND = 'MATCH_FOUND';
377
+ function matchFound(state) {
378
+ const name = state?.name ?? (typeof state === 'string' ? state : undefined);
379
+ return name === MATCH_FOUND; // "NO_MATCH_FOUND" !== "MATCH_FOUND"
380
+ }
381
+ function modelArmorMatches(resp) {
382
+ const sr = get(resp, 'sanitizationResult') ?? get(resp, 'sanitization_result');
383
+ if (sr == null)
384
+ return [];
385
+ const top = get(sr, 'filterMatchState') ?? get(sr, 'filter_match_state');
386
+ if (!matchFound(top))
387
+ return [];
388
+ const fr = get(sr, 'filterResults') ?? get(sr, 'filter_results');
389
+ if (fr == null)
390
+ return ['filter'];
391
+ const entries = fr instanceof Map
392
+ ? [...fr.entries()]
393
+ : typeof fr === 'object'
394
+ ? Object.entries(fr)
395
+ : [];
396
+ const matched = entries.filter(([, v]) => containsMatch(v)).map(([k]) => String(k));
397
+ return matched.length ? matched : ['filter'];
398
+ }
399
+ function containsMatch(val, depth = 0) {
400
+ if (val == null || depth > 6)
401
+ return false;
402
+ const st = get(val, 'match_state') ?? get(val, 'matchState');
403
+ if (st != null && matchFound(st))
404
+ return true;
405
+ if (Array.isArray(val))
406
+ return val.some((v) => containsMatch(v, depth + 1));
407
+ if (val instanceof Map)
408
+ return [...val.values()].some((v) => containsMatch(v, depth + 1));
409
+ if (typeof val === 'object') {
410
+ return Object.values(val).some((v) => containsMatch(v, depth + 1));
411
+ }
412
+ return false;
413
+ }
414
+ //# sourceMappingURL=adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
@@ -11,18 +11,38 @@ export type Stage = (typeof STAGES)[number];
11
11
  /** What a tripped check does (mirrors acttrace's action vocabulary). */
12
12
  export declare const ACTIONS: readonly ["block", "redact", "flag"];
13
13
  export type Action = (typeof ACTIONS)[number];
14
+ /**
15
+ * What to do when a check *itself* errors or times out (as opposed to returning a verdict).
16
+ * `fail_closed` treats the error as a block (fail-safe — the default for a gate you rely on);
17
+ * `fail_open` records the failure as a `flag` and lets the call proceed (so a flaky tier-3/4 judge
18
+ * outage degrades to advisory rather than silently disabling the agent). Either way the failure is
19
+ * emitted as a `GuardrailDecision`, so the audit chain records that the check could not run —
20
+ * evidence, not a swallowed exception.
21
+ */
22
+ export declare const ON_ERROR: readonly ["fail_closed", "fail_open"];
23
+ export type OnError = (typeof ON_ERROR)[number];
14
24
  /** Coerce a stage spec (a single stage or a collection) to a validated array. */
15
25
  export declare function normalizeStages(stage: string | readonly string[]): string[];
16
26
  /**
17
27
  * What a check returns to *trip* a guardrail. Return `null` to pass.
18
28
  * `action`: `"block"` (fail-closed), `"redact"` (replace the payload with `replacement`), or
19
29
  * `"flag"` (record + continue). Keep `reason` free of raw secret values.
30
+ *
31
+ * `metadata` is a per-result annotation dict merged into this decision's
32
+ * {@link GuardrailDecision.metadata} — the channel a check uses to attach the **reserved annotation
33
+ * keys** (`severity` / `detected` / `filtered` / `redacted` / `citation` / `license`, documented in
34
+ * docs/specs/bus-events.md). Unlike the static `Guardrail.metadata` (constant per guardrail — e.g.
35
+ * `loadPolicy`'s `policy_hash`), this is computed per verdict, so a hosted-rail adapter can record
36
+ * the vendor's severity/labels for this specific check. `Verdict` is never serialized (only
37
+ * `GuardrailDecision` is), so this adds no wire change. Layered *under* the caller's per-call
38
+ * `Context.metadata` (context still wins a key clash) — see the engine's `emit`.
20
39
  */
21
40
  export declare class Verdict {
22
41
  readonly action: Action;
23
42
  readonly reason: string;
24
43
  readonly replacement: unknown;
25
- constructor(action: Action, reason?: string, replacement?: unknown);
44
+ readonly metadata: Record<string, unknown>;
45
+ constructor(action: Action, reason?: string, replacement?: unknown, metadata?: Record<string, unknown>);
26
46
  }
27
47
  /** Everything a check knows about *where* it runs, beyond the payload. All fields optional. */
28
48
  export interface Context {
@@ -30,6 +50,12 @@ export interface Context {
30
50
  agent?: string;
31
51
  tool?: string;
32
52
  toolArgs?: unknown;
53
+ /**
54
+ * The user's originating instruction/intent for the run, when the caller knows it. An alignment
55
+ * check (`judge.taskAdherence`) compares a proposed tool call against it. Empty by default; a
56
+ * standalone check ignores it. (`@cendor/sdk` auto-threading is a deferred parity tail — 🚧.)
57
+ */
58
+ instruction?: string;
33
59
  traceId?: string;
34
60
  metadata?: Record<string, unknown>;
35
61
  }
@@ -40,14 +66,48 @@ export interface Guardrail {
40
66
  name: string;
41
67
  stages: string[];
42
68
  check: Check;
69
+ /**
70
+ * Optional per-check wall-clock limit in **seconds**. Meant for slow tier-3/4 checks (an LLM
71
+ * judge, a hosted rail); deterministic built-ins run in microseconds and leave it `undefined`.
72
+ * Enforced on the **async** path only (`evaluateAsync`) — JS has no threads, so there is no true
73
+ * sync timeout (see `evaluate`). On the async path a coroutine check is bounded via
74
+ * `Promise.race`; on a throw/timeout the `onError` policy decides.
75
+ */
76
+ timeout?: number;
77
+ /**
78
+ * What to do when the check *throws* or *times out*: `"fail_closed"` (default — treat it as a
79
+ * block) or `"fail_open"` (record a `flag` and proceed). Rule factories pick the safe default for
80
+ * their action; set it explicitly for a bring-your-own judge so an outage degrades to advisory
81
+ * instead of a hard stop (or vice-versa).
82
+ */
83
+ onError?: OnError;
84
+ /**
85
+ * Static key/values merged into every `GuardrailDecision` this guardrail emits (under the caller's
86
+ * per-call `Context.metadata`, which wins a key clash). `loadPolicy` uses it to stamp
87
+ * `policy_hash` / `policy_version` so the audit chain proves which policy was active; also handy
88
+ * for a severity, owner, or ticket id. Keep values small and payload-free.
89
+ */
90
+ metadata?: Record<string, unknown>;
43
91
  }
44
92
  export interface DefineGuardrailOptions {
45
93
  stage?: string | readonly string[];
46
94
  name?: string;
95
+ /** Per-check wall-clock limit in seconds (async path only); positive or `undefined`. */
96
+ timeout?: number;
97
+ /** Error/timeout policy (default `"fail_closed"`). */
98
+ onError?: OnError;
99
+ /** Static metadata merged into every decision this guardrail emits (see {@link Guardrail.metadata}). */
100
+ metadata?: Record<string, unknown>;
47
101
  }
102
+ /**
103
+ * Validate a guardrail's execution policy (mirrors Python's `Guardrail.__post_init__`). Throws on an
104
+ * unknown `onError` or a non-positive `timeout`.
105
+ */
106
+ export declare function validateExecutionPolicy(timeout: number | undefined, onError: OnError): void;
48
107
  /**
49
108
  * Turn a `check(payload, ctx)` function into a `Guardrail` (the TS analogue of Python's
50
- * `@guardrail` decorator — JS has no function decorators).
109
+ * `@guardrail` decorator — JS has no function decorators). `timeout` / `onError` set the per-check
110
+ * execution policy (see {@link Guardrail}).
51
111
  */
52
112
  export declare function defineGuardrail(check: Check, opts?: DefineGuardrailOptions): Guardrail;
53
113
  export interface GuardrailDecisionInit {
@@ -1 +1 @@
1
- {"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yDAAyD;AACzD,eAAO,MAAM,MAAM,0DAA2D,CAAC;AAC/E,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,OAAO,sCAAuC,CAAC;AAC5D,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAS3E;AAED;;;;GAIG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;gBAElB,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,EAAE,WAAW,GAAE,OAAc;CAUrE;AAED,+FAA+F;AAC/F,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,4GAA4G;AAC5G,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;AAEjG,sGAAsG;AACtG,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,GAAE,sBAA2B,GAAG,SAAS,CAM1F;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,IAAI,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,IAAI,GAAG,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtB,IAAI,EAAE,qBAAqB;CAWxC;AAED,mGAAmG;AACnG,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,EAAE,CAAC;gBAE5B,SAAS,EAAE,iBAAiB,EAAE;CAW3C"}
1
+ {"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"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"}
package/dist/decision.js CHANGED
@@ -9,6 +9,15 @@
9
9
  export const STAGES = ['input', 'tool_call', 'tool_output', 'output'];
10
10
  /** What a tripped check does (mirrors acttrace's action vocabulary). */
11
11
  export const ACTIONS = ['block', 'redact', 'flag'];
12
+ /**
13
+ * What to do when a check *itself* errors or times out (as opposed to returning a verdict).
14
+ * `fail_closed` treats the error as a block (fail-safe — the default for a gate you rely on);
15
+ * `fail_open` records the failure as a `flag` and lets the call proceed (so a flaky tier-3/4 judge
16
+ * outage degrades to advisory rather than silently disabling the agent). Either way the failure is
17
+ * emitted as a `GuardrailDecision`, so the audit chain records that the check could not run —
18
+ * evidence, not a swallowed exception.
19
+ */
20
+ export const ON_ERROR = ['fail_closed', 'fail_open'];
12
21
  /** Coerce a stage spec (a single stage or a collection) to a validated array. */
13
22
  export function normalizeStages(stage) {
14
23
  const stages = typeof stage === 'string' ? [stage] : [...stage];
@@ -25,30 +34,62 @@ export function normalizeStages(stage) {
25
34
  * What a check returns to *trip* a guardrail. Return `null` to pass.
26
35
  * `action`: `"block"` (fail-closed), `"redact"` (replace the payload with `replacement`), or
27
36
  * `"flag"` (record + continue). Keep `reason` free of raw secret values.
37
+ *
38
+ * `metadata` is a per-result annotation dict merged into this decision's
39
+ * {@link GuardrailDecision.metadata} — the channel a check uses to attach the **reserved annotation
40
+ * keys** (`severity` / `detected` / `filtered` / `redacted` / `citation` / `license`, documented in
41
+ * docs/specs/bus-events.md). Unlike the static `Guardrail.metadata` (constant per guardrail — e.g.
42
+ * `loadPolicy`'s `policy_hash`), this is computed per verdict, so a hosted-rail adapter can record
43
+ * the vendor's severity/labels for this specific check. `Verdict` is never serialized (only
44
+ * `GuardrailDecision` is), so this adds no wire change. Layered *under* the caller's per-call
45
+ * `Context.metadata` (context still wins a key clash) — see the engine's `emit`.
28
46
  */
29
47
  export class Verdict {
30
48
  action;
31
49
  reason;
32
50
  replacement;
33
- constructor(action, reason = '', replacement = null) {
51
+ metadata;
52
+ constructor(action, reason = '', replacement = null, metadata = {}) {
34
53
  if (!ACTIONS.includes(action)) {
35
54
  throw new Error(`unknown action ${JSON.stringify(action)}; must be one of ${ACTIONS.join(', ')}`);
36
55
  }
37
56
  this.action = action;
38
57
  this.reason = reason;
39
58
  this.replacement = replacement;
59
+ this.metadata = metadata;
60
+ }
61
+ }
62
+ /**
63
+ * Validate a guardrail's execution policy (mirrors Python's `Guardrail.__post_init__`). Throws on an
64
+ * unknown `onError` or a non-positive `timeout`.
65
+ */
66
+ export function validateExecutionPolicy(timeout, onError) {
67
+ if (!ON_ERROR.includes(onError)) {
68
+ throw new Error(`unknown onError ${JSON.stringify(onError)}; must be one of ${ON_ERROR.join(', ')}`);
69
+ }
70
+ if (timeout !== undefined && !(timeout > 0)) {
71
+ throw new Error(`timeout must be positive seconds or undefined, got ${JSON.stringify(timeout)}`);
40
72
  }
41
73
  }
42
74
  /**
43
75
  * Turn a `check(payload, ctx)` function into a `Guardrail` (the TS analogue of Python's
44
- * `@guardrail` decorator — JS has no function decorators).
76
+ * `@guardrail` decorator — JS has no function decorators). `timeout` / `onError` set the per-check
77
+ * execution policy (see {@link Guardrail}).
45
78
  */
46
79
  export function defineGuardrail(check, opts = {}) {
47
- return {
80
+ const onError = opts.onError ?? 'fail_closed';
81
+ validateExecutionPolicy(opts.timeout, onError);
82
+ const g = {
48
83
  name: opts.name ?? (check.name || 'guardrail'),
49
84
  stages: normalizeStages(opts.stage ?? 'input'),
50
85
  check,
86
+ onError,
51
87
  };
88
+ if (opts.timeout !== undefined)
89
+ g.timeout = opts.timeout;
90
+ if (opts.metadata !== undefined)
91
+ g.metadata = opts.metadata;
92
+ return g;
52
93
  }
53
94
  /**
54
95
  * Evidence that a guardrail tripped or flagged — emitted on the `@cendor/core` bus. acttrace