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.
157 lines • 15.9 kB
JavaScript
;
/**
* Health Score Engine
*
* Aggregates engine results into a composite health score.
* Provides actionable health status and recommendations.
*
* WHAT THIS DOES:
* ✅ Combines multiple engine results
* ✅ Calculates weighted health score
* ✅ Provides actionable status levels
* ✅ Generates recommendations
*
* WHAT THIS DOES NOT DO:
* ❌ Predict future health
* ❌ Identify root causes
* ❌ Guarantee accuracy of individual engines
*
* @module engines/runtime/health-score
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.HealthScoreEngine = HealthScoreEngine;
exports.isHealthy = isHealthy;
exports.getAlertLevel = getAlertLevel;
/**
* Default weights for each metric.
* Consistency and latency are weighted higher as they're most impactful.
*/
const DEFAULT_WEIGHTS = {
consistency: 0.25,
structure: 0.15,
latency: 0.25,
token_rate: 0.15,
fingerprint: 0.20
};
/**
* Generates recommendations based on engine results.
*/
function generateRecommendations(results) {
const recommendations = [];
for (const result of results) {
if (result.status === 'error') {
switch (result.metric) {
case 'latency':
recommendations.push('High latency detected. Consider checking provider status or implementing retry logic.');
break;
case 'token_rate':
recommendations.push('Low token rate detected. Provider may be throttling or experiencing issues.');
break;
case 'fingerprint':
recommendations.push('Response structure has changed significantly. Verify model behavior.');
break;
case 'structure':
recommendations.push('Structural anomalies detected. Check for truncation or format issues.');
break;
case 'consistency':
recommendations.push('Response consistency issues detected. Consider implementing validation.');
break;
}
}
else if (result.status === 'warn') {
switch (result.metric) {
case 'latency':
recommendations.push('Latency slightly elevated. Monitor for trends.');
break;
case 'token_rate':
recommendations.push('Token rate below normal. May indicate early throttling.');
break;
case 'fingerprint':
recommendations.push('Minor structural drift detected. May be normal variation.');
break;
}
}
}
return recommendations;
}
/**
* Aggregates engine results into a health report.
*
* @param results - Array of engine results to aggregate
* @param weights - Optional custom weights for each metric
* @returns Comprehensive health report
*
* @example
* const results = [latencyResult, tokenRateResult, fingerprintResult];
* const report = HealthScoreEngine(results);
*
* if (report.health === 'unstable') {
* alert('LLM health critical!');
* }
*/
function HealthScoreEngine(results, weights) {
const effectiveWeights = { ...DEFAULT_WEIGHTS, ...weights };
// Calculate weighted score
let score = 0;
let totalWeight = 0;
for (const result of results) {
const weight = effectiveWeights[result.metric] || 0.1;
score += result.value * weight;
totalWeight += weight;
}
// Normalize score
score = totalWeight > 0 ? Math.min(1, score / totalWeight * Object.keys(effectiveWeights).length / results.length) : 0;
score = Math.min(1, score);
// Determine health status
let health;
if (score <= 0.25) {
health = 'stable';
}
else if (score <= 0.5) {
health = 'minor_variation';
}
else if (score <= 0.75) {
health = 'degraded';
}
else {
health = 'unstable';
}
// Check for any critical errors that should override
const hasError = results.some(r => r.status === 'error');
if (hasError && health === 'stable') {
health = 'minor_variation';
}
// Generate recommendations
const recommendations = generateRecommendations(results);
return {
health,
score: Math.round(score * 100) / 100,
engineResults: results,
timestamp: Date.now(),
recommendations: recommendations.length > 0 ? recommendations : undefined
};
}
/**
* Quick health check - returns true if healthy.
*/
function isHealthy(report) {
return report.health === 'stable' || report.health === 'minor_variation';
}
/**
* Gets severity level for alerting.
*/
function getAlertLevel(report) {
switch (report.health) {
case 'stable':
return 'none';
case 'minor_variation':
return 'info';
case 'degraded':
return 'warning';
case 'unstable':
return 'critical';
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhbHRoLXNjb3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VuZ2luZXMvcnVudGltZS9oZWFsdGgtc2NvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRzs7QUEwRUgsOENBZ0RDO0FBS0QsOEJBRUM7QUFLRCxzQ0FXQztBQTdJRDs7O0dBR0c7QUFDSCxNQUFNLGVBQWUsR0FBMkI7SUFDOUMsV0FBVyxFQUFFLElBQUk7SUFDakIsU0FBUyxFQUFFLElBQUk7SUFDZixPQUFPLEVBQUUsSUFBSTtJQUNiLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLFdBQVcsRUFBRSxJQUFJO0NBQ2xCLENBQUM7QUFFRjs7R0FFRztBQUNILFNBQVMsdUJBQXVCLENBQUMsT0FBdUI7SUFDdEQsTUFBTSxlQUFlLEdBQWEsRUFBRSxDQUFDO0lBRXJDLEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7UUFDN0IsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQzlCLFFBQVEsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUN0QixLQUFLLFNBQVM7b0JBQ1osZUFBZSxDQUFDLElBQUksQ0FBQyx1RkFBdUYsQ0FBQyxDQUFDO29CQUM5RyxNQUFNO2dCQUNSLEtBQUssWUFBWTtvQkFDZixlQUFlLENBQUMsSUFBSSxDQUFDLDZFQUE2RSxDQUFDLENBQUM7b0JBQ3BHLE1BQU07Z0JBQ1IsS0FBSyxhQUFhO29CQUNoQixlQUFlLENBQUMsSUFBSSxDQUFDLHNFQUFzRSxDQUFDLENBQUM7b0JBQzdGLE1BQU07Z0JBQ1IsS0FBSyxXQUFXO29CQUNkLGVBQWUsQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQUMsQ0FBQztvQkFDOUYsTUFBTTtnQkFDUixLQUFLLGFBQWE7b0JBQ2hCLGVBQWUsQ0FBQyxJQUFJLENBQUMseUVBQXlFLENBQUMsQ0FBQztvQkFDaEcsTUFB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LENBQUMsU0FBUztLQUMxRSxDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsU0FBUyxDQUFDLE1BQW9CO0lBQzVDLE9BQU8sTUFBTSxDQUFDLE1BQU0sS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxpQkFBaUIsQ0FBQztBQUMzRSxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixhQUFhLENBQUMsTUFBb0I7SUFDaEQsUUFBUSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDdEIsS0FBSyxRQUFRO1lBQ1gsT0FBTyxNQUFNLENBQUM7UUFDaEIsS0FBSyxpQkFBaUI7WUFDcEIsT0FBTyxNQUFNLENBQUM7UUFDaEIsS0FBSyxVQUFVO1lBQ2IsT0FBTyxTQUFTLENBQUM7UUFDbkIsS0FBSyxVQUFVO1lBQ2IsT0FBTyxVQUFVLENBQUM7SUFDdEIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEhlYWx0aCBTY29yZSBFbmdpbmVcbiAqIFxuICogQWdncmVnYXRlcyBlbmdpbmUgcmVzdWx0cyBpbnRvIGEgY29tcG9zaXRlIGhlYWx0aCBzY29yZS5cbiAqIFByb3ZpZGVzIGFjdGlvbmFibGUgaGVhbHRoIHN0YXR1cyBhbmQgcmVjb21tZW5kYXRpb25zLlxuICogXG4gKiBXSEFUIFRISVMgRE9FUzpcbiAqIOKchSBDb21iaW5lcyBtdWx0aXBsZSBlbmdpbmUgcmVzdWx0c1xuICog4pyFIENhbGN1bGF0ZXMgd2VpZ2h0ZWQgaGVhbHRoIHNjb3JlXG4gKiDinIUgUHJvdmlkZXMgYWN0aW9uYWJsZSBzdGF0dXMgbGV2ZWxzXG4gKiDinIUgR2VuZXJhdGVzIHJlY29tbWVuZGF0aW9uc1xuICogXG4gKiBXSEFUIFRISVMgRE9FUyBOT1QgRE86XG4gKiDinYwgUHJlZGljdCBmdXR1cmUgaGVhbHRoXG4gKiDinYwgSWRlbnRpZnkgcm9vdCBjYXVzZXNcbiAqIOKdjCBHdWFyYW50ZWUgYWNjdXJhY3kgb2YgaW5kaXZpZHVhbCBlbmdpbmVzXG4gKiBcbiAqIEBtb2R1bGUgZW5naW5lcy9ydW50aW1lL2hlYWx0aC1zY29yZVxuICogQGF1dGhvciBIYWllY1xuICogQGxpY2Vuc2UgTUlUXG4gKi9cblxuaW1wb3J0IHsgRW5naW5lUmVzdWx0LCBIZWFsdGhSZXBvcnQsIEhlYWx0aFN0YXR1cyB9IGZyb20gJy4uLy4uL3R5cGVzL3J1bnRpbWUnO1xuXG4vKipcbiAqIERlZmF1bHQgd2VpZ2h0cyBmb3IgZWFjaCBtZXRyaWMuXG4gKiBDb25zaXN0ZW5jeSBhbmQgbGF0ZW5jeSBhcmUgd2VpZ2h0ZWQgaGlnaGVyIGFzIHRoZXkncmUgbW9zdCBpbXBhY3RmdWwuXG4gKi9cbmNvbnN0IERFRkFVTFRfV0VJR0hUUzogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHtcbiAgY29uc2lzdGVuY3k6IDAuMjUsXG4gIHN0cnVjdHVyZTogMC4xNSxcbiAgbGF0ZW5jeTogMC4yNSxcbiAgdG9rZW5fcmF0ZTogMC4xNSxcbiAgZmluZ2VycHJpbnQ6IDAuMjBcbn07XG5cbi8qKlxuICogR2VuZXJhdGVzIHJlY29tbWVuZGF0aW9ucyBiYXNlZCBvbiBlbmdpbmUgcmVzdWx0cy5cbiAqL1xuZnVuY3Rpb24gZ2VuZXJhdGVSZWNvbW1lbmRhdGlvbnMocmVzdWx0czogRW5naW5lUmVzdWx0W10pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHJlY29tbWVuZGF0aW9uczogc3RyaW5nW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09ICdlcnJvcicpIHtcbiAgICAgIHN3aXRjaCAocmVzdWx0Lm1ldHJpYykge1xuICAgICAgICBjYXNlICdsYXRlbmN5JzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnSGlnaCBsYXRlbmN5IGRldGVjdGVkLiBDb25zaWRlciBjaGVja2luZyBwcm92aWRlciBzdGF0dXMgb3IgaW1wbGVtZW50aW5nIHJldHJ5IGxvZ2ljLicpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICd0b2tlbl9yYXRlJzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnTG93IHRva2VuIHJhdGUgZGV0ZWN0ZWQuIFByb3ZpZGVyIG1heSBiZSB0aHJvdHRsaW5nIG9yIGV4cGVyaWVuY2luZyBpc3N1ZXMuJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2ZpbmdlcnByaW50JzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnUmVzcG9uc2Ugc3RydWN0dXJlIGhhcyBjaGFuZ2VkIHNpZ25pZmljYW50bHkuIFZlcmlmeSBtb2RlbCBiZWhhdmlvci4nKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnc3RydWN0dXJlJzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnU3RydWN0dXJhbCBhbm9tYWxpZXMgZGV0ZWN0ZWQuIENoZWNrIGZvciB0cnVuY2F0aW9uIG9yIGZvcm1hdCBpc3N1ZXMuJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2NvbnNpc3RlbmN5JzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnUmVzcG9uc2UgY29uc2lzdGVuY3kgaXNzdWVzIGRldGVjdGVkLiBDb25zaWRlciBpbXBsZW1lbnRpbmcgdmFsaWRhdGlvbi4nKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJlc3VsdC5zdGF0dXMgPT09ICd3YXJuJykge1xuICAgICAgc3dpdGNoIChyZXN1bHQubWV0cmljKSB7XG4gICAgICAgIGNhc2UgJ2xhdGVuY3knOlxuICAgICAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKCdMYXRlbmN5IHNsaWdodGx5IGVsZXZhdGVkLiBNb25pdG9yIGZvciB0cmVuZHMuJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ3Rva2VuX3JhdGUnOlxuICAgICAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKCdUb2tlbiByYXRlIGJlbG93IG5vcm1hbC4gTWF5IGluZGljYXRlIGVhcmx5IHRocm90dGxpbmcuJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2ZpbmdlcnByaW50JzpcbiAgICAgICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnTWlub3Igc3RydWN0dXJhbCBkcmlmdCBkZXRlY3RlZC4gTWF5IGJlIG5vcm1hbCB2YXJpYXRpb24uJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHJlY29tbWVuZGF0aW9ucztcbn1cblxuLyoqXG4gKiBBZ2dyZWdhdGVzIGVuZ2luZSByZXN1bHRzIGludG8gYSBoZWFsdGggcmVwb3J0LlxuICogXG4gKiBAcGFyYW0gcmVzdWx0cyAtIEFycmF5IG9mIGVuZ2luZSByZXN1bHRzIHRvIGFnZ3JlZ2F0ZVxuICogQHBhcmFtIHdlaWdodHMgLSBPcHRpb25hbCBjdXN0b20gd2VpZ2h0cyBmb3IgZWFjaCBtZXRyaWNcbiAqIEByZXR1cm5zIENvbXByZWhlbnNpdmUgaGVhbHRoIHJlcG9ydFxuICogXG4gKiBAZXhhbXBsZVxuICogY29uc3QgcmVzdWx0cyA9IFtsYXRlbmN5UmVzdWx0LCB0b2tlblJhdGVSZXN1bHQsIGZpbmdlcnByaW50UmVzdWx0XTtcbiAqIGNvbnN0IHJlcG9ydCA9IEhlYWx0aFNjb3JlRW5naW5lKHJlc3VsdHMpO1xuICogXG4gKiBpZiAocmVwb3J0LmhlYWx0aCA9PT0gJ3Vuc3RhYmxlJykge1xuICogICBhbGVydCgnTExNIGhlYWx0aCBjcml0aWNhbCEnKTtcbiAqIH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEhlYWx0aFNjb3JlRW5naW5lKFxuICByZXN1bHRzOiBFbmdpbmVSZXN1bHRbXSxcbiAgd2VpZ2h0cz86IFJlY29yZDxzdHJpbmcsIG51bWJlcj5cbik6IEhlYWx0aFJlcG9ydCB7XG4gIGNvbnN0IGVmZmVjdGl2ZVdlaWdodHMgPSB7IC4uLkRFRkFVTFRfV0VJR0hUUywgLi4ud2VpZ2h0cyB9O1xuXG4gIC8vIENhbGN1bGF0ZSB3ZWlnaHRlZCBzY29yZVxuICBsZXQgc2NvcmUgPSAwO1xuICBsZXQgdG90YWxXZWlnaHQgPSAwO1xuXG4gIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICBjb25zdCB3ZWlnaHQgPSBlZmZlY3RpdmVXZWlnaHRzW3Jlc3VsdC5tZXRyaWNdIHx8IDAuMTtcbiAgICBzY29yZSArPSByZXN1bHQudmFsdWUgKiB3ZWlnaHQ7XG4gICAgdG90YWxXZWlnaHQgKz0gd2VpZ2h0O1xuICB9XG5cbiAgLy8gTm9ybWFsaXplIHNjb3JlXG4gIHNjb3JlID0gdG90YWxXZWlnaHQgPiAwID8gTWF0aC5taW4oMSwgc2NvcmUgLyB0b3RhbFdlaWdodCAqIE9iamVjdC5rZXlzKGVmZmVjdGl2ZVdlaWdodHMpLmxlbmd0aCAvIHJlc3VsdHMubGVuZ3RoKSA6IDA7XG4gIHNjb3JlID0gTWF0aC5taW4oMSwgc2NvcmUpO1xuXG4gIC8vIERldGVybWluZSBoZWFsdGggc3RhdHVzXG4gIGxldCBoZWFsdGg6IEhlYWx0aFN0YXR1cztcbiAgaWYgKHNjb3JlIDw9IDAuMjUpIHtcbiAgICBoZWFsdGggPSAnc3RhYmxlJztcbiAgfSBlbHNlIGlmIChzY29yZSA8PSAwLjUpIHtcbiAgICBoZWFsdGggPSAnbWlub3JfdmFyaWF0aW9uJztcbiAgfSBlbHNlIGlmIChzY29yZSA8PSAwLjc1KSB7XG4gICAgaGVhbHRoID0gJ2RlZ3JhZGVkJztcbiAgfSBlbHNlIHtcbiAgICBoZWFsdGggPSAndW5zdGFibGUnO1xuICB9XG5cbiAgLy8gQ2hlY2sgZm9yIGFueSBjcml0aWNhbCBlcnJvcnMgdGhhdCBzaG91bGQgb3ZlcnJpZGVcbiAgY29uc3QgaGFzRXJyb3IgPSByZXN1bHRzLnNvbWUociA9PiByLnN0YXR1cyA9PT0gJ2Vycm9yJyk7XG4gIGlmIChoYXNFcnJvciAmJiBoZWFsdGggPT09ICdzdGFibGUnKSB7XG4gICAgaGVhbHRoID0gJ21pbm9yX3ZhcmlhdGlvbic7XG4gIH1cblxuICAvLyBHZW5lcmF0ZSByZWNvbW1lbmRhdGlvbnNcbiAgY29uc3QgcmVjb21tZW5kYXRpb25zID0gZ2VuZXJhdGVSZWNvbW1lbmRhdGlvbnMocmVzdWx0cyk7XG5cbiAgcmV0dXJuIHtcbiAgICBoZWFsdGgsXG4gICAgc2NvcmU6IE1hdGgucm91bmQoc2NvcmUgKiAxMDApIC8gMTAwLFxuICAgIGVuZ2luZVJlc3VsdHM6IHJlc3VsdHMsXG4gICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgIHJlY29tbWVuZGF0aW9uczogcmVjb21tZW5kYXRpb25zLmxlbmd0aCA+IDAgPyByZWNvbW1lbmRhdGlvbnMgOiB1bmRlZmluZWRcbiAgfTtcbn1cblxuLyoqXG4gKiBRdWljayBoZWFsdGggY2hlY2sgLSByZXR1cm5zIHRydWUgaWYgaGVhbHRoeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSGVhbHRoeShyZXBvcnQ6IEhlYWx0aFJlcG9ydCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVwb3J0LmhlYWx0aCA9PT0gJ3N0YWJsZScgfHwgcmVwb3J0LmhlYWx0aCA9PT0gJ21pbm9yX3ZhcmlhdGlvbic7XG59XG5cbi8qKlxuICogR2V0cyBzZXZlcml0eSBsZXZlbCBmb3IgYWxlcnRpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGVydExldmVsKHJlcG9ydDogSGVhbHRoUmVwb3J0KTogJ25vbmUnIHwgJ2luZm8nIHwgJ3dhcm5pbmcnIHwgJ2NyaXRpY2FsJyB7XG4gIHN3aXRjaCAocmVwb3J0LmhlYWx0aCkge1xuICAgIGNhc2UgJ3N0YWJsZSc6XG4gICAgICByZXR1cm4gJ25vbmUnO1xuICAgIGNhc2UgJ21pbm9yX3ZhcmlhdGlvbic6XG4gICAgICByZXR1cm4gJ2luZm8nO1xuICAgIGNhc2UgJ2RlZ3JhZGVkJzpcbiAgICAgIHJldHVybiAnd2FybmluZyc7XG4gICAgY2FzZSAndW5zdGFibGUnOlxuICAgICAgcmV0dXJuICdjcml0aWNhbCc7XG4gIH1cbn1cbiJdfQ==