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.

111 lines 14.4 kB
"use strict"; /** * Hallucination Engine * * Identifies risk indicators in AI outputs. * Does NOT definitively detect hallucinations - that requires ground truth. * * @module engines/hallucination * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.HallucinationEngine = void 0; const claim_extractor_1 = require("./claim-extractor"); const risk_analyzer_1 = require("./risk-analyzer"); class HallucinationEngine { constructor(config) { this.config = config; this.LIMITATIONS = [ 'Pattern-based detection only (free tier)', 'Cannot verify factual accuracy without ground truth sources', 'English language only', 'Context-dependent false positives possible', 'Novel phrasings may not be detected', 'Requires human validation for production use' ]; this.METHODOLOGY = 'Risk indicator identification using linguistic pattern analysis. ' + 'Analyzes claim specificity, citation presence, language patterns, and ' + 'contradiction signals. Does NOT verify factual accuracy. ' + 'Results indicate likelihood that claims need human review.'; } async detect(content) { // Step 1: Extract claims let claims = (0, claim_extractor_1.extractClaims)(content); // Step 2: Analyze risk indicators for each claim claims = claims.map(claim => (0, risk_analyzer_1.analyzeRiskIndicators)(claim, this.config)); // Step 3: Check for contradictions claims = (0, risk_analyzer_1.checkContradictions)(claims); // Step 4: Identify suspicious claims const suspiciousClaims = claims.filter(claim => { const totalRisk = this.calculateClaimRisk(claim); return totalRisk > 0.5; }); // Step 5: Calculate overall risk score const riskScore = this.calculateRiskScore(claims); // Step 6: Calculate risk indicators summary const riskIndicators = this.summarizeRiskIndicators(claims); // Step 7: Calculate confidence const confidence = this.calculateConfidence(claims); return { claims, suspiciousClaims, riskScore, confidence, riskIndicators, limitations: this.LIMITATIONS, methodology: this.METHODOLOGY }; } calculateClaimRisk(claim) { return (claim.riskIndicators.lackOfSpecificity * 0.3 + (claim.riskIndicators.missingCitation ? 0.3 : 0) + (claim.riskIndicators.vagueLanguage ? 0.2 : 0) + (claim.riskIndicators.contradictionSignal ? 0.2 : 0)); } calculateRiskScore(claims) { if (claims.length === 0) return 0; const totalRisk = claims.reduce((sum, claim) => { return sum + this.calculateClaimRisk(claim); }, 0); return Math.min(totalRisk / claims.length, 1.0); } summarizeRiskIndicators(claims) { if (claims.length === 0) { return { lackOfSpecificity: 0, missingCitations: 0, vagueLanguage: 0, contradictionSignals: 0 }; } return { lackOfSpecificity: claims.reduce((sum, c) => sum + c.riskIndicators.lackOfSpecificity, 0) / claims.length, missingCitations: claims.filter(c => c.riskIndicators.missingCitation).length, vagueLanguage: claims.filter(c => c.riskIndicators.vagueLanguage).length, contradictionSignals: claims.filter(c => c.riskIndicators.contradictionSignal).length }; } calculateConfidence(claims) { const sampleSize = claims.length; const baseLine = Math.min(sampleSize / 10, 1.0); const value = sampleSize < 3 ? baseLine * 0.5 : baseLine; const margin = 0.2 * (1 - value); return { value: Math.max(0.3, value), interval: [ Math.max(0, value - margin), Math.min(1, value + margin) ], method: 'heuristic', factors: { patternStrength: value, contextClarity: value, historicalAccuracy: 0.7 } }; } } exports.HallucinationEngine = HallucinationEngine; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9oYWxsdWNpbmF0aW9uL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7O0dBU0c7OztBQUlILHVEQUFrRDtBQUNsRCxtREFBNkU7QUFFN0UsTUFBYSxtQkFBbUI7SUFnQjlCLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBZmpCLGdCQUFXLEdBQUc7WUFDN0IsMENBQTBDO1lBQzFDLDZEQUE2RDtZQUM3RCx1QkFBdUI7WUFDdkIsNENBQTRDO1lBQzVDLHFDQUFxQztZQUNyQyw4Q0FBOEM7U0FDL0MsQ0FBQztRQUVlLGdCQUFXLEdBQzFCLG1FQUFtRTtZQUNuRSx3RUFBd0U7WUFDeEUsMkRBQTJEO1lBQzNELDREQUE0RCxDQUFDO0lBRTFCLENBQUM7SUFFdEMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFlO1FBQzFCLHlCQUF5QjtRQUN6QixJQUFJLE1BQU0sR0FBRyxJQUFBLCtCQUFhLEVBQUMsT0FBTyxDQUFDLENBQUM7UUFFcEMsaURBQWlEO1FBQ2pELE1BQU0sR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQzFCLElBQUEscUNBQXFCLEVBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FDMUMsQ0FBQztRQUVGLG1DQUFtQztRQUNuQyxNQUFNLEdBQUcsSUFBQSxtQ0FBbUIsRUFBQyxNQUFNLENBQUMsQ0FBQztRQUVyQyxxQ0FBcUM7UUFDckMsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQzdDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqRCxPQUFPLFNBQVMsR0FBRyxHQUFHLENBQUM7UUFDekIsQ0FBQyxDQUFDLENBQUM7UUFFSCx1Q0FBdUM7UUFD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QUcsQ0FBQyxDQUFDO1FBRWhELE1BQU0sS0FBSyxHQUFHLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztRQUN6RCxNQUFNLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFFakMsT0FBTztZQUNMLEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUM7WUFDM0IsUUFBUSxFQUFFO2dCQUNSLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUM7YUFDNUI7WUFDRCxNQUFNLEVBQUUsV0FBVztZQUNuQixPQUFPLEVBQUU7Z0JBQ1AsZUFBZSxFQUFFLEtBQUs7Z0JBQ3RCLGNBQWMsRUFBRSxLQUFLO2dCQUNyQixrQkFBa0IsRUFBRSxHQUFHO2FBQ3hCO1NBQ0YsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQXRIRCxrREFzSEMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEhhbGx1Y2luYXRpb24gRW5naW5lXG4gKiBcbiAqIElkZW50aWZpZXMgcmlzayBpbmRpY2F0b3JzIGluIEFJIG91dHB1dHMuXG4gKiBEb2VzIE5PVCBkZWZpbml0aXZlbHkgZGV0ZWN0IGhhbGx1Y2luYXRpb25zIC0gdGhhdCByZXF1aXJlcyBncm91bmQgdHJ1dGguXG4gKiBcbiAqIEBtb2R1bGUgZW5naW5lcy9oYWxsdWNpbmF0aW9uXG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyBDb25maWcgfSBmcm9tICcuLi8uLi90eXBlcy9jb25maWcnO1xuaW1wb3J0IHsgSGFsbHVjaW5hdGlvblJlc3VsdCwgQ2xhaW0sIENvbmZpZGVuY2VTY29yZSB9IGZyb20gJy4uLy4uL3R5cGVzL3Jlc3VsdHMnO1xuaW1wb3J0IHsgZXh0cmFjdENsYWltcyB9IGZyb20gJy4vY2xhaW0tZXh0cmFjdG9yJztcbmltcG9ydCB7IGFuYWx5emVSaXNrSW5kaWNhdG9ycywgY2hlY2tDb250cmFkaWN0aW9ucyB9IGZyb20gJy4vcmlzay1hbmFseXplcic7XG5cbmV4cG9ydCBjbGFzcyBIYWxsdWNpbmF0aW9uRW5naW5lIHtcbiAgcHJpdmF0ZSByZWFkb25seSBMSU1JVEFUSU9OUyA9IFtcbiAgICAnUGF0dGVybi1iYXNlZCBkZXRlY3Rpb24gb25seSAoZnJlZSB0aWVyKScsXG4gICAgJ0Nhbm5vdCB2ZXJpZnkgZmFjdHVhbCBhY2N1cmFjeSB3aXRob3V0IGdyb3VuZCB0cnV0aCBzb3VyY2VzJyxcbiAgICAnRW5nbGlzaCBsYW5ndWFnZSBvbmx5JyxcbiAgICAnQ29udGV4dC1kZXBlbmRlbnQgZmFsc2UgcG9zaXRpdmVzIHBvc3NpYmxlJyxcbiAgICAnTm92ZWwgcGhyYXNpbmdzIG1heSBub3QgYmUgZGV0ZWN0ZWQnLFxuICAgICdSZXF1aXJlcyBodW1hbiB2YWxpZGF0aW9uIGZvciBwcm9kdWN0aW9uIHVzZSdcbiAgXTtcbiAgXG4gIHByaXZhdGUgcmVhZG9ubHkgTUVUSE9ET0xPR1kgPSBcbiAgICAnUmlzayBpbmRpY2F0b3IgaWRlbnRpZmljYXRpb24gdXNpbmcgbGluZ3Vpc3RpYyBwYXR0ZXJuIGFuYWx5c2lzLiAnICtcbiAgICAnQW5hbHl6ZXMgY2xhaW0gc3BlY2lmaWNpdHksIGNpdGF0aW9uIHByZXNlbmNlLCBsYW5ndWFnZSBwYXR0ZXJucywgYW5kICcgK1xuICAgICdjb250cmFkaWN0aW9uIHNpZ25hbHMuIERvZXMgTk9UIHZlcmlmeSBmYWN0dWFsIGFjY3VyYWN5LiAnICtcbiAgICAnUmVzdWx0cyBpbmRpY2F0ZSBsaWtlbGlob29kIHRoYXQgY2xhaW1zIG5lZWQgaHVtYW4gcmV2aWV3Lic7XG4gIFxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNvbmZpZzogQ29uZmlnKSB7fVxuICBcbiAgYXN5bmMgZGV0ZWN0KGNvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8SGFsbHVjaW5hdGlvblJlc3VsdD4ge1xuICAgIC8vIFN0ZXAgMTogRXh0cmFjdCBjbGFpbXNcbiAgICBsZXQgY2xhaW1zID0gZXh0cmFjdENsYWltcyhjb250ZW50KTtcbiAgICBcbiAgICAvLyBTdGVwIDI6IEFuYWx5emUgcmlzayBpbmRpY2F0b3JzIGZvciBlYWNoIGNsYWltXG4gICAgY2xhaW1zID0gY2xhaW1zLm1hcChjbGFpbSA9PiBcbiAgICAgIGFuYWx5emVSaXNrSW5kaWNhdG9ycyhjbGFpbSwgdGhpcy5jb25maWcpXG4gICAgKTtcbiAgICBcbiAgICAvLyBTdGVwIDM6IENoZWNrIGZvciBjb250cmFkaWN0aW9uc1xuICAgIGNsYWltcyA9IGNoZWNrQ29udHJhZGljdGlvbnMoY2xhaW1zKTtcbiAgICBcbiAgICAvLyBTdGVwIDQ6IElkZW50aWZ5IHN1c3BpY2lvdXMgY2xhaW1zXG4gICAgY29uc3Qgc3VzcGljaW91c0NsYWltcyA9IGNsYWltcy5maWx0ZXIoY2xhaW0gPT4ge1xuICAgICAgY29uc3QgdG90YWxSaXNrID0gdGhpcy5jYWxjdWxhdGVDbGFpbVJpc2soY2xhaW0pO1xuICAgICAgcmV0dXJuIHRvdGFsUmlzayA+IDAuNTtcbiAgICB9KTtcbiAgICBcbiAgICAvLyBTdGVwIDU6IENhbGN1bGF0ZSBvdmVyYWxsIHJpc2sgc2NvcmVcbiAgICBjb25zdCByaXNrU2NvcmUgPSB0aGlzLmNhbGN1bGF0ZVJpc2tTY29yZShjbGFpbXMpO1xuICAgIFxuICAgIC8vIFN0ZXAgNjogQ2FsY3VsYXRlIHJpc2sgaW5kaWNhdG9ycyBzdW1tYXJ5XG4gICAgY29uc3Qgcmlza0luZGljYXRvcnMgPSB0aGlzLnN1bW1hcml6ZVJpc2tJbmRpY2F0b3JzKGNsYWltcyk7XG4gICAgXG4gICAgLy8gU3RlcCA3OiBDYWxjdWxhdGUgY29uZmlkZW5jZVxuICAgIGNvbnN0IGNvbmZpZGVuY2UgPSB0aGlzLmNhbGN1bGF0ZUNvbmZpZGVuY2UoY2xhaW1zKTtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgY2xhaW1zLFxuICAgICAgc3VzcGljaW91c0NsYWltcyxcbiAgICAgIHJpc2tTY29yZSxcbiAgICAgIGNvbmZpZGVuY2UsXG4gICAgICByaXNrSW5kaWNhdG9ycyxcbiAgICAgIGxpbWl0YXRpb25zOiB0aGlzLkxJTUlUQVRJT05TLFxuICAgICAgbWV0aG9kb2xvZ3k6IHRoaXMuTUVUSE9ET0xPR1lcbiAgICB9O1xuICB9XG4gIFxuICBwcml2YXRlIGNhbGN1bGF0ZUNsYWltUmlzayhjbGFpbTogQ2xhaW0pOiBudW1iZXIge1xuICAgIHJldHVybiAoXG4gICAgICBjbGFpbS5yaXNrSW5kaWNhdG9ycy5sYWNrT2ZTcGVjaWZpY2l0eSAqIDAuMyArXG4gICAgICAoY2xhaW0ucmlza0luZGljYXRvcnMubWlzc2luZ0NpdGF0aW9uID8gMC4zIDogMCkgK1xuICAgICAgKGNsYWltLnJpc2tJbmRpY2F0b3JzLnZhZ3VlTGFuZ3VhZ2UgPyAwLjIgOiAwKSArXG4gICAgICAoY2xhaW0ucmlza0luZGljYXRvcnMuY29udHJhZGljdGlvblNpZ25hbCA/IDAuMiA6IDApXG4gICAgKTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBjYWxjdWxhdGVSaXNrU2NvcmUoY2xhaW1zOiBDbGFpbVtdKTogbnVtYmVyIHtcbiAgICBpZiAoY2xhaW1zLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDA7XG4gICAgXG4gICAgY29uc3QgdG90YWxSaXNrID0gY2xhaW1zLnJlZHVjZSgoc3VtLCBjbGFpbSkgPT4ge1xuICAgICAgcmV0dXJuIHN1bSArIHRoaXMuY2FsY3VsYXRlQ2xhaW1SaXNrKGNsYWltKTtcbiAgICB9LCAwKTtcbiAgICBcbiAgICByZXR1cm4gTWF0aC5taW4odG90YWxSaXNrIC8gY2xhaW1zLmxlbmd0aCwgMS4wKTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBzdW1tYXJpemVSaXNrSW5kaWNhdG9ycyhjbGFpbXM6IENsYWltW10pIHtcbiAgICBpZiAoY2xhaW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbGFja09mU3BlY2lmaWNpdHk6IDAsXG4gICAgICAgIG1pc3NpbmdDaXRhdGlvbnM6IDAsXG4gICAgICAgIHZhZ3VlTGFuZ3VhZ2U6IDAsXG4gICAgICAgIGNvbnRyYWRpY3Rpb25TaWduYWxzOiAwXG4gICAgICB9O1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgbGFja09mU3BlY2lmaWNpdHk6IGNsYWltcy5yZWR1Y2UoKHN1bSwgYykgPT4gXG4gICAgICAgIHN1bSArIGMucmlza0luZGljYXRvcnMubGFja09mU3BlY2lmaWNpdHksIDApIC8gY2xhaW1zLmxlbmd0aCxcbiAgICAgIG1pc3NpbmdDaXRhdGlvbnM6IGNsYWltcy5maWx0ZXIoYyA9PiBcbiAgICAgICAgYy5yaXNrSW5kaWNhdG9ycy5taXNzaW5nQ2l0YXRpb24pLmxlbmd0aCxcbiAgICAgIHZhZ3VlTGFuZ3VhZ2U6IGNsYWltcy5maWx0ZXIoYyA9PiBcbiAgICAgICAgYy5yaXNrSW5kaWNhdG9ycy52YWd1ZUxhbmd1YWdlKS5sZW5ndGgsXG4gICAgICBjb250cmFkaWN0aW9uU2lnbmFsczogY2xhaW1zLmZpbHRlcihjID0+IFxuICAgICAgICBjLnJpc2tJbmRpY2F0b3JzLmNvbnRyYWRpY3Rpb25TaWduYWwpLmxlbmd0aFxuICAgIH07XG4gIH1cbiAgXG4gIHByaXZhdGUgY2FsY3VsYXRlQ29uZmlkZW5jZShjbGFpbXM6IENsYWltW10pOiBDb25maWRlbmNlU2NvcmUge1xuICAgIGNvbnN0IHNhbXBsZVNpemUgPSBjbGFpbXMubGVuZ3RoO1xuICAgIGNvbnN0IGJhc2VMaW5lID0gTWF0aC5taW4oc2FtcGxlU2l6ZSAvIDEwLCAxLjApO1xuICAgIFxuICAgIGNvbnN0IHZhbHVlID0gc2FtcGxlU2l6ZSA8IDMgPyBiYXNlTGluZSAqIDAuNSA6IGJhc2VMaW5lO1xuICAgIGNvbnN0IG1hcmdpbiA9IDAuMiAqICgxIC0gdmFsdWUpO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICB2YWx1ZTogTWF0aC5tYXgoMC4zLCB2YWx1ZSksXG4gICAgICBpbnRlcnZhbDogW1xuICAgICAgICBNYXRoLm1heCgwLCB2YWx1ZSAtIG1hcmdpbiksXG4gICAgICAgIE1hdGgubWluKDEsIHZhbHVlICsgbWFyZ2luKVxuICAgICAgXSxcbiAgICAgIG1ldGhvZDogJ2hldXJpc3RpYycsXG4gICAgICBmYWN0b3JzOiB7XG4gICAgICAgIHBhdHRlcm5TdHJlbmd0aDogdmFsdWUsXG4gICAgICAgIGNvbnRleHRDbGFyaXR5OiB2YWx1ZSxcbiAgICAgICAgaGlzdG9yaWNhbEFjY3VyYWN5OiAwLjdcbiAgICAgIH1cbiAgICB9O1xuICB9XG59XG4iXX0=