@kindgi/guardrails 0.1.1 → 0.1.2
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/define-check.d.ts.map +1 -1
- package/dist/define-check.js +53 -3
- package/dist/define-check.js.map +1 -1
- package/package.json +9 -8
- package/src/define-check.ts +89 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-check.d.ts","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAShF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAE,GACvF,CAAC,GACD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe,CAAC,aAAa,SAAS,SAAS;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,gBAAgB,CAAC,aAAa,CAAC,EACvC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EACnC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KACnC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,CAAC,aAAa,SAAS,SAAS,IAAI,eAAe,GAAG;IAC5E,QAAQ,CAAC,SAAS,EAAE,aAAa,SAAS,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;IACpF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,aAAa,SAAS,SAAS,GAAG,SAAS,EACrE,IAAI,EAAE,eAAe,CAAC,aAAa,CAAC,GACnC,YAAY,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"define-check.d.ts","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAShF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAE,GACvF,CAAC,GACD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe,CAAC,aAAa,SAAS,SAAS;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,gBAAgB,CAAC,aAAa,CAAC,EACvC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EACnC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KACnC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,CAAC,aAAa,SAAS,SAAS,IAAI,eAAe,GAAG;IAC5E,QAAQ,CAAC,SAAS,EAAE,aAAa,SAAS,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;IACpF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,aAAa,SAAS,SAAS,GAAG,SAAS,EACrE,IAAI,EAAE,eAAe,CAAC,aAAa,CAAC,GACnC,YAAY,CAAC,aAAa,CAAC,CA0E7B"}
|
package/dist/define-check.js
CHANGED
|
@@ -76,18 +76,68 @@ export function defineCheck(spec) {
|
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
78
|
const validate = chainValidator(derivedValidator, spec.validateConfig);
|
|
79
|
+
// `evaluate` gets the config its schema resolves: the schema's defaults
|
|
80
|
+
// applied (a guardrail that declares no config gets them all), and a
|
|
81
|
+
// config that doesn't fit refused, naming where. Python's guardrails do
|
|
82
|
+
// the same. Without a schema, the config as declared.
|
|
83
|
+
const evaluate = evaluateWithResolvedConfig(spec.evaluate, configResolver(zodSchema, jsonSchema, spec.id));
|
|
79
84
|
const check = {
|
|
80
85
|
id: spec.id,
|
|
81
86
|
kind: spec.kind,
|
|
82
|
-
evaluate
|
|
87
|
+
evaluate,
|
|
83
88
|
...(validate !== undefined && { validateConfig: validate }),
|
|
84
89
|
...(zodSchema !== undefined && { configZod: zodSchema }),
|
|
85
90
|
...(jsonSchema !== undefined && { configJsonSchema: jsonSchema }),
|
|
86
91
|
};
|
|
87
92
|
return check;
|
|
88
93
|
}
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
/** `evaluate`, called with the config `resolve` gives (as declared without one). */
|
|
95
|
+
function evaluateWithResolvedConfig(evaluate, resolve) {
|
|
96
|
+
if (resolve === undefined)
|
|
97
|
+
return evaluate;
|
|
98
|
+
return async (config, trace, bindings) => evaluate((await resolve(config)), trace, bindings);
|
|
99
|
+
}
|
|
100
|
+
/** The resolver for the check's schema: Zod's own parse, or Ajv for JSON Schema; none without one. */
|
|
101
|
+
function configResolver(zodSchema, jsonSchema, checkId) {
|
|
102
|
+
if (zodSchema !== undefined)
|
|
103
|
+
return zodConfigResolver(zodSchema, checkId);
|
|
104
|
+
if (jsonSchema !== undefined)
|
|
105
|
+
return jsonConfigResolver(jsonSchema, checkId);
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
/** A Zod config, parsed by Zod itself (through `~standard`): its defaults and transforms apply. */
|
|
109
|
+
function zodConfigResolver(schema, checkId) {
|
|
110
|
+
const standard = schema['~standard'];
|
|
111
|
+
return async (config) => {
|
|
112
|
+
const result = await standard.validate(config ?? {});
|
|
113
|
+
if (result.issues === undefined)
|
|
114
|
+
return result.value;
|
|
115
|
+
const issue = result.issues[0];
|
|
116
|
+
const path = (issue?.path ?? [])
|
|
117
|
+
.map((segment) => String(typeof segment === 'object' && segment !== null ? segment.key : segment))
|
|
118
|
+
.join('.');
|
|
119
|
+
throw new Error(`Check "${checkId}": the guardrail's config doesn't fit its configSchema${path === '' ? '' : ` at ${path}`}: ${issue?.message ?? 'invalid config'}`);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** A JSON Schema config: checked by Ajv, which fills in the schema's `default`s (on a copy). */
|
|
123
|
+
function jsonConfigResolver(schema, checkId) {
|
|
124
|
+
const validator = compileValidator(schema, checkId, { useDefaults: true });
|
|
125
|
+
return async (config) => {
|
|
126
|
+
const resolved = structuredClone(config ?? {});
|
|
127
|
+
if (validator(resolved))
|
|
128
|
+
return resolved;
|
|
129
|
+
const first = validator.errors?.[0];
|
|
130
|
+
const path = first?.instancePath ?? '';
|
|
131
|
+
throw new Error(`Check "${checkId}": the guardrail's config doesn't fit its configSchema${path === '' ? '' : ` at ${path}`}: ${first?.message ?? 'invalid config'}`);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function compileValidator(schema, checkId, options = {}) {
|
|
135
|
+
const ajv = new Ajv2020({
|
|
136
|
+
strict: true,
|
|
137
|
+
allErrors: true,
|
|
138
|
+
allowUnionTypes: false,
|
|
139
|
+
...(options.useDefaults === true && { useDefaults: true }),
|
|
140
|
+
});
|
|
91
141
|
addFormats(ajv);
|
|
92
142
|
try {
|
|
93
143
|
return ajv.compile(schema);
|
package/dist/define-check.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-check.js","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"define-check.js","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kindgi/guardrails",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Runtime + CI enforcement of agent-behavior guardrails for Kindgi. Same declaration runs at runtime (halt / retry / escalate / log-only / compensate on violation) and in CI (fails the build) — no drift between test and prod. Zero-LLM checks (must-cite, never-call-tool, max-tool-calls, output-matches, tool-order, required-substring, forbidden-substring) are the default fast path; LLM-judge guardrails route via @kindgi/capabilities with explicit budget declarations. Execution strategies and action handlers are pluggable registries, and failed checks optionally emit compliance evidence.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
|
-
"import": "./dist/index.js"
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"default": "./dist/index.js"
|
|
22
23
|
}
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
@@ -29,10 +30,10 @@
|
|
|
29
30
|
"type-manifest.json"
|
|
30
31
|
],
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@kindgi/capabilities": "0.1.
|
|
33
|
-
"@kindgi/compliance": "0.1.
|
|
34
|
-
"@kindgi/schema": "0.1.
|
|
35
|
-
"@kindgi/types": "0.1.
|
|
33
|
+
"@kindgi/capabilities": "0.1.2",
|
|
34
|
+
"@kindgi/compliance": "0.1.2",
|
|
35
|
+
"@kindgi/schema": "0.1.2",
|
|
36
|
+
"@kindgi/types": "0.1.2",
|
|
36
37
|
"ajv": "^8.17.1",
|
|
37
38
|
"ajv-formats": "^3.0.1"
|
|
38
39
|
},
|
|
@@ -45,14 +46,14 @@
|
|
|
45
46
|
}
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
|
-
"@kindgi/specs": "0.1.
|
|
49
|
+
"@kindgi/specs": "0.1.2",
|
|
49
50
|
"@types/node": "^22.10.5",
|
|
50
51
|
"typescript": "^5.7.3",
|
|
51
52
|
"vitest": "^2.1.8",
|
|
52
53
|
"zod": "^4.6.5"
|
|
53
54
|
},
|
|
54
55
|
"engines": {
|
|
55
|
-
"node": ">=22.
|
|
56
|
+
"node": ">=22.12.0"
|
|
56
57
|
},
|
|
57
58
|
"publishConfig": {
|
|
58
59
|
"access": "public",
|
package/src/define-check.ts
CHANGED
|
@@ -169,10 +169,19 @@ export function defineCheck<TConfigSchema extends AnySchema = AnySchema>(
|
|
|
169
169
|
|
|
170
170
|
const validate = chainValidator(derivedValidator, spec.validateConfig);
|
|
171
171
|
|
|
172
|
+
// `evaluate` gets the config its schema resolves: the schema's defaults
|
|
173
|
+
// applied (a guardrail that declares no config gets them all), and a
|
|
174
|
+
// config that doesn't fit refused, naming where. Python's guardrails do
|
|
175
|
+
// the same. Without a schema, the config as declared.
|
|
176
|
+
const evaluate = evaluateWithResolvedConfig(
|
|
177
|
+
spec.evaluate as CheckFunction,
|
|
178
|
+
configResolver(zodSchema, jsonSchema, spec.id),
|
|
179
|
+
);
|
|
180
|
+
|
|
172
181
|
const check = {
|
|
173
182
|
id: spec.id,
|
|
174
183
|
kind: spec.kind,
|
|
175
|
-
evaluate
|
|
184
|
+
evaluate,
|
|
176
185
|
...(validate !== undefined && { validateConfig: validate }),
|
|
177
186
|
...(zodSchema !== undefined && { configZod: zodSchema }),
|
|
178
187
|
...(jsonSchema !== undefined && { configJsonSchema: jsonSchema }),
|
|
@@ -181,11 +190,89 @@ export function defineCheck<TConfigSchema extends AnySchema = AnySchema>(
|
|
|
181
190
|
return check;
|
|
182
191
|
}
|
|
183
192
|
|
|
193
|
+
/** `evaluate`, called with the config `resolve` gives (as declared without one). */
|
|
194
|
+
function evaluateWithResolvedConfig(
|
|
195
|
+
evaluate: CheckFunction,
|
|
196
|
+
resolve: ConfigResolver | undefined,
|
|
197
|
+
): CheckFunction {
|
|
198
|
+
if (resolve === undefined) return evaluate;
|
|
199
|
+
return async (config, trace, bindings) =>
|
|
200
|
+
evaluate((await resolve(config)) as Parameters<CheckFunction>[0], trace, bindings);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** The resolver for the check's schema: Zod's own parse, or Ajv for JSON Schema; none without one. */
|
|
204
|
+
function configResolver(
|
|
205
|
+
zodSchema: ZodLikeSchema | undefined,
|
|
206
|
+
jsonSchema: Readonly<Record<string, unknown>> | undefined,
|
|
207
|
+
checkId: string,
|
|
208
|
+
): ConfigResolver | undefined {
|
|
209
|
+
if (zodSchema !== undefined) return zodConfigResolver(zodSchema, checkId);
|
|
210
|
+
if (jsonSchema !== undefined) return jsonConfigResolver(jsonSchema, checkId);
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** A config resolved by its schema: defaults applied, or an error naming what doesn't fit. */
|
|
215
|
+
type ConfigResolver = (config: unknown) => Promise<unknown>;
|
|
216
|
+
|
|
217
|
+
/** The Standard Schema interface (`~standard`) every Zod v4 schema implements. */
|
|
218
|
+
interface StandardSchema {
|
|
219
|
+
readonly validate: (value: unknown) => StandardResult | Promise<StandardResult>;
|
|
220
|
+
}
|
|
221
|
+
type StandardResult =
|
|
222
|
+
| { readonly value: unknown; readonly issues?: undefined }
|
|
223
|
+
| {
|
|
224
|
+
readonly issues: readonly {
|
|
225
|
+
readonly message: string;
|
|
226
|
+
readonly path?: readonly (PropertyKey | { readonly key: PropertyKey })[];
|
|
227
|
+
}[];
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/** A Zod config, parsed by Zod itself (through `~standard`): its defaults and transforms apply. */
|
|
231
|
+
function zodConfigResolver(schema: ZodLikeSchema, checkId: string): ConfigResolver {
|
|
232
|
+
const standard = schema['~standard'] as StandardSchema;
|
|
233
|
+
return async (config) => {
|
|
234
|
+
const result = await standard.validate(config ?? {});
|
|
235
|
+
if (result.issues === undefined) return result.value;
|
|
236
|
+
const issue = result.issues[0];
|
|
237
|
+
const path = (issue?.path ?? [])
|
|
238
|
+
.map((segment) =>
|
|
239
|
+
String(typeof segment === 'object' && segment !== null ? segment.key : segment),
|
|
240
|
+
)
|
|
241
|
+
.join('.');
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Check "${checkId}": the guardrail's config doesn't fit its configSchema${path === '' ? '' : ` at ${path}`}: ${issue?.message ?? 'invalid config'}`,
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** A JSON Schema config: checked by Ajv, which fills in the schema's `default`s (on a copy). */
|
|
249
|
+
function jsonConfigResolver(
|
|
250
|
+
schema: Readonly<Record<string, unknown>>,
|
|
251
|
+
checkId: string,
|
|
252
|
+
): ConfigResolver {
|
|
253
|
+
const validator = compileValidator(schema, checkId, { useDefaults: true });
|
|
254
|
+
return async (config) => {
|
|
255
|
+
const resolved = structuredClone(config ?? {});
|
|
256
|
+
if (validator(resolved)) return resolved;
|
|
257
|
+
const first = validator.errors?.[0] as { instancePath?: string; message?: string } | undefined;
|
|
258
|
+
const path = first?.instancePath ?? '';
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Check "${checkId}": the guardrail's config doesn't fit its configSchema${path === '' ? '' : ` at ${path}`}: ${first?.message ?? 'invalid config'}`,
|
|
261
|
+
);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
184
265
|
function compileValidator(
|
|
185
266
|
schema: Readonly<Record<string, unknown>>,
|
|
186
267
|
checkId: string,
|
|
268
|
+
options: { readonly useDefaults?: boolean } = {},
|
|
187
269
|
): ValidateFunction {
|
|
188
|
-
const ajv = new Ajv2020({
|
|
270
|
+
const ajv = new Ajv2020({
|
|
271
|
+
strict: true,
|
|
272
|
+
allErrors: true,
|
|
273
|
+
allowUnionTypes: false,
|
|
274
|
+
...(options.useDefaults === true && { useDefaults: true }),
|
|
275
|
+
});
|
|
189
276
|
addFormats(ajv);
|
|
190
277
|
try {
|
|
191
278
|
return ajv.compile(schema as object);
|