llm-entropy-filter 1.1.0 → 1.2.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/CHANGELOG.md +155 -51
- package/LICENSE +93 -93
- package/README.md +297 -352
- package/dist/index.cjs +104 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +104 -70
- package/dist/index.js.map +1 -1
- package/integrations/express.mjs +117 -117
- package/integrations/fastify.mjs +106 -106
- package/integrations/langchain.mjs +98 -98
- package/integrations/vercel-ai-sdk.mjs +44 -44
- package/package.json +99 -59
- package/rulesets/default.js +8 -0
- package/rulesets/default.json +77 -73
- package/rulesets/public-api.js +7 -0
- package/rulesets/public-api.json +179 -27
- package/rulesets/schema +24 -24
- package/rulesets/strict.js +7 -0
- package/rulesets/strict.json +173 -25
- package/rulesets/support.js +7 -0
- package/rulesets/support.json +22 -22
package/dist/index.cjs
CHANGED
|
@@ -42,18 +42,48 @@ function analyzeEntropy(text) {
|
|
|
42
42
|
const t = raw.toLowerCase();
|
|
43
43
|
const flags = [];
|
|
44
44
|
let score = 0;
|
|
45
|
-
if (/\b(ahora|ya|urgente
|
|
45
|
+
if (/\b(ahora|ya|urgente|urgencia|hoy|inmediato|inmediatamente|últim[oa]s?|solo\s+hoy|ap[uú]rate|rápido|de\s+inmediato)\b/.test(
|
|
46
|
+
t
|
|
47
|
+
)) {
|
|
46
48
|
flags.push("urgency");
|
|
47
49
|
score += 0.2;
|
|
48
50
|
}
|
|
49
|
-
if (/\b(compra|oferta|promo|descuento|gratis|clic|click
|
|
51
|
+
if (/\b(compra|oferta|promo|promoci[oó]n|descuento|rebaja|gratis|free|premio|prize|winner|gana|claim|reward|clic|click)\b/.test(
|
|
52
|
+
t
|
|
53
|
+
)) {
|
|
50
54
|
flags.push("spam_sales");
|
|
51
55
|
score += 0.25;
|
|
52
56
|
}
|
|
57
|
+
const wantsSendVerb = /\b(envi(a|á)me|env[ií]ame|m(a|á)ndame|p(a|á)same|dame|compart(e|a|as)|reenv[ií]a(me)?)\b/.test(
|
|
58
|
+
t
|
|
59
|
+
);
|
|
60
|
+
const mentionsCode = /\b(c[oó]digo|codigo|otp|2fa|token|pin|clave)\b/.test(t);
|
|
61
|
+
const mentionsVerify = /\b(verificaci[oó]n|verificar|confirmar|validar)\b/.test(t);
|
|
62
|
+
const mentionsAccount = /\b(cuenta|account)\b/.test(t);
|
|
63
|
+
const mentionsSms = /\b(sms|por\s+sms)\b/.test(t);
|
|
64
|
+
if (wantsSendVerb && mentionsCode && (mentionsVerify || mentionsAccount || mentionsSms)) {
|
|
65
|
+
flags.push("phishing_2fa_code");
|
|
66
|
+
score += 0.55;
|
|
67
|
+
}
|
|
68
|
+
if (/\bverify\b/.test(t) && /\baccount\b/.test(t) && /\bclick\b/.test(t) && /\b(closed|close|suspend|suspended|disable|disabled|locked)\b/.test(t)) {
|
|
69
|
+
flags.push("phishing_verify_threat_en");
|
|
70
|
+
score += 0.35;
|
|
71
|
+
}
|
|
72
|
+
if (/\b(te\s+deposito|te\s+dep[oó]sito|te\s+transfiero|te\s+transferir[eé]|transferencia|dep[oó]sito)\b/.test(
|
|
73
|
+
t
|
|
74
|
+
) && /\b(tarjeta|cuenta|clabe|iban|swift|n[uú]mero\s+de\s+tarjeta|numero\s+de\s+tarjeta)\b/.test(t)) {
|
|
75
|
+
flags.push("fraud_payment_request");
|
|
76
|
+
score += 0.35;
|
|
77
|
+
}
|
|
78
|
+
if (/\b(gana(r)?\s+dinero|ingresos|dinero\s+extra)\b/.test(t) && /\b(desde\s+casa|en\s+casa|home)\b/.test(t) && /\b(sin\s+esfuerzo|f[aá]cil|r[aá]pido|easy|fast)\b/.test(t)) {
|
|
79
|
+
flags.push("scam_wfh");
|
|
80
|
+
score += 0.3;
|
|
81
|
+
}
|
|
53
82
|
const moneyHits = countRegex(raw, /\$+/g);
|
|
54
|
-
|
|
83
|
+
const pctHits = countRegex(raw, /%/g);
|
|
84
|
+
if (moneyHits > 0 || pctHits > 0 || /\b(usd|mxn|eur)\b/i.test(raw)) {
|
|
55
85
|
flags.push("money_signal");
|
|
56
|
-
score += Math.min(0.
|
|
86
|
+
score += Math.min(0.25, moneyHits * 0.05 + pctHits * 0.05 + 0.1);
|
|
57
87
|
}
|
|
58
88
|
const exclam = countRegex(raw, /!/g);
|
|
59
89
|
const capsRatio = (() => {
|
|
@@ -66,39 +96,24 @@ function analyzeEntropy(text) {
|
|
|
66
96
|
flags.push("shouting");
|
|
67
97
|
score += 0.2;
|
|
68
98
|
}
|
|
69
|
-
if (/\b(si
|
|
99
|
+
if (/\b(si\s+de\s+verdad|si\s+me\s+quisieras|es\s+tu\s+culpa|no\s+tienes\s+opci[oó]n|me\s+debes|hazlo\s+o\s+si\s+no|si\s+no\s+lo\s+haces)\b/.test(
|
|
100
|
+
t
|
|
101
|
+
)) {
|
|
70
102
|
flags.push("emotional_manipulation");
|
|
71
103
|
score += 0.35;
|
|
72
104
|
}
|
|
73
|
-
if (/\b(todos
|
|
105
|
+
if (/\b(todos\s+lo\s+saben|lo\s+esconden|la\s+verdad\s+oculta|ellos\s+no\s+quieren|simulaci[oó]n)\b/.test(
|
|
106
|
+
t
|
|
107
|
+
)) {
|
|
74
108
|
flags.push("conspiracy_vague");
|
|
75
109
|
score += 0.2;
|
|
76
110
|
}
|
|
77
|
-
if (/\b(
|
|
111
|
+
if (/\b(es\s+obvio|todo\s+mundo\s+sabe|se\s+sabe|est[aá]\s+claro|la\s+cultura\s+lo\s+prueba)\b/.test(
|
|
112
|
+
t
|
|
113
|
+
)) {
|
|
78
114
|
flags.push("weak_evidence");
|
|
79
115
|
score += 0.2;
|
|
80
116
|
}
|
|
81
|
-
if (/\b(ellos|la élite|los de arriba)\b/.test(t) && /\b(esconden|ocultan|tapan)\b/.test(t)) {
|
|
82
|
-
flags.push("hidden_actor");
|
|
83
|
-
score += 0.15;
|
|
84
|
-
}
|
|
85
|
-
if (/\b(física cuántica|cuantica|cuántico|quantum)\b/.test(t)) {
|
|
86
|
-
flags.push("pseudo_science_quantum");
|
|
87
|
-
score += 0.2;
|
|
88
|
-
}
|
|
89
|
-
const manifestHits = countRegex(t, /\b(manifestar|manifestación|decretar|decreto|vibración|vibracion|frecuencia|energía|energia|ley de la atracción|universo me lo dará)\b/g) + countRegex(t, /\b(realine(a|ar)\b.*\bátom|\bátom|\batomos\b)/g);
|
|
90
|
-
if (manifestHits > 0) {
|
|
91
|
-
flags.push("magic_manifesting");
|
|
92
|
-
score += Math.min(0.35, 0.15 + manifestHits * 0.06);
|
|
93
|
-
}
|
|
94
|
-
if (/\b(no hay una verdad objetiva|no existe la verdad objetiva|tu verdad|mi verdad|la verdad es relativa|lo que importa es lo que sientes)\b/.test(t)) {
|
|
95
|
-
flags.push("truth_relativism");
|
|
96
|
-
score += 0.35;
|
|
97
|
-
}
|
|
98
|
-
if (/\b(deben|debe)\b.*\b(obligatoriamente|por lo tanto|por ende)\b/.test(t) || /\b(la materia)\b.*\b(se subordina|obedece)\b/.test(t)) {
|
|
99
|
-
flags.push("broken_causality");
|
|
100
|
-
score += 0.2;
|
|
101
|
-
}
|
|
102
117
|
score = clamp01(score);
|
|
103
118
|
return { score, flags };
|
|
104
119
|
}
|
|
@@ -189,39 +204,56 @@ function mergeFlags(base, extra) {
|
|
|
189
204
|
}
|
|
190
205
|
return out;
|
|
191
206
|
}
|
|
192
|
-
function englishSpamBooster(
|
|
193
|
-
const t = (
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
{ re: /\btax refund\b|\bunpaid\b|\brefund\b|\bchargeback\b/g, score: 0.1, flag: "spam_kw_refund" }
|
|
207
|
+
function englishSpamBooster(text) {
|
|
208
|
+
const t = (text || "").toLowerCase();
|
|
209
|
+
const hits = [];
|
|
210
|
+
const kw = [
|
|
211
|
+
["free", "spam_kw_free"],
|
|
212
|
+
["winner", "spam_kw_winner"],
|
|
213
|
+
["claim", "spam_kw_claim"],
|
|
214
|
+
["click", "spam_kw_click"],
|
|
215
|
+
["verify", "spam_kw_verify"],
|
|
216
|
+
["prize", "spam_kw_prize"],
|
|
217
|
+
["urgent", "spam_kw_urgency_en"],
|
|
218
|
+
["limited time", "spam_kw_urgency_en"],
|
|
219
|
+
["today only", "spam_kw_urgency_en"]
|
|
206
220
|
];
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let hitCount = 0;
|
|
210
|
-
for (const p of patterns) {
|
|
211
|
-
const m = t.match(p.re);
|
|
212
|
-
if (m && m.length > 0) {
|
|
213
|
-
hitCount += m.length;
|
|
214
|
-
addScore += p.score;
|
|
215
|
-
addFlags.push(p.flag);
|
|
216
|
-
}
|
|
221
|
+
for (const [s, flag] of kw) {
|
|
222
|
+
if (t.includes(s)) hits.push(flag);
|
|
217
223
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
224
|
+
if (hits.length === 0) return { hitCount: 0, addScore: 0, addFlags: [] };
|
|
225
|
+
const addScore = Math.min(0.25, hits.length * 0.05);
|
|
226
|
+
const addFlags = mergeFlags(["spam_keywords_en"], hits);
|
|
227
|
+
return { hitCount: hits.length, addScore, addFlags };
|
|
228
|
+
}
|
|
229
|
+
function decideAction(params) {
|
|
230
|
+
const {
|
|
231
|
+
score,
|
|
232
|
+
warnT,
|
|
233
|
+
blockT,
|
|
234
|
+
strongSpam,
|
|
235
|
+
intention = "",
|
|
236
|
+
flags,
|
|
237
|
+
policy = {}
|
|
238
|
+
} = params;
|
|
239
|
+
const blockIntentions = new Set(policy.block_intentions ?? []);
|
|
240
|
+
const warnIntentions = new Set(policy.warn_intentions ?? []);
|
|
241
|
+
const blockFlags = new Set(policy.block_flags ?? []);
|
|
242
|
+
const warnFlags = new Set(policy.warn_flags ?? []);
|
|
243
|
+
if (blockIntentions.has(intention)) return "BLOCK";
|
|
244
|
+
if (flags.some((f) => blockFlags.has(f))) return "BLOCK";
|
|
245
|
+
if (warnIntentions.has(intention)) return "WARN";
|
|
246
|
+
if (flags.some((f) => warnFlags.has(f))) return "WARN";
|
|
247
|
+
const strongSpamBlock = policy.strong_spam_block ?? true;
|
|
248
|
+
if (strongSpamBlock && strongSpam) return "BLOCK";
|
|
249
|
+
if (score >= blockT) return "BLOCK";
|
|
250
|
+
if (score >= warnT) return "WARN";
|
|
251
|
+
return "ALLOW";
|
|
221
252
|
}
|
|
222
253
|
function gateLLM(text, config = {}) {
|
|
223
|
-
const
|
|
224
|
-
const
|
|
254
|
+
const ruleset = config.ruleset;
|
|
255
|
+
const warnT = ruleset?.thresholds?.warn ?? config.warnThreshold ?? 0.25;
|
|
256
|
+
const blockT = ruleset?.thresholds?.block ?? config.blockThreshold ?? 0.6;
|
|
225
257
|
const r = runEntropyFilter(text);
|
|
226
258
|
let score = r.entropy_analysis.score;
|
|
227
259
|
let flags = [...r.entropy_analysis.flags];
|
|
@@ -230,20 +262,22 @@ function gateLLM(text, config = {}) {
|
|
|
230
262
|
score = clamp013(score + booster.addScore);
|
|
231
263
|
flags = mergeFlags(flags, booster.addFlags);
|
|
232
264
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
confidence = Math.max(confidence, 0.75);
|
|
239
|
-
rationale = (rationale ? rationale + " " : "") + "Detect\xE9 keywords t\xEDpicas de spam/phishing en ingl\xE9s.";
|
|
240
|
-
}
|
|
241
|
-
const hasSpam = flags.includes("spam_sales") || flags.includes("spam_keywords_en");
|
|
242
|
-
const hasMoneySignals = flags.includes("money_signal") || flags.includes("spam_kw_prize") || flags.includes("spam_kw_loan");
|
|
265
|
+
const intention = r.intention_evaluation.intention || "unknown";
|
|
266
|
+
const confidence = r.intention_evaluation.confidence ?? 0;
|
|
267
|
+
const rationale = r.intention_evaluation.rationale ?? "";
|
|
268
|
+
const hasSpam = flags.includes("spam_sales");
|
|
269
|
+
const hasMoneySignals = flags.includes("money_signal") || flags.includes("money_signal_high");
|
|
243
270
|
const strongSpam = hasSpam && hasMoneySignals;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
271
|
+
const policy = ruleset?.policy ?? {};
|
|
272
|
+
const action = decideAction({
|
|
273
|
+
score,
|
|
274
|
+
warnT,
|
|
275
|
+
blockT,
|
|
276
|
+
strongSpam,
|
|
277
|
+
intention,
|
|
278
|
+
flags,
|
|
279
|
+
policy
|
|
280
|
+
});
|
|
247
281
|
return {
|
|
248
282
|
action,
|
|
249
283
|
entropy_score: score,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/entropy.ts","../src/intention.ts","../src/wrapper.ts","../src/middleware.ts","../src/gate.ts"],"sourcesContent":["// src/index.ts\nexport { analyzeEntropy } from \"./entropy\";\nexport { evaluateIntention } from \"./intention\";\nexport { runEntropyFilter } from \"./wrapper\";\nexport { entropyMiddleware } from \"./middleware\";\n\nexport type {\n EntropyResult,\n IntentionEvaluation,\n FilterResult\n} from \"./types\";\nexport { gateLLM as gate } from \"./gate\";\nexport * from \"./gate\";\n","// src/entropy.ts\nexport type EntropyResult = {\n score: number; // 0..1\n flags: string[];\n};\n\nfunction clamp01(x: number) {\n return Math.max(0, Math.min(1, x));\n}\n\nfunction countRegex(text: string, re: RegExp) {\n const m = text.match(re);\n return m ? m.length : 0;\n}\n\nexport function analyzeEntropy(text: string): EntropyResult {\n const raw = text || \"\";\n const t = raw.toLowerCase();\n const flags: string[] = [];\n let score = 0;\n\n // 1) Urgencia / presión\n if (/\\b(ahora|ya|urgente|última|hoy|inmediato)\\b/.test(t)) {\n flags.push(\"urgency\");\n score += 0.20;\n }\n\n // 2) Spam / venta agresiva\n if (/\\b(compra|oferta|promo|descuento|gratis|clic|click|off)\\b/.test(t)) {\n flags.push(\"spam_sales\");\n score += 0.25;\n }\n\n // 3) Señales $$$ / símbolos\n const moneyHits = countRegex(raw, /\\$+/g);\n if (moneyHits > 0) {\n flags.push(\"money_signal\");\n score += Math.min(0.20, moneyHits * 0.05);\n }\n\n // 4) Exceso de signos / gritos\n const exclam = countRegex(raw, /!/g);\n const capsRatio = (() => {\n const letters = raw.match(/[A-Za-zÁÉÍÓÚÜÑáéíóúüñ]/g) || [];\n if (letters.length === 0) return 0;\n const caps = (raw.match(/[A-ZÁÉÍÓÚÜÑ]/g) || []).length;\n return caps / letters.length;\n })();\n\n if (exclam >= 3 || capsRatio >= 0.35) {\n flags.push(\"shouting\");\n score += 0.20;\n }\n\n // 5) Manipulación / culpa / coerción\n if (/\\b(si de verdad|si me quisieras|es tu culpa|no tienes opción|me debes)\\b/.test(t)) {\n flags.push(\"emotional_manipulation\");\n score += 0.35;\n }\n\n // 6) Conspiración vaga / “todos lo saben”\n if (/\\b(todos lo saben|lo esconden|la verdad oculta|ellos no quieren|simulación)\\b/.test(t)) {\n flags.push(\"conspiracy_vague\");\n score += 0.20;\n }\n\n // 6.5) “Prueba vaga” / apelación a cultura como evidencia\n if (/\\b(la cultura lo prueba|es obvio|todo mundo sabe|se sabe|está claro)\\b/.test(t)) {\n flags.push(\"weak_evidence\");\n score += 0.20;\n }\n\n // 6.6) Totalización + agente oculto (“ellos”)\n if (/\\b(ellos|la élite|los de arriba)\\b/.test(t) && /\\b(esconden|ocultan|tapan)\\b/.test(t)) {\n flags.push(\"hidden_actor\");\n score += 0.15;\n }\n\n // ------------------------------------------------------------\n // NUEVO: Entropía por pseudo-ciencia / pensamiento mágico / relativismo\n // ------------------------------------------------------------\n\n // 7) Pseudo-ciencia \"cuántica\" usada como licencia mágica\n if (/\\b(física cuántica|cuantica|cuántico|quantum)\\b/.test(t)) {\n flags.push(\"pseudo_science_quantum\");\n score += 0.20;\n }\n\n // 8) Manifestación mágica / decretos / vibración / energía como causalidad\n const manifestHits =\n countRegex(t, /\\b(manifestar|manifestación|decretar|decreto|vibración|vibracion|frecuencia|energía|energia|ley de la atracción|universo me lo dará)\\b/g) +\n countRegex(t, /\\b(realine(a|ar)\\b.*\\bátom|\\bátom|\\batomos\\b)/g);\n\n if (manifestHits > 0) {\n flags.push(\"magic_manifesting\");\n score += Math.min(0.35, 0.15 + manifestHits * 0.06);\n }\n\n // 9) Relativismo de la verdad / negación explícita de verdad objetiva\n if (/\\b(no hay una verdad objetiva|no existe la verdad objetiva|tu verdad|mi verdad|la verdad es relativa|lo que importa es lo que sientes)\\b/.test(t)) {\n flags.push(\"truth_relativism\");\n score += 0.35;\n }\n\n // 10) Causalidad rota / obligación metafísica (\"debe\" porque lo deseo)\n if (/\\b(deben|debe)\\b.*\\b(obligatoriamente|por lo tanto|por ende)\\b/.test(t) || /\\b(la materia)\\b.*\\b(se subordina|obedece)\\b/.test(t)) {\n flags.push(\"broken_causality\");\n score += 0.20;\n }\n\n // Normaliza: score final 0..1\n score = clamp01(score);\n\n return { score, flags };\n}\n","// src/intention.ts\nimport type { IntentionEvaluation, IntentionType } from \"./types\";\n\nfunction clamp01(x: number) {\n return Math.max(0, Math.min(1, x));\n}\n\nexport function evaluateIntention(text: string): IntentionEvaluation {\n const raw = text || \"\";\n const t = raw.toLowerCase();\n\n // Heurísticas rápidas (MVP)\n const isHelp =\n /\\b(ayuda|ayúdame|explica|resume|resumir|cómo|como|puedes|podrías|por favor)\\b/.test(\n t\n );\n\n const isSpam =\n /\\b(compra|oferta|promo|descuento|gratis|haz clic|click|off|90%|% off)\\b/.test(\n t\n ) || (raw.match(/\\$+/g) || []).length > 0;\n\n const isManip =\n /\\b(si de verdad|si me quisieras|es tu culpa|no tienes opción|me debes)\\b/.test(\n t\n );\n\n const isConsp =\n /\\b(simulación|todos lo saben|lo esconden|verdad oculta|ellos no quieren)\\b/.test(\n t\n );\n\n // NUEVO: pseudo-ciencia / pensamiento mágico / relativismo (desinformación)\n const isMisinformation =\n /\\b(física cuántica|cuantica|cuántica|cuántico|quantum)\\b/.test(t) ||\n /\\b(manifestar|manifestación|decretar|decreto|vibración|vibracion|frecuencia|energía|energia|ley de la atracción)\\b/.test(t) ||\n /\\b(no hay una verdad objetiva|no existe la verdad objetiva|tu verdad|mi verdad|la verdad es relativa)\\b/.test(t) ||\n /\\b(la materia)\\b.*\\b(se subordina|obedece)\\b/.test(t);\n\n let intention: IntentionType = \"unknown\";\n let confidence = 0.0;\n let rationale = \"\";\n\n if (isSpam) {\n intention = \"marketing_spam\";\n confidence = 0.85;\n rationale = \"Detecté señales de venta agresiva/urgencia/dinero.\";\n } else if (isManip) {\n intention = \"manipulation\";\n confidence = 0.85;\n rationale = \"Detecté coerción/culpa/chantaje emocional.\";\n } else if (isConsp) {\n intention = \"conspiracy\";\n confidence = 0.75;\n rationale = \"Detecté marco conspirativo vago ('lo esconden', 'todos lo saben').\";\n } else if (isMisinformation) {\n intention = \"misinformation\";\n confidence = 0.85;\n rationale =\n \"Detecté patrón de pseudo-ciencia/pensamiento mágico/relativismo de la verdad (alta probabilidad de desinformación).\";\n } else if (isHelp) {\n intention = \"request_help\";\n confidence = 0.7;\n rationale = \"Parece una petición legítima de ayuda/explicación.\";\n }\n\n return { intention, confidence: clamp01(confidence), rationale };\n}\n","// src/wrapper.ts\nimport { analyzeEntropy } from \"./entropy\";\nimport { evaluateIntention } from \"./intention\";\nimport type { FilterResult, IntentionEvaluation } from \"./types\";\n\nexport function runEntropyFilter(text: string): FilterResult {\n const entropy_analysis = analyzeEntropy(text);\n let intention_evaluation: IntentionEvaluation = evaluateIntention(text);\n\n // Corrección: si el texto trae señales fuertes de entropía epistemológica,\n // no lo clasifiques como \"request_help\" solo por ser pregunta larga.\n const hardFlags = new Set(entropy_analysis.flags);\n const epistemicEntropy =\n hardFlags.has(\"truth_relativism\") ||\n hardFlags.has(\"magic_manifesting\") ||\n hardFlags.has(\"pseudo_science_quantum\") ||\n hardFlags.has(\"broken_causality\");\n\n if (epistemicEntropy) {\n intention_evaluation = {\n intention: \"misinformation\",\n confidence: Math.max(intention_evaluation.confidence ?? 0.7, 0.8),\n rationale:\n \"Detecté patrón de pseudo-ciencia/pensamiento mágico/relativismo de la verdad; alta probabilidad de desinformación o argumento sin anclaje causal.\"\n };\n }\n\n return { entropy_analysis, intention_evaluation };\n}\n","// src/middleware.ts\nimport { runEntropyFilter } from \"./wrapper\";\nimport type { FilterResult } from \"./types\";\n\n/**\n * Middleware agnóstico (NO depende de express types).\n * Compatible con Express / Next API routes / cualquier framework estilo req-res-next.\n *\n * Espera: req.body.text (string)\n * Escribe: req.entropy = FilterResult\n */\nexport function entropyMiddleware(req: any, _res: any, next: any) {\n const text = req?.body?.text;\n\n const result: FilterResult =\n typeof text === \"string\" ? runEntropyFilter(text) : runEntropyFilter(\"\");\n\n req.entropy = result;\n next?.();\n}\n\n/**\n * Tipo auxiliar opcional (sin forzar dependencias).\n * Útil si quieres tipar tu req en tu app.\n */\nexport type EntropyAugmentedRequest = {\n body?: { text?: unknown };\n entropy?: FilterResult;\n};\n","// src/gate.ts\nimport { runEntropyFilter } from \"./wrapper\";\n\nexport type GateAction = \"ALLOW\" | \"WARN\" | \"BLOCK\";\n\nexport type GateResult = {\n action: GateAction;\n entropy_score: number;\n flags: string[];\n intention: string;\n confidence: number;\n rationale: string;\n};\n\nexport type GateConfig = {\n warnThreshold?: number; // default: 0.25\n blockThreshold?: number; // default: 0.60\n};\n\n/** Clamp 0..1 */\nfunction clamp01(x: number) {\n return Math.max(0, Math.min(1, x));\n}\n\n/** Add unique flags preserving order */\nfunction mergeFlags(base: string[], extra: string[]) {\n const set = new Set(base);\n const out = [...base];\n for (const f of extra) {\n if (!set.has(f)) {\n set.add(f);\n out.push(f);\n }\n }\n return out;\n}\n\n/**\n * Detección de spam/phishing en inglés por keywords.\n * Se implementa como “booster” de score + flags (sin tocar entropy.ts).\n */\nfunction englishSpamBooster(rawText: string): {\n addScore: number;\n addFlags: string[];\n hitCount: number;\n} {\n const t = (rawText || \"\").toLowerCase();\n\n // Patrones típicos (spam / phishing / promos agresivas)\n const patterns: Array<{ re: RegExp; score: number; flag: string }> = [\n { re: /\\bfree\\b/g, score: 0.08, flag: \"spam_kw_free\" },\n { re: /\\bwinner\\b|\\bwon\\b|\\bcongratulations\\b/g, score: 0.10, flag: \"spam_kw_winner\" },\n { re: /\\bclaim\\b|\\bredeem\\b/g, score: 0.08, flag: \"spam_kw_claim\" },\n { re: /\\bclick\\b|\\bclick here\\b|\\bopen link\\b|\\btap here\\b/g, score: 0.10, flag: \"spam_kw_click\" },\n { re: /\\blimited time\\b|\\bact now\\b|\\bfinal notice\\b|\\bbefore midnight\\b/g, score: 0.10, flag: \"spam_kw_urgency_en\" },\n { re: /\\bverify\\b|\\bconfirm\\b|\\baccount\\b.*\\b(suspended|locked)\\b/g, score: 0.12, flag: \"spam_kw_verify\" },\n { re: /\\bprize\\b|\\bgift card\\b|\\bgiftcard\\b|\\bvoucher\\b|\\biphone\\b|\\bsurvey\\b/g, score: 0.10, flag: \"spam_kw_prize\" },\n { re: /\\bloan\\b|\\bpre-?approved\\b|\\bno credit check\\b/g, score: 0.12, flag: \"spam_kw_loan\" },\n { re: /\\bcrypto\\b|\\bairdrop\\b|\\bwallet\\b|\\bseed phrase\\b/g, score: 0.10, flag: \"spam_kw_crypto\" },\n { re: /\\bdelivery failed\\b|\\breschedule\\b|\\bpackage\\b|\\bcourier\\b/g, score: 0.10, flag: \"spam_kw_delivery\" },\n { re: /\\btax refund\\b|\\bunpaid\\b|\\brefund\\b|\\bchargeback\\b/g, score: 0.10, flag: \"spam_kw_refund\" },\n ];\n\n let addScore = 0;\n const addFlags: string[] = [];\n let hitCount = 0;\n\n for (const p of patterns) {\n const m = t.match(p.re);\n if (m && m.length > 0) {\n hitCount += m.length;\n addScore += p.score; // suma “por patrón”, no por ocurrencia (controlado)\n addFlags.push(p.flag);\n }\n }\n\n // cap para no sobre-castigar\n addScore = Math.min(0.35, addScore);\n\n if (hitCount > 0) addFlags.push(\"spam_keywords_en\");\n\n return { addScore, addFlags, hitCount };\n}\n\n/**\n * Gate principal (producto): deterministic + barato.\n */\nexport function gateLLM(text: string, config: GateConfig = {}): GateResult {\n const warnT = config.warnThreshold ?? 0.25;\n const blockT = config.blockThreshold ?? 0.6;\n\n const r = runEntropyFilter(text);\n\n // base\n let score = r.entropy_analysis.score;\n let flags = [...r.entropy_analysis.flags];\n\n // booster EN\n const booster = englishSpamBooster(text);\n if (booster.hitCount > 0) {\n score = clamp01(score + booster.addScore);\n flags = mergeFlags(flags, booster.addFlags);\n }\n\n // intención base (intention.ts)\n let intention = r.intention_evaluation.intention || \"unknown\";\n let confidence = r.intention_evaluation.confidence ?? 0;\n let rationale = r.intention_evaluation.rationale ?? \"\";\n\n // si pegó booster EN y quedó unknown → marketing_spam\n if (booster.hitCount > 0 && intention === \"unknown\") {\n intention = \"marketing_spam\";\n confidence = Math.max(confidence, 0.75);\n rationale = (rationale ? rationale + \" \" : \"\") + \"Detecté keywords típicas de spam/phishing en inglés.\";\n }\n\n // reglas fuertes (para BLOCK “vendible”)\n const hasSpam =\n flags.includes(\"spam_sales\") ||\n flags.includes(\"spam_keywords_en\");\n\n const hasMoneySignals =\n flags.includes(\"money_signal\") ||\n flags.includes(\"spam_kw_prize\") ||\n flags.includes(\"spam_kw_loan\");\n\n const strongSpam = hasSpam && hasMoneySignals;\n\n let action: GateAction = \"ALLOW\";\n if (score > blockT || strongSpam) action = \"BLOCK\";\n else if (score >= warnT) action = \"WARN\";\n\n return {\n action,\n entropy_score: score,\n flags,\n intention,\n confidence: clamp01(confidence),\n rationale,\n };\n}\n\n// Alias “bonito” para tu server: gate(text)\nexport const gate = gateLLM;\n"],"mappings":"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","names":["clamp01","clamp01"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/entropy.ts","../src/intention.ts","../src/wrapper.ts","../src/middleware.ts","../src/gate.ts"],"sourcesContent":["// src/index.ts\r\nexport { analyzeEntropy } from \"./entropy\";\r\nexport { evaluateIntention } from \"./intention\";\r\nexport { runEntropyFilter } from \"./wrapper\";\r\nexport { entropyMiddleware } from \"./middleware\";\r\n\r\nexport type {\r\n EntropyResult,\r\n IntentionEvaluation,\r\n FilterResult\r\n} from \"./types\";\r\nexport { gateLLM as gate } from \"./gate\";\r\nexport * from \"./gate\";\r\n","// src/entropy.ts\r\nexport type EntropyResult = {\r\n score: number; // 0..1\r\n flags: string[];\r\n};\r\n\r\nfunction clamp01(x: number) {\r\n return Math.max(0, Math.min(1, x));\r\n}\r\n\r\nfunction countRegex(text: string, re: RegExp) {\r\n const m = text.match(re);\r\n return m ? m.length : 0;\r\n}\r\n\r\n/**\r\n * Entropy = señales lingüísticas + lógicas (determinístico, barato).\r\n * Nota: aquí SOLO generamos banderas y score. La acción (ALLOW/WARN/BLOCK)\r\n * se decide en gate.ts según thresholds/policy del ruleset.\r\n */\r\nexport function analyzeEntropy(text: string): EntropyResult {\r\n const raw = text || \"\";\r\n const t = raw.toLowerCase();\r\n const flags: string[] = [];\r\n let score = 0;\r\n\r\n // ------------------------------------------------------------\r\n // 1) Urgencia / presión temporal\r\n // ------------------------------------------------------------\r\n if (\r\n /\\b(ahora|ya|urgente|urgencia|hoy|inmediato|inmediatamente|últim[oa]s?|solo\\s+hoy|ap[uú]rate|rápido|de\\s+inmediato)\\b/.test(\r\n t\r\n )\r\n ) {\r\n flags.push(\"urgency\");\r\n score += 0.2;\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 2) Spam / venta agresiva (ES/EN básico)\r\n // ------------------------------------------------------------\r\n if (\r\n /\\b(compra|oferta|promo|promoci[oó]n|descuento|rebaja|gratis|free|premio|prize|winner|gana|claim|reward|clic|click)\\b/.test(\r\n t\r\n )\r\n ) {\r\n flags.push(\"spam_sales\");\r\n score += 0.25;\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 3) Phishing / Fraude / Scam (señales de alto riesgo)\r\n // ------------------------------------------------------------\r\n\r\n // 3A) Phishing: pedir código/OTP/token de verificación (ES/EN)\r\n // Ej: \"Envíame tu código de verificación para confirmar tu cuenta.\"\r\n const wantsSendVerb =\r\n /\\b(envi(a|á)me|env[ií]ame|m(a|á)ndame|p(a|á)same|dame|compart(e|a|as)|reenv[ií]a(me)?)\\b/.test(\r\n t\r\n );\r\n\r\n const mentionsCode =\r\n /\\b(c[oó]digo|codigo|otp|2fa|token|pin|clave)\\b/.test(t);\r\n\r\n const mentionsVerify =\r\n /\\b(verificaci[oó]n|verificar|confirmar|validar)\\b/.test(t);\r\n\r\n const mentionsAccount = /\\b(cuenta|account)\\b/.test(t);\r\n\r\n const mentionsSms = /\\b(sms|por\\s+sms)\\b/.test(t);\r\n\r\n // Regla: verbo de “enviar/pasar” + (código/otp/token/pin) + (verificación/cuenta/sms)\r\n if (wantsSendVerb && mentionsCode && (mentionsVerify || mentionsAccount || mentionsSms)) {\r\n flags.push(\"phishing_2fa_code\");\r\n score += 0.55; // fuerte: debe quedar mínimo en WARN con casi cualquier preset\r\n }\r\n\r\n // 3B) Phishing EN: “verify account” + “click” + amenaza de cierre\r\n if (\r\n /\\bverify\\b/.test(t) &&\r\n /\\baccount\\b/.test(t) &&\r\n /\\bclick\\b/.test(t) &&\r\n /\\b(closed|close|suspend|suspended|disable|disabled|locked)\\b/.test(t)\r\n ) {\r\n flags.push(\"phishing_verify_threat_en\");\r\n score += 0.35;\r\n }\r\n\r\n // 3C) Fraude: “te deposito / transfiero” + “tarjeta/cuenta/clabe”\r\n if (\r\n /\\b(te\\s+deposito|te\\s+dep[oó]sito|te\\s+transfiero|te\\s+transferir[eé]|transferencia|dep[oó]sito)\\b/.test(\r\n t\r\n ) &&\r\n /\\b(tarjeta|cuenta|clabe|iban|swift|n[uú]mero\\s+de\\s+tarjeta|numero\\s+de\\s+tarjeta)\\b/.test(t)\r\n ) {\r\n flags.push(\"fraud_payment_request\");\r\n score += 0.35;\r\n }\r\n\r\n // 3D) Scam: “gana dinero desde casa / sin esfuerzo”\r\n if (\r\n /\\b(gana(r)?\\s+dinero|ingresos|dinero\\s+extra)\\b/.test(t) &&\r\n /\\b(desde\\s+casa|en\\s+casa|home)\\b/.test(t) &&\r\n /\\b(sin\\s+esfuerzo|f[aá]cil|r[aá]pido|easy|fast)\\b/.test(t)\r\n ) {\r\n flags.push(\"scam_wfh\");\r\n score += 0.3;\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 4) Señales de dinero ($$$, %, monedas)\r\n // ------------------------------------------------------------\r\n const moneyHits = countRegex(raw, /\\$+/g);\r\n const pctHits = countRegex(raw, /%/g);\r\n if (moneyHits > 0 || pctHits > 0 || /\\b(usd|mxn|eur)\\b/i.test(raw)) {\r\n flags.push(\"money_signal\");\r\n score += Math.min(0.25, moneyHits * 0.05 + pctHits * 0.05 + 0.1);\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 5) Exceso de signos / gritos (señal de baja calidad o manipulación)\r\n // ------------------------------------------------------------\r\n const exclam = countRegex(raw, /!/g);\r\n const capsRatio = (() => {\r\n const letters = raw.match(/[A-Za-zÁÉÍÓÚÜÑáéíóúüñ]/g) || [];\r\n if (letters.length === 0) return 0;\r\n const caps = (raw.match(/[A-ZÁÉÍÓÚÜÑ]/g) || []).length;\r\n return caps / letters.length;\r\n })();\r\n\r\n if (exclam >= 3 || capsRatio >= 0.35) {\r\n flags.push(\"shouting\");\r\n score += 0.2;\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 6) Coerción / culpa / chantaje emocional\r\n // ------------------------------------------------------------\r\n if (\r\n /\\b(si\\s+de\\s+verdad|si\\s+me\\s+quisieras|es\\s+tu\\s+culpa|no\\s+tienes\\s+opci[oó]n|me\\s+debes|hazlo\\s+o\\s+si\\s+no|si\\s+no\\s+lo\\s+haces)\\b/.test(\r\n t\r\n )\r\n ) {\r\n flags.push(\"emotional_manipulation\");\r\n score += 0.35;\r\n }\r\n\r\n // ------------------------------------------------------------\r\n // 7) Conspiración vaga / evidencia débil (baja confiabilidad)\r\n // ------------------------------------------------------------\r\n if (\r\n /\\b(todos\\s+lo\\s+saben|lo\\s+esconden|la\\s+verdad\\s+oculta|ellos\\s+no\\s+quieren|simulaci[oó]n)\\b/.test(\r\n t\r\n )\r\n ) {\r\n flags.push(\"conspiracy_vague\");\r\n score += 0.2;\r\n }\r\n\r\n if (\r\n /\\b(es\\s+obvio|todo\\s+mundo\\s+sabe|se\\s+sabe|est[aá]\\s+claro|la\\s+cultura\\s+lo\\s+prueba)\\b/.test(\r\n t\r\n )\r\n ) {\r\n flags.push(\"weak_evidence\");\r\n score += 0.2;\r\n }\r\n\r\n score = clamp01(score);\r\n return { score, flags };\r\n}\r\n","// src/intention.ts\r\nimport type { IntentionEvaluation, IntentionType } from \"./types\";\r\n\r\nfunction clamp01(x: number) {\r\n return Math.max(0, Math.min(1, x));\r\n}\r\n\r\nexport function evaluateIntention(text: string): IntentionEvaluation {\r\n const raw = text || \"\";\r\n const t = raw.toLowerCase();\r\n\r\n // Heurísticas rápidas (MVP)\r\n const isHelp =\r\n /\\b(ayuda|ayúdame|explica|resume|resumir|cómo|como|puedes|podrías|por favor)\\b/.test(\r\n t\r\n );\r\n\r\n const isSpam =\r\n /\\b(compra|oferta|promo|descuento|gratis|haz clic|click|off|90%|% off)\\b/.test(\r\n t\r\n ) || (raw.match(/\\$+/g) || []).length > 0;\r\n\r\n const isManip =\r\n /\\b(si de verdad|si me quisieras|es tu culpa|no tienes opción|me debes)\\b/.test(\r\n t\r\n );\r\n\r\n const isConsp =\r\n /\\b(simulación|todos lo saben|lo esconden|verdad oculta|ellos no quieren)\\b/.test(\r\n t\r\n );\r\n\r\n // NUEVO: pseudo-ciencia / pensamiento mágico / relativismo (desinformación)\r\n const isMisinformation =\r\n /\\b(física cuántica|cuantica|cuántica|cuántico|quantum)\\b/.test(t) ||\r\n /\\b(manifestar|manifestación|decretar|decreto|vibración|vibracion|frecuencia|energía|energia|ley de la atracción)\\b/.test(t) ||\r\n /\\b(no hay una verdad objetiva|no existe la verdad objetiva|tu verdad|mi verdad|la verdad es relativa)\\b/.test(t) ||\r\n /\\b(la materia)\\b.*\\b(se subordina|obedece)\\b/.test(t);\r\n\r\n let intention: IntentionType = \"unknown\";\r\n let confidence = 0.0;\r\n let rationale = \"\";\r\n\r\n if (isSpam) {\r\n intention = \"marketing_spam\";\r\n confidence = 0.85;\r\n rationale = \"Detecté señales de venta agresiva/urgencia/dinero.\";\r\n } else if (isManip) {\r\n intention = \"manipulation\";\r\n confidence = 0.85;\r\n rationale = \"Detecté coerción/culpa/chantaje emocional.\";\r\n } else if (isConsp) {\r\n intention = \"conspiracy\";\r\n confidence = 0.75;\r\n rationale = \"Detecté marco conspirativo vago ('lo esconden', 'todos lo saben').\";\r\n } else if (isMisinformation) {\r\n intention = \"misinformation\";\r\n confidence = 0.85;\r\n rationale =\r\n \"Detecté patrón de pseudo-ciencia/pensamiento mágico/relativismo de la verdad (alta probabilidad de desinformación).\";\r\n } else if (isHelp) {\r\n intention = \"request_help\";\r\n confidence = 0.7;\r\n rationale = \"Parece una petición legítima de ayuda/explicación.\";\r\n }\r\n\r\n return { intention, confidence: clamp01(confidence), rationale };\r\n}\r\n","// src/wrapper.ts\r\nimport { analyzeEntropy } from \"./entropy\";\r\nimport { evaluateIntention } from \"./intention\";\r\nimport type { FilterResult, IntentionEvaluation } from \"./types\";\r\n\r\nexport function runEntropyFilter(text: string): FilterResult {\r\n const entropy_analysis = analyzeEntropy(text);\r\n let intention_evaluation: IntentionEvaluation = evaluateIntention(text);\r\n\r\n // Corrección: si el texto trae señales fuertes de entropía epistemológica,\r\n // no lo clasifiques como \"request_help\" solo por ser pregunta larga.\r\n const hardFlags = new Set(entropy_analysis.flags);\r\n const epistemicEntropy =\r\n hardFlags.has(\"truth_relativism\") ||\r\n hardFlags.has(\"magic_manifesting\") ||\r\n hardFlags.has(\"pseudo_science_quantum\") ||\r\n hardFlags.has(\"broken_causality\");\r\n\r\n if (epistemicEntropy) {\r\n intention_evaluation = {\r\n intention: \"misinformation\",\r\n confidence: Math.max(intention_evaluation.confidence ?? 0.7, 0.8),\r\n rationale:\r\n \"Detecté patrón de pseudo-ciencia/pensamiento mágico/relativismo de la verdad; alta probabilidad de desinformación o argumento sin anclaje causal.\"\r\n };\r\n }\r\n\r\n return { entropy_analysis, intention_evaluation };\r\n}\r\n","// src/middleware.ts\r\nimport { runEntropyFilter } from \"./wrapper\";\r\nimport type { FilterResult } from \"./types\";\r\n\r\n/**\r\n * Middleware agnóstico (NO depende de express types).\r\n * Compatible con Express / Next API routes / cualquier framework estilo req-res-next.\r\n *\r\n * Espera: req.body.text (string)\r\n * Escribe: req.entropy = FilterResult\r\n */\r\nexport function entropyMiddleware(req: any, _res: any, next: any) {\r\n const text = req?.body?.text;\r\n\r\n const result: FilterResult =\r\n typeof text === \"string\" ? runEntropyFilter(text) : runEntropyFilter(\"\");\r\n\r\n req.entropy = result;\r\n next?.();\r\n}\r\n\r\n/**\r\n * Tipo auxiliar opcional (sin forzar dependencias).\r\n * Útil si quieres tipar tu req en tu app.\r\n */\r\nexport type EntropyAugmentedRequest = {\r\n body?: { text?: unknown };\r\n entropy?: FilterResult;\r\n};\r\n","// src/gate.ts\r\nimport { runEntropyFilter } from \"./wrapper\";\r\n\r\nexport type GateAction = \"ALLOW\" | \"WARN\" | \"BLOCK\";\r\n\r\nexport type GateResult = {\r\n action: GateAction;\r\n entropy_score: number;\r\n flags: string[];\r\n intention: string;\r\n confidence: number;\r\n rationale: string;\r\n};\r\n\r\nexport type RulesetThresholds = {\r\n warn?: number;\r\n block?: number;\r\n};\r\n\r\nexport type RulesetPolicy = {\r\n /** if true, allow strongSpam to force BLOCK */\r\n strong_spam_block?: boolean;\r\n\r\n /** optional overrides */\r\n block_intentions?: string[];\r\n warn_intentions?: string[];\r\n\r\n /** flag overrides */\r\n block_flags?: string[];\r\n warn_flags?: string[];\r\n};\r\n\r\nexport type RulesetConfig = {\r\n name?: string;\r\n version?: number;\r\n description?: string;\r\n thresholds?: RulesetThresholds;\r\n policy?: RulesetPolicy;\r\n // normalization is applied in wrapper/ruleset loader; kept here for completeness\r\n normalization?: Record<string, unknown>;\r\n};\r\n\r\nexport type GateConfig = {\r\n /** Per-call threshold overrides (fallback if ruleset.thresholds not provided) */\r\n warnThreshold?: number; // default: 0.25\r\n blockThreshold?: number; // default: 0.60\r\n\r\n /** Optional ruleset (default/strict/public-api) */\r\n ruleset?: RulesetConfig;\r\n};\r\n\r\n/** Clamp 0..1 */\r\nfunction clamp01(x: number) {\r\n return Math.max(0, Math.min(1, x));\r\n}\r\n\r\n/** Add unique flags preserving order */\r\nfunction mergeFlags(base: string[], extra: string[]) {\r\n const set = new Set(base);\r\n const out = [...base];\r\n for (const f of extra) {\r\n if (!set.has(f)) {\r\n set.add(f);\r\n out.push(f);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Very small EN spam booster (keyword-ish).\r\n * Keep it deterministic and cheap. Tune in src/entropy.ts for real weights/patterns.\r\n */\r\nfunction englishSpamBooster(text: string): {\r\n hitCount: number;\r\n addScore: number;\r\n addFlags: string[];\r\n} {\r\n const t = (text || \"\").toLowerCase();\r\n const hits: string[] = [];\r\n\r\n const kw = [\r\n [\"free\", \"spam_kw_free\"],\r\n [\"winner\", \"spam_kw_winner\"],\r\n [\"claim\", \"spam_kw_claim\"],\r\n [\"click\", \"spam_kw_click\"],\r\n [\"verify\", \"spam_kw_verify\"],\r\n [\"prize\", \"spam_kw_prize\"],\r\n [\"urgent\", \"spam_kw_urgency_en\"],\r\n [\"limited time\", \"spam_kw_urgency_en\"],\r\n [\"today only\", \"spam_kw_urgency_en\"],\r\n ] as const;\r\n\r\n for (const [s, flag] of kw) {\r\n if (t.includes(s)) hits.push(flag);\r\n }\r\n\r\n if (hits.length === 0) return { hitCount: 0, addScore: 0, addFlags: [] };\r\n\r\n // conservative bump: 0.05 per hit, capped\r\n const addScore = Math.min(0.25, hits.length * 0.05);\r\n const addFlags = mergeFlags([\"spam_keywords_en\"], hits);\r\n return { hitCount: hits.length, addScore, addFlags };\r\n}\r\n\r\nfunction decideAction(params: {\r\n score: number;\r\n warnT: number;\r\n blockT: number;\r\n strongSpam: boolean;\r\n intention?: string;\r\n flags: string[];\r\n policy?: RulesetPolicy;\r\n}): GateAction {\r\n const {\r\n score,\r\n warnT,\r\n blockT,\r\n strongSpam,\r\n intention = \"\",\r\n flags,\r\n policy = {},\r\n } = params;\r\n\r\n const blockIntentions = new Set(policy.block_intentions ?? []);\r\n const warnIntentions = new Set(policy.warn_intentions ?? []);\r\n const blockFlags = new Set(policy.block_flags ?? []);\r\n const warnFlags = new Set(policy.warn_flags ?? []);\r\n\r\n // 1) explicit overrides (if provided)\r\n if (blockIntentions.has(intention)) return \"BLOCK\";\r\n if (flags.some((f) => blockFlags.has(f))) return \"BLOCK\";\r\n\r\n if (warnIntentions.has(intention)) return \"WARN\";\r\n if (flags.some((f) => warnFlags.has(f))) return \"WARN\";\r\n\r\n // 2) strong spam override (configurable)\r\n const strongSpamBlock = policy.strong_spam_block ?? true;\r\n if (strongSpamBlock && strongSpam) return \"BLOCK\";\r\n\r\n // 3) thresholds\r\n if (score >= blockT) return \"BLOCK\";\r\n if (score >= warnT) return \"WARN\";\r\n return \"ALLOW\";\r\n}\r\n\r\n/**\r\n * Gate principal (producto): deterministic + barato.\r\n */\r\nexport function gateLLM(text: string, config: GateConfig = {}): GateResult {\r\n const ruleset = config.ruleset;\r\n\r\n // thresholds: ruleset > config > defaults\r\n const warnT = ruleset?.thresholds?.warn ?? config.warnThreshold ?? 0.25;\r\n const blockT = ruleset?.thresholds?.block ?? config.blockThreshold ?? 0.6;\r\n\r\n const r = runEntropyFilter(text);\r\n\r\n // base\r\n let score = r.entropy_analysis.score;\r\n let flags = [...r.entropy_analysis.flags];\r\n\r\n // booster EN\r\n const booster = englishSpamBooster(text);\r\n if (booster.hitCount > 0) {\r\n score = clamp01(score + booster.addScore);\r\n flags = mergeFlags(flags, booster.addFlags);\r\n }\r\n\r\n // intención base (intention.ts)\r\n const intention = r.intention_evaluation.intention || \"unknown\";\r\n const confidence = r.intention_evaluation.confidence ?? 0;\r\n const rationale = r.intention_evaluation.rationale ?? \"\";\r\n\r\n // heuristic: \"strong spam\" only when BOTH spam_sales + money_signal are present\r\n // (tune this in entropy.ts; here we only consume flags)\r\n const hasSpam = flags.includes(\"spam_sales\");\r\n const hasMoneySignals =\r\n flags.includes(\"money_signal\") || flags.includes(\"money_signal_high\");\r\n const strongSpam = hasSpam && hasMoneySignals;\r\n\r\n const policy: RulesetPolicy = ruleset?.policy ?? {};\r\n\r\n const action: GateAction = decideAction({\r\n score,\r\n warnT,\r\n blockT,\r\n strongSpam,\r\n intention,\r\n flags,\r\n policy,\r\n });\r\n\r\n return {\r\n action,\r\n entropy_score: score,\r\n flags,\r\n intention,\r\n confidence: clamp01(confidence),\r\n rationale,\r\n };\r\n}\r\n\r\n// Alias “bonito” para tu server: gate(text)\r\nexport const gate = gateLLM;\r\n"],"mappings":"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","names":["clamp01","clamp01"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,11 @@ type EntropyResult$1 = {
|
|
|
2
2
|
score: number;
|
|
3
3
|
flags: string[];
|
|
4
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* Entropy = señales lingüísticas + lógicas (determinístico, barato).
|
|
7
|
+
* Nota: aquí SOLO generamos banderas y score. La acción (ALLOW/WARN/BLOCK)
|
|
8
|
+
* se decide en gate.ts según thresholds/policy del ruleset.
|
|
9
|
+
*/
|
|
5
10
|
declare function analyzeEntropy(text: string): EntropyResult$1;
|
|
6
11
|
|
|
7
12
|
type EntropyResult = {
|
|
@@ -41,13 +46,38 @@ type GateResult = {
|
|
|
41
46
|
confidence: number;
|
|
42
47
|
rationale: string;
|
|
43
48
|
};
|
|
49
|
+
type RulesetThresholds = {
|
|
50
|
+
warn?: number;
|
|
51
|
+
block?: number;
|
|
52
|
+
};
|
|
53
|
+
type RulesetPolicy = {
|
|
54
|
+
/** if true, allow strongSpam to force BLOCK */
|
|
55
|
+
strong_spam_block?: boolean;
|
|
56
|
+
/** optional overrides */
|
|
57
|
+
block_intentions?: string[];
|
|
58
|
+
warn_intentions?: string[];
|
|
59
|
+
/** flag overrides */
|
|
60
|
+
block_flags?: string[];
|
|
61
|
+
warn_flags?: string[];
|
|
62
|
+
};
|
|
63
|
+
type RulesetConfig = {
|
|
64
|
+
name?: string;
|
|
65
|
+
version?: number;
|
|
66
|
+
description?: string;
|
|
67
|
+
thresholds?: RulesetThresholds;
|
|
68
|
+
policy?: RulesetPolicy;
|
|
69
|
+
normalization?: Record<string, unknown>;
|
|
70
|
+
};
|
|
44
71
|
type GateConfig = {
|
|
72
|
+
/** Per-call threshold overrides (fallback if ruleset.thresholds not provided) */
|
|
45
73
|
warnThreshold?: number;
|
|
46
74
|
blockThreshold?: number;
|
|
75
|
+
/** Optional ruleset (default/strict/public-api) */
|
|
76
|
+
ruleset?: RulesetConfig;
|
|
47
77
|
};
|
|
48
78
|
/**
|
|
49
79
|
* Gate principal (producto): deterministic + barato.
|
|
50
80
|
*/
|
|
51
81
|
declare function gateLLM(text: string, config?: GateConfig): GateResult;
|
|
52
82
|
|
|
53
|
-
export { type EntropyResult, type FilterResult, type GateAction, type GateConfig, type GateResult, type IntentionEvaluation, analyzeEntropy, entropyMiddleware, evaluateIntention, gateLLM as gate, gateLLM, runEntropyFilter };
|
|
83
|
+
export { type EntropyResult, type FilterResult, type GateAction, type GateConfig, type GateResult, type IntentionEvaluation, type RulesetConfig, type RulesetPolicy, type RulesetThresholds, analyzeEntropy, entropyMiddleware, evaluateIntention, gateLLM as gate, gateLLM, runEntropyFilter };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ type EntropyResult$1 = {
|
|
|
2
2
|
score: number;
|
|
3
3
|
flags: string[];
|
|
4
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* Entropy = señales lingüísticas + lógicas (determinístico, barato).
|
|
7
|
+
* Nota: aquí SOLO generamos banderas y score. La acción (ALLOW/WARN/BLOCK)
|
|
8
|
+
* se decide en gate.ts según thresholds/policy del ruleset.
|
|
9
|
+
*/
|
|
5
10
|
declare function analyzeEntropy(text: string): EntropyResult$1;
|
|
6
11
|
|
|
7
12
|
type EntropyResult = {
|
|
@@ -41,13 +46,38 @@ type GateResult = {
|
|
|
41
46
|
confidence: number;
|
|
42
47
|
rationale: string;
|
|
43
48
|
};
|
|
49
|
+
type RulesetThresholds = {
|
|
50
|
+
warn?: number;
|
|
51
|
+
block?: number;
|
|
52
|
+
};
|
|
53
|
+
type RulesetPolicy = {
|
|
54
|
+
/** if true, allow strongSpam to force BLOCK */
|
|
55
|
+
strong_spam_block?: boolean;
|
|
56
|
+
/** optional overrides */
|
|
57
|
+
block_intentions?: string[];
|
|
58
|
+
warn_intentions?: string[];
|
|
59
|
+
/** flag overrides */
|
|
60
|
+
block_flags?: string[];
|
|
61
|
+
warn_flags?: string[];
|
|
62
|
+
};
|
|
63
|
+
type RulesetConfig = {
|
|
64
|
+
name?: string;
|
|
65
|
+
version?: number;
|
|
66
|
+
description?: string;
|
|
67
|
+
thresholds?: RulesetThresholds;
|
|
68
|
+
policy?: RulesetPolicy;
|
|
69
|
+
normalization?: Record<string, unknown>;
|
|
70
|
+
};
|
|
44
71
|
type GateConfig = {
|
|
72
|
+
/** Per-call threshold overrides (fallback if ruleset.thresholds not provided) */
|
|
45
73
|
warnThreshold?: number;
|
|
46
74
|
blockThreshold?: number;
|
|
75
|
+
/** Optional ruleset (default/strict/public-api) */
|
|
76
|
+
ruleset?: RulesetConfig;
|
|
47
77
|
};
|
|
48
78
|
/**
|
|
49
79
|
* Gate principal (producto): deterministic + barato.
|
|
50
80
|
*/
|
|
51
81
|
declare function gateLLM(text: string, config?: GateConfig): GateResult;
|
|
52
82
|
|
|
53
|
-
export { type EntropyResult, type FilterResult, type GateAction, type GateConfig, type GateResult, type IntentionEvaluation, analyzeEntropy, entropyMiddleware, evaluateIntention, gateLLM as gate, gateLLM, runEntropyFilter };
|
|
83
|
+
export { type EntropyResult, type FilterResult, type GateAction, type GateConfig, type GateResult, type IntentionEvaluation, type RulesetConfig, type RulesetPolicy, type RulesetThresholds, analyzeEntropy, entropyMiddleware, evaluateIntention, gateLLM as gate, gateLLM, runEntropyFilter };
|