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.

154 lines 16.5 kB
"use strict"; /** * Classification Engine Utilities * * Shared helper functions for classification. * * @module engines/classification/utils * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.STOPWORDS = void 0; exports.clamp = clamp; exports.computeEntropy = computeEntropy; exports.tokenize = tokenize; exports.countSentences = countSentences; exports.countBullets = countBullets; exports.extractCapitalizedTokens = extractCapitalizedTokens; exports.computeWordFrequency = computeWordFrequency; exports.getMaxWordFrequency = getMaxWordFrequency; exports.containsAny = containsAny; exports.countMatches = countMatches; /** * Clamps a value between min and max. */ function clamp(value, min, max) { return Math.min(max, Math.max(min, value)); } /** * Computes Shannon entropy of text. */ function computeEntropy(text) { if (!text || text.length === 0) return 0; const freq = {}; for (const ch of text) { freq[ch] = (freq[ch] || 0) + 1; } const len = text.length; let entropy = 0; for (const ch in freq) { const p = freq[ch] / len; entropy -= p * Math.log2(p); } return entropy; } /** * Tokenizes text into words. */ function tokenize(text) { return text.split(/\s+/).filter(w => w.length > 0); } /** * Counts sentences in text. */ function countSentences(text) { const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0); return sentences.length; } /** * Counts bullet points/list items in text. */ function countBullets(text) { const patterns = [ /^[-*•]\s+/gm, // Bullet points /^\d+[.)]\s+/gm, // Numbered lists /^[a-z][.)]\s+/gim // Lettered lists ]; let count = 0; for (const pattern of patterns) { const matches = text.match(pattern); if (matches) count += matches.length; } return count; } /** * Common English stopwords. */ exports.STOPWORDS = new Set([ 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'were', 'been', 'be', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'need', 'dare', 'ought', 'used', 'it', 'its', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'we', 'they', 'what', 'which', 'who', 'whom', 'when', 'where', 'why', 'how', 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 'just', 'also', 'now', 'here', 'there', 'then' ]); /** * Extracts capitalized tokens (potential entities). */ function extractCapitalizedTokens(text) { const tokens = new Set(); const words = text.split(/\s+/); for (let i = 0; i < words.length; i++) { const word = words[i].replace(/[^a-zA-Z]/g, ''); if (word.length > 1 && /^[A-Z]/.test(word)) { // Skip if at sentence start (after . ! ?) if (i > 0) { const prev = words[i - 1]; if (!/[.!?]$/.test(prev)) { const lower = word.toLowerCase(); if (!exports.STOPWORDS.has(lower)) { tokens.add(word); } } } } } return tokens; } /** * Computes word frequency excluding stopwords. */ function computeWordFrequency(text) { const freq = new Map(); const words = tokenize(text.toLowerCase()); for (const word of words) { const clean = word.replace(/[^a-z]/g, ''); if (clean.length > 2 && !exports.STOPWORDS.has(clean)) { freq.set(clean, (freq.get(clean) || 0) + 1); } } return freq; } /** * Gets the most frequent word count. */ function getMaxWordFrequency(text) { const freq = computeWordFrequency(text); let max = 0; for (const count of freq.values()) { if (count > max) max = count; } return max; } /** * Checks if text contains any of the patterns (case-insensitive). */ function containsAny(text, patterns) { const lower = text.toLowerCase(); return patterns.some(p => lower.includes(p.toLowerCase())); } /** * Counts how many patterns are found in text. */ function countMatches(text, patterns) { const lower = text.toLowerCase(); return patterns.filter(p => lower.includes(p.toLowerCase())).length; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9jbGFzc2lmaWNhdGlvbi91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7OztBQUtILHNCQUVDO0FBS0Qsd0NBZ0JDO0FBS0QsNEJBRUM7QUFLRCx3Q0FHQztBQUtELG9DQWNDO0FBb0JELDREQXFCQztBQUtELG9EQVlDO0FBS0Qsa0RBT0M7QUFLRCxrQ0FHQztBQUtELG9DQUdDO0FBbEpEOztHQUVHO0FBQ0gsU0FBZ0IsS0FBSyxDQUFDLEtBQWEsRUFBRSxHQUFXLEVBQUUsR0FBVztJQUMzRCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDN0MsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLElBQVk7SUFDekMsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQztJQUV6QyxNQUFNLElBQUksR0FBMkIsRUFBRSxDQUFDO0lBQ3hDLEtBQUssTUFBTSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUN4QixJQUFJLE9BQU8sR0FBRyxDQUFDLENBQUM7SUFDaEIsS0FBSyxNQUFNLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN0QixNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLEdBQUcsSUFBSSxD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QUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7QUFDdEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2xhc3NpZmljYXRpb24gRW5naW5lIFV0aWxpdGllc1xuICogXG4gKiBTaGFyZWQgaGVscGVyIGZ1bmN0aW9ucyBmb3IgY2xhc3NpZmljYXRpb24uXG4gKiBcbiAqIEBtb2R1bGUgZW5naW5lcy9jbGFzc2lmaWNhdGlvbi91dGlsc1xuICogQGF1dGhvciBIYWllY1xuICogQGxpY2Vuc2UgTUlUXG4gKi9cblxuLyoqXG4gKiBDbGFtcHMgYSB2YWx1ZSBiZXR3ZWVuIG1pbiBhbmQgbWF4LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xhbXAodmFsdWU6IG51bWJlciwgbWluOiBudW1iZXIsIG1heDogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIE1hdGgubWluKG1heCwgTWF0aC5tYXgobWluLCB2YWx1ZSkpO1xufVxuXG4vKipcbiAqIENvbXB1dGVzIFNoYW5ub24gZW50cm9weSBvZiB0ZXh0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZUVudHJvcHkodGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgaWYgKCF0ZXh0IHx8IHRleHQubGVuZ3RoID09PSAwKSByZXR1cm4gMDtcbiAgXG4gIGNvbnN0IGZyZXE6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgZm9yIChjb25zdCBjaCBvZiB0ZXh0KSB7XG4gICAgZnJlcVtjaF0gPSAoZnJlcVtjaF0gfHwgMCkgKyAxO1xuICB9XG4gIFxuICBjb25zdCBsZW4gPSB0ZXh0Lmxlbmd0aDtcbiAgbGV0IGVudHJvcHkgPSAwO1xuICBmb3IgKGNvbnN0IGNoIGluIGZyZXEpIHtcbiAgICBjb25zdCBwID0gZnJlcVtjaF0gLyBsZW47XG4gICAgZW50cm9weSAtPSBwICogTWF0aC5sb2cyKHApO1xuICB9XG4gIFxuICByZXR1cm4gZW50cm9weTtcbn1cblxuLyoqXG4gKiBUb2tlbml6ZXMgdGV4dCBpbnRvIHdvcmRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9rZW5pemUodGV4dDogc3RyaW5nKTogc3RyaW5nW10ge1xuICByZXR1cm4gdGV4dC5zcGxpdCgvXFxzKy8pLmZpbHRlcih3ID0+IHcubGVuZ3RoID4gMCk7XG59XG5cbi8qKlxuICogQ291bnRzIHNlbnRlbmNlcyBpbiB0ZXh0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY291bnRTZW50ZW5jZXModGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgY29uc3Qgc2VudGVuY2VzID0gdGV4dC5zcGxpdCgvWy4hP10rLykuZmlsdGVyKHMgPT4gcy50cmltKCkubGVuZ3RoID4gMCk7XG4gIHJldHVybiBzZW50ZW5jZXMubGVuZ3RoO1xufVxuXG4vKipcbiAqIENvdW50cyBidWxsZXQgcG9pbnRzL2xpc3QgaXRlbXMgaW4gdGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50QnVsbGV0cyh0ZXh0OiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCBwYXR0ZXJucyA9IFtcbiAgICAvXlstKuKAol1cXHMrL2dtLCAgICAgICAgICAgLy8gQnVsbGV0IHBvaW50c1xuICAgIC9eXFxkK1suKV1cXHMrL2dtLCAgICAgICAgIC8vIE51bWJlcmVkIGxpc3RzXG4gICAgL15bYS16XVsuKV1cXHMrL2dpbSAgICAgICAvLyBMZXR0ZXJlZCBsaXN0c1xuICBdO1xuICBcbiAgbGV0IGNvdW50ID0gMDtcbiAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIHBhdHRlcm5zKSB7XG4gICAgY29uc3QgbWF0Y2hlcyA9IHRleHQubWF0Y2gocGF0dGVybik7XG4gICAgaWYgKG1hdGNoZXMpIGNvdW50ICs9IG1hdGNoZXMubGVuZ3RoO1xuICB9XG4gIFxuICByZXR1cm4gY291bnQ7XG59XG5cbi8qKlxuICogQ29tbW9uIEVuZ2xpc2ggc3RvcHdvcmRzLlxuICovXG5leHBvcnQgY29uc3QgU1RPUFdPUkRTID0gbmV3IFNldChbXG4gICd0aGUnLCAnYScsICdhbicsICdhbmQnLCAnb3InLCAnYnV0JywgJ2luJywgJ29uJywgJ2F0JywgJ3RvJywgJ2ZvcicsXG4gICdvZicsICd3aXRoJywgJ2J5JywgJ2Zyb20nLCAnYXMnLCAnaXMnLCAnd2FzJywgJ2FyZScsICd3ZXJlJywgJ2JlZW4nLFxuICAnYmUnLCAnaGF2ZScsICdoYXMnLCAnaGFkJywgJ2RvJywgJ2RvZXMnLCAnZGlkJywgJ3dpbGwnLCAnd291bGQnLCAnY291bGQnLFxuICAnc2hvdWxkJywgJ21heScsICdtaWdodCcsICdtdXN0JywgJ3NoYWxsJywgJ2NhbicsICduZWVkJywgJ2RhcmUnLCAnb3VnaHQnLFxuICAndXNlZCcsICdpdCcsICdpdHMnLCAndGhpcycsICd0aGF0JywgJ3RoZXNlJywgJ3Rob3NlJywgJ2knLCAneW91JywgJ2hlJyxcbiAgJ3NoZScsICd3ZScsICd0aGV5JywgJ3doYXQnLCAnd2hpY2gnLCAnd2hvJywgJ3dob20nLCAnd2hlbicsICd3aGVyZScsXG4gICd3aHknLCAnaG93JywgJ2FsbCcsICdlYWNoJywgJ2V2ZXJ5JywgJ2JvdGgnLCAnZmV3JywgJ21vcmUnLCAnbW9zdCcsXG4gICdvdGhlcicsICdzb21lJywgJ3N1Y2gnLCAnbm8nLCAnbm9yJywgJ25vdCcsICdvbmx5JywgJ293bicsICdzYW1lJywgJ3NvJyxcbiAgJ3RoYW4nLCAndG9vJywgJ3ZlcnknLCAnanVzdCcsICdhbHNvJywgJ25vdycsICdoZXJlJywgJ3RoZXJlJywgJ3RoZW4nXG5dKTtcblxuLyoqXG4gKiBFeHRyYWN0cyBjYXBpdGFsaXplZCB0b2tlbnMgKHBvdGVudGlhbCBlbnRpdGllcykuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0Q2FwaXRhbGl6ZWRUb2tlbnModGV4dDogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICBjb25zdCB0b2tlbnMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3Qgd29yZHMgPSB0ZXh0LnNwbGl0KC9cXHMrLyk7XG4gIFxuICBmb3IgKGxldCBpID0gMDsgaSA8IHdvcmRzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qgd29yZCA9IHdvcmRzW2ldLnJlcGxhY2UoL1teYS16QS1aXS9nLCAnJyk7XG4gICAgaWYgKHdvcmQubGVuZ3RoID4gMSAmJiAvXltBLVpdLy50ZXN0KHdvcmQpKSB7XG4gICAgICAvLyBTa2lwIGlmIGF0IHNlbnRlbmNlIHN0YXJ0IChhZnRlciAuICEgPylcbiAgICAgIGlmIChpID4gMCkge1xuICAgICAgICBjb25zdCBwcmV2ID0gd29yZHNbaSAtIDFdO1xuICAgICAgICBpZiAoIS9bLiE/XSQvLnRlc3QocHJldikpIHtcbiAgICAgICAgICBjb25zdCBsb3dlciA9IHdvcmQudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBpZiAoIVNUT1BXT1JEUy5oYXMobG93ZXIpKSB7XG4gICAgICAgICAgICB0b2tlbnMuYWRkKHdvcmQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgcmV0dXJuIHRva2Vucztcbn1cblxuLyoqXG4gKiBDb21wdXRlcyB3b3JkIGZyZXF1ZW5jeSBleGNsdWRpbmcgc3RvcHdvcmRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVdvcmRGcmVxdWVuY3kodGV4dDogc3RyaW5nKTogTWFwPHN0cmluZywgbnVtYmVyPiB7XG4gIGNvbnN0IGZyZXEgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICBjb25zdCB3b3JkcyA9IHRva2VuaXplKHRleHQudG9Mb3dlckNhc2UoKSk7XG4gIFxuICBmb3IgKGNvbnN0IHdvcmQgb2Ygd29yZHMpIHtcbiAgICBjb25zdCBjbGVhbiA9IHdvcmQucmVwbGFjZSgvW15hLXpdL2csICcnKTtcbiAgICBpZiAoY2xlYW4ubGVuZ3RoID4gMiAmJiAhU1RPUFdPUkRTLmhhcyhjbGVhbikpIHtcbiAgICAgIGZyZXEuc2V0KGNsZWFuLCAoZnJlcS5nZXQoY2xlYW4pIHx8IDApICsgMSk7XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4gZnJlcTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBtb3N0IGZyZXF1ZW50IHdvcmQgY291bnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRNYXhXb3JkRnJlcXVlbmN5KHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGZyZXEgPSBjb21wdXRlV29yZEZyZXF1ZW5jeSh0ZXh0KTtcbiAgbGV0IG1heCA9IDA7XG4gIGZvciAoY29uc3QgY291bnQgb2YgZnJlcS52YWx1ZXMoKSkge1xuICAgIGlmIChjb3VudCA+IG1heCkgbWF4ID0gY291bnQ7XG4gIH1cbiAgcmV0dXJuIG1heDtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgdGV4dCBjb250YWlucyBhbnkgb2YgdGhlIHBhdHRlcm5zIChjYXNlLWluc2Vuc2l0aXZlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnRhaW5zQW55KHRleHQ6IHN0cmluZywgcGF0dGVybnM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gIGNvbnN0IGxvd2VyID0gdGV4dC50b0xvd2VyQ2FzZSgpO1xuICByZXR1cm4gcGF0dGVybnMuc29tZShwID0+IGxvd2VyLmluY2x1ZGVzKHAudG9Mb3dlckNhc2UoKSkpO1xufVxuXG4vKipcbiAqIENvdW50cyBob3cgbWFueSBwYXR0ZXJucyBhcmUgZm91bmQgaW4gdGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvdW50TWF0Y2hlcyh0ZXh0OiBzdHJpbmcsIHBhdHRlcm5zOiBzdHJpbmdbXSk6IG51bWJlciB7XG4gIGNvbnN0IGxvd2VyID0gdGV4dC50b0xvd2VyQ2FzZSgpO1xuICByZXR1cm4gcGF0dGVybnMuZmlsdGVyKHAgPT4gbG93ZXIuaW5jbHVkZXMocC50b0xvd2VyQ2FzZSgpKSkubGVuZ3RoO1xufVxuIl19