UNPKG

llmverify

Version:

AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.

124 lines 12.9 kB
"use strict"; /** * Baseline Engine * * Maintains and updates baseline metrics for drift detection. * Uses exponential moving average for stability. * * WHAT THIS DOES: * ✅ Tracks average latency, token rate, similarity * ✅ Maintains response fingerprint baseline * ✅ Uses EMA for smooth baseline updates * * WHAT THIS DOES NOT DO: * ❌ Persist baselines across sessions (in-memory only) * ❌ Account for intentional model changes * ❌ Distinguish normal variation from anomalies * * @module engines/runtime/baseline * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BaselineEngine = void 0; /** * Manages baseline state for LLM monitoring. * * @example * const baseline = new BaselineEngine(); * * // After each call * baseline.update(callRecord, fingerprint, similarity); * * // Get current baseline * const state = baseline.get(); */ class BaselineEngine { /** * Creates a new BaselineEngine. * * @param learningRate - EMA learning rate (0-1, default: 0.1) * @param minSamples - Minimum samples before baseline is stable (default: 5) */ constructor(learningRate = 0.1, minSamples = 5) { this.learningRate = Math.max(0.01, Math.min(1, learningRate)); this.minSamples = minSamples; this.baseline = { avgLatencyMs: 0, avgTokensPerSecond: 0, avgSimilarity: 0.85, fingerprint: {}, sampleCount: 0 }; } /** * Updates baseline with new call data. * * @param call - The call record * @param fingerprint - Response fingerprint * @param similarity - Similarity score (0-1) */ update(call, fingerprint, similarity = 1) { const alpha = this.learningRate; const tps = call.responseTokens / Math.max(call.latencyMs / 1000, 0.001); if (this.baseline.sampleCount === 0) { // First sample - initialize directly this.baseline.avgLatencyMs = call.latencyMs; this.baseline.avgTokensPerSecond = tps; this.baseline.fingerprint = fingerprint; this.baseline.avgSimilarity = similarity; } else { // EMA update this.baseline.avgLatencyMs = alpha * call.latencyMs + (1 - alpha) * this.baseline.avgLatencyMs; this.baseline.avgTokensPerSecond = alpha * tps + (1 - alpha) * this.baseline.avgTokensPerSecond; this.baseline.avgSimilarity = alpha * similarity + (1 - alpha) * this.baseline.avgSimilarity; // Update fingerprint with EMA if (this.baseline.fingerprint && 'tokens' in this.baseline.fingerprint) { const fp = this.baseline.fingerprint; this.baseline.fingerprint = { tokens: alpha * fingerprint.tokens + (1 - alpha) * fp.tokens, sentences: alpha * fingerprint.sentences + (1 - alpha) * fp.sentences, avgSentLength: alpha * fingerprint.avgSentLength + (1 - alpha) * fp.avgSentLength, entropy: alpha * fingerprint.entropy + (1 - alpha) * fp.entropy }; } else { this.baseline.fingerprint = fingerprint; } } this.baseline.sampleCount++; } /** * Gets current baseline state. */ get() { return { ...this.baseline }; } /** * Checks if baseline has enough samples to be stable. */ isStable() { return this.baseline.sampleCount >= this.minSamples; } /** * Resets baseline to initial state. */ reset() { this.baseline = { avgLatencyMs: 0, avgTokensPerSecond: 0, avgSimilarity: 0.85, fingerprint: {}, sampleCount: 0 }; } /** * Gets sample count. */ getSampleCount() { return this.baseline.sampleCount; } } exports.BaselineEngine = BaselineEngine; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZWxpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9ydW50aW1lL2Jhc2VsaW5lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRzs7O0FBSUg7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFhLGNBQWM7SUFLekI7Ozs7O09BS0c7SUFDSCxZQUFZLGVBQXVCLEdBQUcsRUFBRSxhQUFxQixDQUFDO1FBQzVELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUM5RCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsUUFBUSxHQUFHO1lBQ2QsWUFBWSxFQUFFLENBQUM7WUFDZixrQkFBa0IsRUFBRSxDQUFDO1lBQ3JCLGFBQWEsRUFBRSxJQUFJO1lBQ25CLFdBQVcsRUFBRSxFQUFFO1lBQ2YsV0FBVyxFQUFFLENBQUM7U0FDZixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxJQUFnQixFQUFFLFdBQWdDLEVBQUUsYUFBcUIsQ0FBQztRQUMvRSxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ2hDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV6RSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3BDLHFDQUFxQztZQUNyQyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQzVDLElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEdBQUcsR0FBRyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztZQUN4QyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsR0FBRyxVQUFVLENBQUM7UUFDM0MsQ0FBQzthQUFNLENBQUM7WUFDTixhQUFhO1lBQ2IsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEdBQUcsS0FBSyxHQUFHLElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7WUFDL0YsSUFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUM7WUFDaEcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLEdBQUcsS0FBSyxHQUFHLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQztZQUU3Riw4QkFBOEI7WUFDOUIsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBSSxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDdkUsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFrQyxDQUFDO2dCQUM1RCxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsR0FBRztvQkFDMUIsTUFBTSxFQUFFLEtBQUssR0FBRyxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNO29CQUM1RCxTQUFTLEVBQUUsS0FBSyxHQUFHLFdBQVcsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLFNBQVM7b0JBQ3JFLGFBQWEsRUFBRSxLQUFLLEdBQUcsV0FBVyxDQUFDLGFBQWEsR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsYUFBYTtvQkFDakYsT0FBTyxFQUFFLEtBQUssR0FBRyxXQUFXLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPO2lCQUNoRSxDQUFDO1lBQ0osQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztZQUMxQyxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsR0FBRztRQUNELE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3RELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxJQUFJLENBQUMsUUFBUSxHQUFHO1lBQ2QsWUFBWSxFQUFFLENBQUM7WUFDZixrQkFBa0IsRUFBRSxDQUFDO1lBQ3JCLGFBQWEsRUFBRSxJQUFJO1lBQ25CLFdBQVcsRUFBRSxFQUFFO1lBQ2YsV0FBVyxFQUFFLENBQUM7U0FDZixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0gsY0FBYztRQUNaLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7SUFDbkMsQ0FBQztDQUNGO0FBaEdELHdDQWdHQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQmFzZWxpbmUgRW5naW5lXG4gKiBcbiAqIE1haW50YWlucyBhbmQgdXBkYXRlcyBiYXNlbGluZSBtZXRyaWNzIGZvciBkcmlmdCBkZXRlY3Rpb24uXG4gKiBVc2VzIGV4cG9uZW50aWFsIG1vdmluZyBhdmVyYWdlIGZvciBzdGFiaWxpdHkuXG4gKiBcbiAqIFdIQVQgVEhJUyBET0VTOlxuICog4pyFIFRyYWNrcyBhdmVyYWdlIGxhdGVuY3ksIHRva2VuIHJhdGUsIHNpbWlsYXJpdHlcbiAqIOKchSBNYWludGFpbnMgcmVzcG9uc2UgZmluZ2VycHJpbnQgYmFzZWxpbmVcbiAqIOKchSBVc2VzIEVNQSBmb3Igc21vb3RoIGJhc2VsaW5lIHVwZGF0ZXNcbiAqIFxuICogV0hBVCBUSElTIERPRVMgTk9UIERPOlxuICog4p2MIFBlcnNpc3QgYmFzZWxpbmVzIGFjcm9zcyBzZXNzaW9ucyAoaW4tbWVtb3J5IG9ubHkpXG4gKiDinYwgQWNjb3VudCBmb3IgaW50ZW50aW9uYWwgbW9kZWwgY2hhbmdlc1xuICog4p2MIERpc3Rpbmd1aXNoIG5vcm1hbCB2YXJpYXRpb24gZnJvbSBhbm9tYWxpZXNcbiAqIFxuICogQG1vZHVsZSBlbmdpbmVzL3J1bnRpbWUvYmFzZWxpbmVcbiAqIEBhdXRob3IgSGFpZWNcbiAqIEBsaWNlbnNlIE1JVFxuICovXG5cbmltcG9ydCB7IENhbGxSZWNvcmQsIEJhc2VsaW5lU3RhdGUsIFJlc3BvbnNlRmluZ2VycHJpbnQgfSBmcm9tICcuLi8uLi90eXBlcy9ydW50aW1lJztcblxuLyoqXG4gKiBNYW5hZ2VzIGJhc2VsaW5lIHN0YXRlIGZvciBMTE0gbW9uaXRvcmluZy5cbiAqIFxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGJhc2VsaW5lID0gbmV3IEJhc2VsaW5lRW5naW5lKCk7XG4gKiBcbiAqIC8vIEFmdGVyIGVhY2ggY2FsbFxuICogYmFzZWxpbmUudXBkYXRlKGNhbGxSZWNvcmQsIGZpbmdlcnByaW50LCBzaW1pbGFyaXR5KTtcbiAqIFxuICogLy8gR2V0IGN1cnJlbnQgYmFzZWxpbmVcbiAqIGNvbnN0IHN0YXRlID0gYmFzZWxpbmUuZ2V0KCk7XG4gKi9cbmV4cG9ydCBjbGFzcyBCYXNlbGluZUVuZ2luZSB7XG4gIHByaXZhdGUgYmFzZWxpbmU6IEJhc2VsaW5lU3RhdGU7XG4gIHByaXZhdGUgcmVhZG9ubHkgbGVhcm5pbmdSYXRlOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWluU2FtcGxlczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IEJhc2VsaW5lRW5naW5lLlxuICAgKiBcbiAgICogQHBhcmFtIGxlYXJuaW5nUmF0ZSAtIEVNQSBsZWFybmluZyByYXRlICgwLTEsIGRlZmF1bHQ6IDAuMSlcbiAgICogQHBhcmFtIG1pblNhbXBsZXMgLSBNaW5pbXVtIHNhbXBsZXMgYmVmb3JlIGJhc2VsaW5lIGlzIHN0YWJsZSAoZGVmYXVsdDogNSlcbiAgICovXG4gIGNvbnN0cnVjdG9yKGxlYXJuaW5nUmF0ZTogbnVtYmVyID0gMC4xLCBtaW5TYW1wbGVzOiBudW1iZXIgPSA1KSB7XG4gICAgdGhpcy5sZWFybmluZ1JhdGUgPSBNYXRoLm1heCgwLjAxLCBNYXRoLm1pbigxLCBsZWFybmluZ1JhdGUpKTtcbiAgICB0aGlzLm1pblNhbXBsZXMgPSBtaW5TYW1wbGVzO1xuICAgIHRoaXMuYmFzZWxpbmUgPSB7XG4gICAgICBhdmdMYXRlbmN5TXM6IDAsXG4gICAgICBhdmdUb2tlbnNQZXJTZWNvbmQ6IDAsXG4gICAgICBhdmdTaW1pbGFyaXR5OiAwLjg1LFxuICAgICAgZmluZ2VycHJpbnQ6IHt9LFxuICAgICAgc2FtcGxlQ291bnQ6IDBcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYmFzZWxpbmUgd2l0aCBuZXcgY2FsbCBkYXRhLlxuICAgKiBcbiAgICogQHBhcmFtIGNhbGwgLSBUaGUgY2FsbCByZWNvcmRcbiAgICogQHBhcmFtIGZpbmdlcnByaW50IC0gUmVzcG9uc2UgZmluZ2VycHJpbnRcbiAgICogQHBhcmFtIHNpbWlsYXJpdHkgLSBTaW1pbGFyaXR5IHNjb3JlICgwLTEpXG4gICAqL1xuICB1cGRhdGUoY2FsbDogQ2FsbFJlY29yZCwgZmluZ2VycHJpbnQ6IFJlc3BvbnNlRmluZ2VycHJpbnQsIHNpbWlsYXJpdHk6IG51bWJlciA9IDEpOiB2b2lkIHtcbiAgICBjb25zdCBhbHBoYSA9IHRoaXMubGVhcm5pbmdSYXRlO1xuICAgIGNvbnN0IHRwcyA9IGNhbGwucmVzcG9uc2VUb2tlbnMgLyBNYXRoLm1heChjYWxsLmxhdGVuY3lNcyAvIDEwMDAsIDAuMDAxKTtcblxuICAgIGlmICh0aGlzLmJhc2VsaW5lLnNhbXBsZUNvdW50ID09PSAwKSB7XG4gICAgICAvLyBGaXJzdCBzYW1wbGUgLSBpbml0aWFsaXplIGRpcmVjdGx5XG4gICAgICB0aGlzLmJhc2VsaW5lLmF2Z0xhdGVuY3lNcyA9IGNhbGwubGF0ZW5jeU1zO1xuICAgICAgdGhpcy5iYXNlbGluZS5hdmdUb2tlbnNQZXJTZWNvbmQgPSB0cHM7XG4gICAgICB0aGlzLmJhc2VsaW5lLmZpbmdlcnByaW50ID0gZmluZ2VycHJpbnQ7XG4gICAgICB0aGlzLmJhc2VsaW5lLmF2Z1NpbWlsYXJpdHkgPSBzaW1pbGFyaXR5O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBFTUEgdXBkYXRlXG4gICAgICB0aGlzLmJhc2VsaW5lLmF2Z0xhdGVuY3lNcyA9IGFscGhhICogY2FsbC5sYXRlbmN5TXMgKyAoMSAtIGFscGhhKSAqIHRoaXMuYmFzZWxpbmUuYXZnTGF0ZW5jeU1zO1xuICAgICAgdGhpcy5iYXNlbGluZS5hdmdUb2tlbnNQZXJTZWNvbmQgPSBhbHBoYSAqIHRwcyArICgxIC0gYWxwaGEpICogdGhpcy5iYXNlbGluZS5hdmdUb2tlbnNQZXJTZWNvbmQ7XG4gICAgICB0aGlzLmJhc2VsaW5lLmF2Z1NpbWlsYXJpdHkgPSBhbHBoYSAqIHNpbWlsYXJpdHkgKyAoMSAtIGFscGhhKSAqIHRoaXMuYmFzZWxpbmUuYXZnU2ltaWxhcml0eTtcblxuICAgICAgLy8gVXBkYXRlIGZpbmdlcnByaW50IHdpdGggRU1BXG4gICAgICBpZiAodGhpcy5iYXNlbGluZS5maW5nZXJwcmludCAmJiAndG9rZW5zJyBpbiB0aGlzLmJhc2VsaW5lLmZpbmdlcnByaW50KSB7XG4gICAgICAgIGNvbnN0IGZwID0gdGhpcy5iYXNlbGluZS5maW5nZXJwcmludCBhcyBSZXNwb25zZUZpbmdlcnByaW50O1xuICAgICAgICB0aGlzLmJhc2VsaW5lLmZpbmdlcnByaW50ID0ge1xuICAgICAgICAgIHRva2VuczogYWxwaGEgKiBmaW5nZXJwcmludC50b2tlbnMgKyAoMSAtIGFscGhhKSAqIGZwLnRva2VucyxcbiAgICAgICAgICBzZW50ZW5jZXM6IGFscGhhICogZmluZ2VycHJpbnQuc2VudGVuY2VzICsgKDEgLSBhbHBoYSkgKiBmcC5zZW50ZW5jZXMsXG4gICAgICAgICAgYXZnU2VudExlbmd0aDogYWxwaGEgKiBmaW5nZXJwcmludC5hdmdTZW50TGVuZ3RoICsgKDEgLSBhbHBoYSkgKiBmcC5hdmdTZW50TGVuZ3RoLFxuICAgICAgICAgIGVudHJvcHk6IGFscGhhICogZmluZ2VycHJpbnQuZW50cm9weSArICgxIC0gYWxwaGEpICogZnAuZW50cm9weVxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5iYXNlbGluZS5maW5nZXJwcmludCA9IGZpbmdlcnByaW50O1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuYmFzZWxpbmUuc2FtcGxlQ291bnQrKztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGN1cnJlbnQgYmFzZWxpbmUgc3RhdGUuXG4gICAqL1xuICBnZXQoKTogQmFzZWxpbmVTdGF0ZSB7XG4gICAgcmV0dXJuIHsgLi4udGhpcy5iYXNlbGluZSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBiYXNlbGluZSBoYXMgZW5vdWdoIHNhbXBsZXMgdG8gYmUgc3RhYmxlLlxuICAgKi9cbiAgaXNTdGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYmFzZWxpbmUuc2FtcGxlQ291bnQgPj0gdGhpcy5taW5TYW1wbGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyBiYXNlbGluZSB0byBpbml0aWFsIHN0YXRlLlxuICAgKi9cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy5iYXNlbGluZSA9IHtcbiAgICAgIGF2Z0xhdGVuY3lNczogMCxcbiAgICAgIGF2Z1Rva2Vuc1BlclNlY29uZDogMCxcbiAgICAgIGF2Z1NpbWlsYXJpdHk6IDAuODUsXG4gICAgICBmaW5nZXJwcmludDoge30sXG4gICAgICBzYW1wbGVDb3VudDogMFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBzYW1wbGUgY291bnQuXG4gICAqL1xuICBnZXRTYW1wbGVDb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmJhc2VsaW5lLnNhbXBsZUNvdW50O1xuICB9XG59XG4iXX0=