@sovr/engine 3.2.0 → 3.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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,354 @@
1
+ /**
2
+ * @sovr/engine — Expression Tree Engine
3
+ *
4
+ * Compiles SOVR Policy DSL rules into an AST (Abstract Syntax Tree),
5
+ * supporting complex condition composition, short-circuit evaluation,
6
+ * and high-performance cached execution.
7
+ *
8
+ * Features:
9
+ * - Nested AND/OR/NOT logic
10
+ * - Comparison operators: ==, !=, >, <, >=, <=, in, not_in, contains, starts_with, ends_with, matches
11
+ * - Variable references (dot-separated paths from context)
12
+ * - Built-in functions (now_hour, risk_level, is_business_hours, etc.)
13
+ * - Compile once, evaluate many times
14
+ *
15
+ * @since 3.3.0
16
+ */
17
+ type ExpressionNode = LogicalNode | ComparisonNode | NotNode | LiteralNode | VariableNode | FunctionNode;
18
+ interface LogicalNode {
19
+ type: 'AND' | 'OR';
20
+ children: ExpressionNode[];
21
+ }
22
+ interface NotNode {
23
+ type: 'NOT';
24
+ child: ExpressionNode;
25
+ }
26
+ interface ComparisonNode {
27
+ type: 'COMPARE';
28
+ operator: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'in' | 'not_in' | 'contains' | 'starts_with' | 'ends_with' | 'matches';
29
+ left: ExpressionNode;
30
+ right: ExpressionNode;
31
+ }
32
+ interface LiteralNode {
33
+ type: 'LITERAL';
34
+ value: string | number | boolean | string[] | number[];
35
+ }
36
+ interface VariableNode {
37
+ type: 'VARIABLE';
38
+ path: string;
39
+ }
40
+ interface FunctionNode {
41
+ type: 'FUNCTION';
42
+ name: string;
43
+ args: ExpressionNode[];
44
+ }
45
+ interface EvalContext {
46
+ [key: string]: any;
47
+ }
48
+ interface CompiledExpression {
49
+ ast: ExpressionNode;
50
+ evaluate: (ctx: EvalContext) => boolean;
51
+ toString: () => string;
52
+ variables: string[];
53
+ }
54
+ /**
55
+ * Compile a JSON rule definition into an expression tree.
56
+ *
57
+ * Supported JSON formats:
58
+ * ```json
59
+ * { "and": [...conditions] }
60
+ * { "or": [...conditions] }
61
+ * { "not": condition }
62
+ * { "field": "action.type", "op": "==", "value": "delete" }
63
+ * { "field": "risk_score", "op": ">", "value": 0.8 }
64
+ * { "field": "user.role", "op": "in", "value": ["admin", "owner"] }
65
+ * { "fn": "now_hour", "op": ">=", "value": 22 }
66
+ * ```
67
+ */
68
+ declare function compileFromJSON(rule: any): CompiledExpression;
69
+ /**
70
+ * Register a custom function for use in expression trees.
71
+ */
72
+ declare function registerFunction(name: string, fn: (args: any[], ctx: EvalContext) => any): void;
73
+ interface ExprTreePolicyRule {
74
+ id: string;
75
+ name: string;
76
+ priority: number;
77
+ condition: any;
78
+ action: 'ALLOW' | 'DENY' | 'REQUIRE_APPROVAL' | 'LOG';
79
+ metadata?: Record<string, any>;
80
+ }
81
+ interface RuleEvalResult {
82
+ ruleId: string;
83
+ ruleName: string;
84
+ matched: boolean;
85
+ action: string;
86
+ evaluationTimeMs: number;
87
+ }
88
+ declare function compileRuleSet(rules: ExprTreePolicyRule[]): void;
89
+ /**
90
+ * Evaluate all rules against a context (sorted by priority, first match wins).
91
+ */
92
+ declare function evaluateRules(rules: ExprTreePolicyRule[], ctx: EvalContext): {
93
+ matched: ExprTreePolicyRule | null;
94
+ results: RuleEvalResult[];
95
+ };
96
+
97
+ /**
98
+ * @sovr/engine — Adaptive Threshold Module
99
+ *
100
+ * Automatically adjusts risk-control thresholds based on historical decision data:
101
+ * - Sliding window statistics (false positive rate, false negative rate, pass rate)
102
+ * - EWMA (Exponentially Weighted Moving Average) threshold self-adjustment
103
+ * - Safety boundary protection (thresholds never exceed [min, max] range)
104
+ * - Change audit (every adjustment is logged via callback)
105
+ *
106
+ * This module is database-agnostic — it uses in-memory storage and emits
107
+ * adjustment events via a configurable callback for external persistence.
108
+ *
109
+ * @since 3.3.0
110
+ */
111
+ interface ThresholdConfig {
112
+ /** Threshold name (e.g., risk_score, cost_limit, latency_p99) */
113
+ name: string;
114
+ /** Current value */
115
+ currentValue: number;
116
+ /** Minimum allowed value (safety lower bound) */
117
+ minValue: number;
118
+ /** Maximum allowed value (safety upper bound) */
119
+ maxValue: number;
120
+ /** EWMA smoothing factor (0 < alpha < 1), higher = more responsive */
121
+ alpha: number;
122
+ /** Maximum adjustment step per cycle (percentage) */
123
+ maxStepPercent: number;
124
+ /** Last adjustment timestamp */
125
+ lastAdjustedAt: number;
126
+ /** Direction lock (prevents oscillation) */
127
+ directionLock: 'up' | 'down' | null;
128
+ /** Consecutive same-direction adjustment count */
129
+ consecutiveAdjustments: number;
130
+ }
131
+ interface DecisionFeedback {
132
+ /** Decision ID */
133
+ decisionId: string;
134
+ /** Threshold name */
135
+ thresholdName: string;
136
+ /** Threshold value at decision time */
137
+ thresholdAtDecision: number;
138
+ /** Actual risk score */
139
+ actualScore: number;
140
+ /** Decision outcome */
141
+ outcome: 'true_positive' | 'true_negative' | 'false_positive' | 'false_negative';
142
+ /** Timestamp */
143
+ timestamp: number;
144
+ }
145
+ interface AdjustmentResult {
146
+ thresholdName: string;
147
+ previousValue: number;
148
+ newValue: number;
149
+ reason: string;
150
+ metrics: {
151
+ falsePositiveRate: number;
152
+ falseNegativeRate: number;
153
+ totalSamples: number;
154
+ windowHours: number;
155
+ };
156
+ }
157
+ interface AdaptiveThresholdOptions {
158
+ /** Custom threshold configurations (overrides defaults) */
159
+ thresholds?: ThresholdConfig[];
160
+ /** Maximum feedback buffer size */
161
+ maxBufferSize?: number;
162
+ /** Cooldown between adjustments in milliseconds */
163
+ adjustmentCooldownMs?: number;
164
+ /** Callback for audit trail (called on every adjustment) */
165
+ onAdjustment?: (result: AdjustmentResult) => void | Promise<void>;
166
+ }
167
+ declare class AdaptiveThresholdManager {
168
+ private thresholds;
169
+ private feedbackBuffer;
170
+ private maxBufferSize;
171
+ private cooldownMs;
172
+ private onAdjustment?;
173
+ constructor(options?: AdaptiveThresholdOptions);
174
+ /** Get a threshold by name */
175
+ getThreshold(name: string): ThresholdConfig | undefined;
176
+ /** Get all thresholds */
177
+ getAllThresholds(): ThresholdConfig[];
178
+ /** Record a decision feedback sample */
179
+ recordFeedback(feedback: DecisionFeedback): void;
180
+ /**
181
+ * Adjust a single threshold based on feedback (EWMA algorithm).
182
+ * Returns null if no adjustment is needed (cooldown, insufficient samples, etc.).
183
+ */
184
+ adjustThreshold(thresholdName: string, windowHours?: number): Promise<AdjustmentResult | null>;
185
+ /** Adjust all thresholds */
186
+ adjustAll(windowHours?: number): Promise<AdjustmentResult[]>;
187
+ /** Manually override a threshold value */
188
+ setThresholdManual(name: string, value: number): boolean;
189
+ /** Get feedback statistics for a threshold (or all) */
190
+ getFeedbackStats(thresholdName?: string, windowHours?: number): {
191
+ total: number;
192
+ truePositive: number;
193
+ trueNegative: number;
194
+ falsePositive: number;
195
+ falseNegative: number;
196
+ accuracy: number;
197
+ precision: number;
198
+ recall: number;
199
+ };
200
+ /** Clear the feedback buffer */
201
+ clearFeedback(): void;
202
+ }
203
+
204
+ /**
205
+ * @sovr/engine — Feature Switches Module
206
+ *
207
+ * Manages 4 core feature switches for the SOVR decision plane:
208
+ * - USE_NEW_RISK_ENGINE: Enable expression tree + adaptive threshold engine
209
+ * - ENFORCE_COST_CAP: Hard-reject when agent cost exceeds budget
210
+ * - ENABLE_PROMPT_GUARD: Enable prompt injection scanning for all LLM calls
211
+ * - DISABLE_EVIDENCE_PAUSE: Keep evidence chain writing even under high load
212
+ *
213
+ * All switches are stored in-memory with configurable persistence callbacks.
214
+ * Supports multi-tenant isolation and TTL-based caching.
215
+ *
216
+ * @since 3.3.0
217
+ */
218
+ interface FeatureSwitchDef {
219
+ key: string;
220
+ description: string;
221
+ defaultValue: boolean;
222
+ category: 'risk' | 'cost' | 'security' | 'evidence';
223
+ impactLevel: 'high' | 'medium' | 'low';
224
+ }
225
+ interface FeatureSwitchState {
226
+ key: string;
227
+ value: boolean;
228
+ description: string;
229
+ category: string;
230
+ impactLevel: string;
231
+ isDefault: boolean;
232
+ }
233
+ interface FeatureSwitchesOptions {
234
+ /** Cache TTL in milliseconds (default: 30000) */
235
+ cacheTtlMs?: number;
236
+ /** Callback to load switch value from external storage */
237
+ onLoad?: (key: string, tenantId: string) => Promise<boolean | null>;
238
+ /** Callback to save switch value to external storage */
239
+ onSave?: (key: string, value: boolean, tenantId: string) => Promise<void>;
240
+ }
241
+ declare const SOVR_FEATURE_SWITCHES: Record<string, FeatureSwitchDef>;
242
+ declare class FeatureSwitchesManager {
243
+ private cache;
244
+ private cacheTtlMs;
245
+ private onLoad?;
246
+ private onSave?;
247
+ constructor(options?: FeatureSwitchesOptions);
248
+ /**
249
+ * Get a switch value (with cache + optional external load).
250
+ */
251
+ getValue(key: string, tenantId?: string): Promise<boolean>;
252
+ /**
253
+ * Set a switch value (updates cache + optional external save).
254
+ */
255
+ setValue(key: string, value: boolean, tenantId?: string): Promise<void>;
256
+ /**
257
+ * Get all switch states.
258
+ */
259
+ getAll(tenantId?: string): Promise<Record<string, FeatureSwitchState>>;
260
+ /** Clear the cache (for testing or forced refresh) */
261
+ clearCache(): void;
262
+ isNewRiskEngineEnabled(tenantId?: string): Promise<boolean>;
263
+ isCostCapEnforced(tenantId?: string): Promise<boolean>;
264
+ isPromptGuardEnabled(tenantId?: string): Promise<boolean>;
265
+ isEvidencePauseDisabled(tenantId?: string): Promise<boolean>;
266
+ }
267
+
268
+ /**
269
+ * @sovr/engine — Pricing Rules Engine
270
+ *
271
+ * Evaluates pricing rules for SOVR-governed actions.
272
+ * Supports tiered pricing, volume discounts, time-based multipliers,
273
+ * and cost-cap enforcement.
274
+ *
275
+ * Schema reference (sovr_pricing_rules table):
276
+ * id, rule_name, tier, action_pattern, base_cost_usd, multiplier,
277
+ * volume_discount_threshold, volume_discount_percent, time_window_start,
278
+ * time_window_end, is_active, priority, created_at, updated_at
279
+ *
280
+ * This module is database-agnostic — rules are loaded into memory
281
+ * and evaluated purely in-process.
282
+ *
283
+ * @since 3.3.0
284
+ */
285
+ interface PricingRule {
286
+ id: string;
287
+ ruleName: string;
288
+ /** Which tier this rule applies to (empty string = all tiers) */
289
+ tier: string;
290
+ /** Glob pattern for action names */
291
+ actionPattern: string;
292
+ /** Base cost in USD */
293
+ baseCostUsd: number;
294
+ /** Cost multiplier (default 1.0) */
295
+ multiplier: number;
296
+ /** Volume discount threshold (number of actions) */
297
+ volumeDiscountThreshold: number;
298
+ /** Volume discount percentage (0-100) */
299
+ volumeDiscountPercent: number;
300
+ /** Time window start hour (0-23, -1 = no time restriction) */
301
+ timeWindowStart: number;
302
+ /** Time window end hour (0-23, -1 = no time restriction) */
303
+ timeWindowEnd: number;
304
+ /** Whether this rule is active */
305
+ isActive: boolean;
306
+ /** Priority (higher = evaluated first) */
307
+ priority: number;
308
+ }
309
+ interface PricingEvalRequest {
310
+ /** Action being performed */
311
+ action: string;
312
+ /** Actor's tier */
313
+ tier: string;
314
+ /** Number of actions already performed in current period */
315
+ currentVolume: number;
316
+ /** Current hour (0-23), defaults to now */
317
+ currentHour?: number;
318
+ }
319
+ interface PricingEvalResult {
320
+ /** Final computed cost in USD */
321
+ costUsd: number;
322
+ /** Base cost before adjustments */
323
+ baseCostUsd: number;
324
+ /** Applied multiplier */
325
+ multiplier: number;
326
+ /** Volume discount applied (0-100) */
327
+ volumeDiscountPercent: number;
328
+ /** Whether a time-based rule was applied */
329
+ timeWindowActive: boolean;
330
+ /** Which rule was matched */
331
+ matchedRuleId: string | null;
332
+ /** Human-readable breakdown */
333
+ breakdown: string;
334
+ }
335
+ declare class PricingRulesEngine {
336
+ private rules;
337
+ constructor(rules?: PricingRule[]);
338
+ /** Load rules (sorted by priority descending) */
339
+ loadRules(rules: PricingRule[]): void;
340
+ /** Add a single rule */
341
+ addRule(rule: PricingRule): void;
342
+ /** Get all loaded rules */
343
+ getRules(): readonly PricingRule[];
344
+ /**
345
+ * Evaluate pricing for an action.
346
+ * Returns the computed cost and breakdown.
347
+ */
348
+ evaluate(request: PricingEvalRequest): PricingEvalResult;
349
+ private globMatch;
350
+ }
351
+
1
352
  /**
2
353
  * @sovr/engine — Unified Policy Engine
3
354
  *
@@ -214,4 +565,4 @@ declare class PolicyEngine {
214
565
  }): void;
215
566
  }
216
567
 
217
- export { type AuditEvent, type Channel, DEFAULT_RULES, type EngineConfig, type EngineTier, type EngineTierLimits, type EvalRequest, type EvalResult, type ExecContext, type HttpContext, type McpContext, PolicyEngine, type PolicyRule, type RiskLevel, type RuleCondition, type SqlContext, type Verdict, PolicyEngine as default };
568
+ export { AdaptiveThresholdManager, type AdaptiveThresholdOptions, type AdjustmentResult, type AuditEvent, type Channel, type ComparisonNode, type CompiledExpression, DEFAULT_RULES, type DecisionFeedback, type EngineConfig, type EngineTier, type EngineTierLimits, type EvalContext, type EvalRequest, type EvalResult, type ExecContext, type ExprTreePolicyRule, type ExpressionNode, type FeatureSwitchDef, type FeatureSwitchState, FeatureSwitchesManager, type FeatureSwitchesOptions, type FunctionNode, type HttpContext, type LiteralNode, type LogicalNode, type McpContext, type NotNode, PolicyEngine, type PolicyRule, type PricingEvalRequest, type PricingEvalResult, type PricingRule, PricingRulesEngine, type RiskLevel, type RuleCondition, type RuleEvalResult, SOVR_FEATURE_SWITCHES, type SqlContext, type ThresholdConfig, type VariableNode, type Verdict, compileFromJSON, compileRuleSet, PolicyEngine as default, evaluateRules, registerFunction };