@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
165 lines • 5.54 kB
JavaScript
export class GuardrailEngine {
rules;
config;
state;
constructor(config) {
this.rules = config.rules || [];
this.config = {
stopOnFatal: true,
enableStreaming: true,
checkInterval: 100,
...config,
};
this.state = this.createInitialState();
}
createInitialState() {
return {
violations: [],
violationsByRule: new Map(),
hasFatalViolations: false,
hasErrorViolations: false,
violationCount: 0,
};
}
check(context) {
const violations = [];
const timestamp = Date.now();
if (this.config.onPhaseStart) {
this.config.onPhaseStart(context.content.length, this.rules.length);
}
let ruleIndex = 0;
for (const rule of this.rules) {
if (rule.streaming &&
!this.config.enableStreaming &&
!context.completed) {
continue;
}
if (!rule.streaming && !context.completed) {
continue;
}
if (this.config.onRuleStart) {
this.config.onRuleStart(ruleIndex, rule.name);
}
try {
const ruleViolations = rule.check({
...context,
previousViolations: this.state.violations,
});
for (const violation of ruleViolations) {
violations.push({
...violation,
timestamp: timestamp,
});
}
if (ruleViolations.length > 0) {
const existing = this.state.violationsByRule.get(rule.name) || [];
this.state.violationsByRule.set(rule.name, [
...existing,
...ruleViolations,
]);
}
if (this.config.onRuleEnd) {
this.config.onRuleEnd(ruleIndex, rule.name);
}
if (this.config.stopOnFatal &&
ruleViolations.some((v) => v.severity === "fatal")) {
break;
}
}
catch (error) {
violations.push({
rule: rule.name,
message: `Rule execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
severity: "warning",
recoverable: true,
timestamp,
});
if (this.config.onRuleEnd) {
this.config.onRuleEnd(ruleIndex, rule.name);
}
}
ruleIndex++;
}
if (this.config.onPhaseEnd) {
this.config.onPhaseEnd(this.rules.length, violations.length);
}
this.state.violations.push(...violations);
this.state.violationCount = this.state.violations.length;
this.state.hasFatalViolations = violations.some((v) => v.severity === "fatal");
this.state.hasErrorViolations = violations.some((v) => v.severity === "error");
this.state.lastCheckTime = timestamp;
if (this.config.onViolation) {
for (const violation of violations) {
this.config.onViolation(violation);
}
}
const result = {
passed: violations.length === 0,
violations,
shouldRetry: this.shouldRetry(violations),
shouldHalt: this.shouldHalt(violations),
summary: {
total: violations.length,
fatal: violations.filter((v) => v.severity === "fatal").length,
errors: violations.filter((v) => v.severity === "error").length,
warnings: violations.filter((v) => v.severity === "warning").length,
},
};
return result;
}
shouldRetry(violations) {
return violations.some((v) => v.recoverable && (v.severity === "error" || v.severity === "fatal"));
}
shouldHalt(violations) {
if (violations.some((v) => v.severity === "fatal")) {
return true;
}
if (violations.some((v) => !v.recoverable && v.severity === "error")) {
return true;
}
return false;
}
getState() {
return { ...this.state };
}
reset() {
this.state = this.createInitialState();
}
addRule(rule) {
this.rules.push(rule);
}
removeRule(ruleName) {
const index = this.rules.findIndex((r) => r.name === ruleName);
if (index !== -1) {
this.rules.splice(index, 1);
return true;
}
return false;
}
getViolationsByRule(ruleName) {
return this.state.violationsByRule.get(ruleName) || [];
}
getAllViolations() {
return [...this.state.violations];
}
hasViolations() {
return this.state.violationCount > 0;
}
hasFatalViolations() {
return this.state.hasFatalViolations;
}
hasErrorViolations() {
return this.state.hasErrorViolations;
}
}
export function createGuardrailEngine(rules, options) {
return new GuardrailEngine({
rules,
...options,
});
}
export function checkGuardrails(context, rules) {
const engine = createGuardrailEngine(rules);
return engine.check(context);
}
//# sourceMappingURL=engine.js.map