@denizsvnc/ai-rag-engine 2.2.1 → 2.2.3
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 +31 -0
- package/dist/adapters/faq/local-faq.adapter.d.ts +2 -0
- package/dist/adapters/llm/fallback.adapter.d.ts +1 -0
- package/dist/adapters/llm/gemini.adapter.d.ts +10 -1
- package/dist/adapters/llm/openai.adapter.d.ts +12 -1
- package/dist/adapters/llm/openrouter.adapter.d.ts +4 -2
- package/dist/adapters/rules/static-rules.adapter.d.ts +6 -1
- package/dist/adapters/vector/memory-vector.adapter.d.ts +2 -0
- package/dist/api/server.js +291 -73
- package/dist/core/engine.d.ts +54 -2
- package/dist/core/metrics/rag-evaluator.d.ts +5 -0
- package/dist/core/queue/job-queue.interface.d.ts +7 -0
- package/dist/core/sml-engine.d.ts +37 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +360 -82
- package/dist/interfaces/engine-config.interface.d.ts +106 -1
- package/dist/scripts/migrate-vector.js +64 -38
- package/dist/services/document-ingestion.service.d.ts +10 -3
- package/dist/worker.js +156 -50
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -164,7 +164,36 @@ var CircuitBreakerOpenError = class extends Error {
|
|
|
164
164
|
this.name = "CircuitBreakerOpenError";
|
|
165
165
|
}
|
|
166
166
|
};
|
|
167
|
-
var
|
|
167
|
+
var SMLModelPresets = {
|
|
168
|
+
/**
|
|
169
|
+
* Ultra-fast English embedding model (~30MB q8 ONNX).
|
|
170
|
+
* Ideal for English-only workloads, low-latency semantic routing, and minimal RAM footprint.
|
|
171
|
+
*/
|
|
172
|
+
ENGLISH_FAST: "Xenova/all-MiniLM-L6-v2",
|
|
173
|
+
/**
|
|
174
|
+
* Highly recommended balanced multilingual model (~117MB q8 ONNX).
|
|
175
|
+
* Provides exceptional semantic similarity across 50+ languages including Turkish, German, English, French, and Spanish.
|
|
176
|
+
*/
|
|
177
|
+
MULTILINGUAL: "Xenova/paraphrase-multilingual-MiniLM-L12-v2",
|
|
178
|
+
/**
|
|
179
|
+
* Heavyweight high-accuracy multilingual foundation model (1024-dim, long context, 100+ languages).
|
|
180
|
+
* Highest precision across mixed-language corpora, but requires higher memory and CPU allocation.
|
|
181
|
+
*/
|
|
182
|
+
MULTILINGUAL_ACCURATE: "Xenova/bge-m3"
|
|
183
|
+
};
|
|
184
|
+
var SMLEngine = class _SMLEngine {
|
|
185
|
+
static initLockChain = Promise.resolve();
|
|
186
|
+
static async acquireInitLock() {
|
|
187
|
+
let releaseLock = () => {
|
|
188
|
+
};
|
|
189
|
+
const nextLock = new Promise((resolve) => {
|
|
190
|
+
releaseLock = resolve;
|
|
191
|
+
});
|
|
192
|
+
const currentLock = _SMLEngine.initLockChain;
|
|
193
|
+
_SMLEngine.initLockChain = currentLock.then(() => nextLock);
|
|
194
|
+
await currentLock;
|
|
195
|
+
return releaseLock;
|
|
196
|
+
}
|
|
168
197
|
modelName;
|
|
169
198
|
cacheDir;
|
|
170
199
|
localFilesOnly;
|
|
@@ -224,48 +253,62 @@ var SMLEngine = class {
|
|
|
224
253
|
console.log(`[SML CircuitBreaker] Cooldown expired. Transitioned to HALF_OPEN for probe.`);
|
|
225
254
|
}
|
|
226
255
|
if (!this.extractorPromise) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const previousCacheDir = env.cacheDir;
|
|
230
|
-
const previousAllowRemote = env.allowRemoteModels;
|
|
256
|
+
this.extractorPromise = (async () => {
|
|
257
|
+
const releaseLock = await _SMLEngine.acquireInitLock();
|
|
231
258
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
259
|
+
console.log(`[SML] Loading ${this.modelName} (dtype: ${this.dtype})...`);
|
|
260
|
+
const { pipeline: pipeline2, env } = await import("@huggingface/transformers");
|
|
261
|
+
const previousCacheDir = env.cacheDir;
|
|
262
|
+
const previousAllowRemote = env.allowRemoteModels;
|
|
263
|
+
const previousLocalModelPath = env.localModelPath;
|
|
264
|
+
try {
|
|
265
|
+
if (this.cacheDir) {
|
|
266
|
+
env.cacheDir = this.cacheDir;
|
|
267
|
+
}
|
|
268
|
+
if (this.localFilesOnly !== void 0) {
|
|
269
|
+
env.allowRemoteModels = !this.localFilesOnly;
|
|
270
|
+
}
|
|
271
|
+
const pipelineOptions = {
|
|
272
|
+
dtype: this.dtype
|
|
273
|
+
};
|
|
274
|
+
if (this.cacheDir) {
|
|
275
|
+
pipelineOptions.cache_dir = this.cacheDir;
|
|
276
|
+
}
|
|
277
|
+
if (this.localFilesOnly !== void 0) {
|
|
278
|
+
pipelineOptions.local_files_only = this.localFilesOnly;
|
|
279
|
+
}
|
|
280
|
+
const pipelineInstance = await pipeline2("feature-extraction", this.modelName, pipelineOptions);
|
|
281
|
+
this.circuitState = "CLOSED";
|
|
282
|
+
this.failureCount = 0;
|
|
283
|
+
const extract = async (text, options) => {
|
|
284
|
+
const output = await pipelineInstance(text, options);
|
|
285
|
+
const values = output.data;
|
|
286
|
+
const data = output.data instanceof Float32Array ? output.data : Float32Array.from({ length: values.length }, (_, index) => Number(values[index]));
|
|
287
|
+
return { data, dims: output.dims };
|
|
288
|
+
};
|
|
289
|
+
return extract;
|
|
290
|
+
} finally {
|
|
291
|
+
env.cacheDir = previousCacheDir;
|
|
292
|
+
env.allowRemoteModels = previousAllowRemote;
|
|
293
|
+
env.localModelPath = previousLocalModelPath;
|
|
234
294
|
}
|
|
235
|
-
|
|
236
|
-
|
|
295
|
+
} catch (err) {
|
|
296
|
+
this.failureCount++;
|
|
297
|
+
this.lastFailureTime = Date.now();
|
|
298
|
+
this.extractorPromise = null;
|
|
299
|
+
if (this.failureCount >= this.failureThreshold) {
|
|
300
|
+
this.circuitState = "OPEN";
|
|
301
|
+
console.error(
|
|
302
|
+
`[SML CircuitBreaker] \u26A0\uFE0F Tripped to OPEN state! Model failed ${this.failureCount} times. Pausing requests for ${this.cooldownMs / 1e3}s.`
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
console.error(`[SML] Model loading error (attempt ${this.failureCount}/${this.failureThreshold}):`, err);
|
|
237
306
|
}
|
|
238
|
-
|
|
239
|
-
dtype: this.dtype
|
|
240
|
-
});
|
|
307
|
+
throw err;
|
|
241
308
|
} finally {
|
|
242
|
-
|
|
243
|
-
env.allowRemoteModels = previousAllowRemote;
|
|
244
|
-
}
|
|
245
|
-
}).then((pipelineInstance) => {
|
|
246
|
-
this.circuitState = "CLOSED";
|
|
247
|
-
this.failureCount = 0;
|
|
248
|
-
const extract = async (text, options) => {
|
|
249
|
-
const output = await pipelineInstance(text, options);
|
|
250
|
-
const values = output.data;
|
|
251
|
-
const data = output.data instanceof Float32Array ? output.data : Float32Array.from({ length: values.length }, (_, index) => Number(values[index]));
|
|
252
|
-
return { data, dims: output.dims };
|
|
253
|
-
};
|
|
254
|
-
return extract;
|
|
255
|
-
}).catch((err) => {
|
|
256
|
-
this.failureCount++;
|
|
257
|
-
this.lastFailureTime = Date.now();
|
|
258
|
-
this.extractorPromise = null;
|
|
259
|
-
if (this.failureCount >= this.failureThreshold) {
|
|
260
|
-
this.circuitState = "OPEN";
|
|
261
|
-
console.error(
|
|
262
|
-
`[SML CircuitBreaker] \u26A0\uFE0F Tripped to OPEN state! Model failed ${this.failureCount} times. Pausing requests for ${this.cooldownMs / 1e3}s.`
|
|
263
|
-
);
|
|
264
|
-
} else {
|
|
265
|
-
console.error(`[SML] Model loading error (attempt ${this.failureCount}/${this.failureThreshold}):`, err);
|
|
309
|
+
releaseLock();
|
|
266
310
|
}
|
|
267
|
-
|
|
268
|
-
});
|
|
311
|
+
})();
|
|
269
312
|
}
|
|
270
313
|
return this.extractorPromise;
|
|
271
314
|
}
|
|
@@ -531,11 +574,11 @@ var InjectionDetector = class {
|
|
|
531
574
|
// 2. Jailbreaks, DAN modes, role hijacking
|
|
532
575
|
{
|
|
533
576
|
id: "JAILBREAK_MODE_EN",
|
|
534
|
-
regex: /\b(you\s+are\s+now|act\s+as|switch\s+to|enter)\s+(an?\s+)?(developer|dan|jailbreak|unrestricted|unfiltered|god)\s*(mode|persona|ai)?\b/i
|
|
577
|
+
regex: /\b(you\s+are\s+now|act\s+as|switch\s+to|enter)\s+(in\s+(an?\s+)?|an?\s+)?(developer|dan|jailbreak|unrestricted|unfiltered|god)\s*(mode|persona|ai)?\b/i
|
|
535
578
|
},
|
|
536
579
|
{
|
|
537
580
|
id: "JAILBREAK_MODE_TR",
|
|
538
|
-
regex:
|
|
581
|
+
regex: /(?:^|\s|[.,!?])(artık|şimdi)\s+(bir\s+)?(geliştirici|dan|kısıtlamasız|admin|jailbreak)\s+(modundasın|moduna\s+geç|olarak\s+davran)(?:$|\s|[.,!?])/i
|
|
539
582
|
},
|
|
540
583
|
{
|
|
541
584
|
id: "DISABLE_SAFETY_EN",
|
|
@@ -1207,6 +1250,8 @@ import fs3 from "node:fs";
|
|
|
1207
1250
|
import fsp from "node:fs/promises";
|
|
1208
1251
|
import path3 from "node:path";
|
|
1209
1252
|
import os from "node:os";
|
|
1253
|
+
import zlib from "node:zlib";
|
|
1254
|
+
import { StringDecoder } from "node:string_decoder";
|
|
1210
1255
|
|
|
1211
1256
|
// src/core/queue/in-memory-queue.ts
|
|
1212
1257
|
import { randomUUID } from "node:crypto";
|
|
@@ -1458,17 +1503,71 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1458
1503
|
* - Performs binary artifact suppression and multi-lingual UTF-8 normalization (Turkish, European, and CJK diacritics).
|
|
1459
1504
|
*/
|
|
1460
1505
|
static extractText(filename, buffer) {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
return _DocumentIngestionService.extractPdfText(rawString);
|
|
1506
|
+
if (buffer.length >= 4 && buffer.subarray(0, 4).toString() === "%PDF") {
|
|
1507
|
+
return _DocumentIngestionService.extractPdfText(buffer);
|
|
1464
1508
|
}
|
|
1465
|
-
return
|
|
1509
|
+
return buffer.toString("utf-8").trim();
|
|
1466
1510
|
}
|
|
1467
1511
|
/**
|
|
1468
|
-
* Enterprise High-Efficiency PDF Lexical Extractor.
|
|
1469
|
-
*
|
|
1512
|
+
* Enterprise High-Efficiency PDF Lexical Extractor with native zlib.inflate decompression.
|
|
1513
|
+
* Decodes and parses PDF content streams without heavy external C++/WASM dependencies.
|
|
1514
|
+
*
|
|
1515
|
+
* Supports:
|
|
1516
|
+
* - Decompression of compressed stream objects (/Filter /FlateDecode) via Node.js native zlib.
|
|
1517
|
+
* - BT (Begin Text) ... ET (End Text) matrices.
|
|
1518
|
+
* - TJ array operators with kerning spacing preservation.
|
|
1519
|
+
* - Literal (Tj) and hexadecimal (<hex> Tj) text operators with escape and octal decoding.
|
|
1470
1520
|
*/
|
|
1471
1521
|
static extractPdfText(rawContent) {
|
|
1522
|
+
const buffer = Buffer.isBuffer(rawContent) ? rawContent : Buffer.from(rawContent, "latin1");
|
|
1523
|
+
const decompressedStreams = [];
|
|
1524
|
+
const streamMarker = Buffer.from("stream");
|
|
1525
|
+
const endStreamMarker = Buffer.from("endstream");
|
|
1526
|
+
let pos = 0;
|
|
1527
|
+
while (pos < buffer.length) {
|
|
1528
|
+
const streamIdx = buffer.indexOf(streamMarker, pos);
|
|
1529
|
+
if (streamIdx === -1) break;
|
|
1530
|
+
const prevChar = streamIdx > 0 ? buffer[streamIdx - 1] : 32;
|
|
1531
|
+
if (prevChar !== 10 && prevChar !== 13 && prevChar !== 32 && prevChar !== 62) {
|
|
1532
|
+
pos = streamIdx + 6;
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
let dataStart = streamIdx + 6;
|
|
1536
|
+
if (buffer[dataStart] === 13 && buffer[dataStart + 1] === 10) {
|
|
1537
|
+
dataStart += 2;
|
|
1538
|
+
} else if (buffer[dataStart] === 10 || buffer[dataStart] === 13) {
|
|
1539
|
+
dataStart += 1;
|
|
1540
|
+
}
|
|
1541
|
+
const endIdx = buffer.indexOf(endStreamMarker, dataStart);
|
|
1542
|
+
if (endIdx === -1) break;
|
|
1543
|
+
let dataEnd = endIdx;
|
|
1544
|
+
while (dataEnd > dataStart && (buffer[dataEnd - 1] === 10 || buffer[dataEnd - 1] === 13 || buffer[dataEnd - 1] === 32)) {
|
|
1545
|
+
dataEnd--;
|
|
1546
|
+
}
|
|
1547
|
+
const streamBytes = buffer.subarray(dataStart, dataEnd);
|
|
1548
|
+
const dictStart = Math.max(0, streamIdx - 500);
|
|
1549
|
+
const dictSnippet = buffer.subarray(dictStart, streamIdx).toString("latin1");
|
|
1550
|
+
const isFlate = /\/Filter\s*(?:\[\s*)?\/(?:FlateDecode|Fl)\b/.test(dictSnippet) || !/\/Filter\b/.test(dictSnippet);
|
|
1551
|
+
let decoded = "";
|
|
1552
|
+
if (isFlate && streamBytes.length > 0) {
|
|
1553
|
+
try {
|
|
1554
|
+
decoded = zlib.inflateSync(streamBytes).toString("utf-8");
|
|
1555
|
+
} catch {
|
|
1556
|
+
try {
|
|
1557
|
+
decoded = zlib.inflateRawSync(streamBytes).toString("utf-8");
|
|
1558
|
+
} catch {
|
|
1559
|
+
decoded = streamBytes.toString("utf-8");
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
} else {
|
|
1563
|
+
decoded = streamBytes.toString("utf-8");
|
|
1564
|
+
}
|
|
1565
|
+
if (decoded && decoded.trim().length > 0) {
|
|
1566
|
+
decompressedStreams.push(decoded);
|
|
1567
|
+
}
|
|
1568
|
+
pos = endIdx + 9;
|
|
1569
|
+
}
|
|
1570
|
+
const contentToScan = [buffer.toString("latin1"), ...decompressedStreams].join("\n");
|
|
1472
1571
|
const extractedSegments = [];
|
|
1473
1572
|
const decodePdfLiteral = (encoded) => {
|
|
1474
1573
|
return encoded.replace(/\\([0-7]{1,3})/g, (_, oct) => String.fromCharCode(parseInt(oct, 8))).replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\b/g, "\b").replace(/\\f/g, "\f").replace(/\\\(/g, "(").replace(/\\\)/g, ")").replace(/\\\\/g, "\\");
|
|
@@ -1483,7 +1582,7 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1483
1582
|
};
|
|
1484
1583
|
const btEtRegex = /BT[\s\S]*?ET/g;
|
|
1485
1584
|
let btMatch;
|
|
1486
|
-
while ((btMatch = btEtRegex.exec(
|
|
1585
|
+
while ((btMatch = btEtRegex.exec(contentToScan)) !== null) {
|
|
1487
1586
|
const blockContent = btMatch[0];
|
|
1488
1587
|
const tjArrayRegex = /\[([\s\S]*?)\]\s*TJ/g;
|
|
1489
1588
|
let tjArrMatch;
|
|
@@ -1528,7 +1627,7 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1528
1627
|
if (extractedSegments.length > 0) {
|
|
1529
1628
|
return extractedSegments.join(" ").replace(/\s+/g, " ").trim();
|
|
1530
1629
|
}
|
|
1531
|
-
const cleaned =
|
|
1630
|
+
const cleaned = contentToScan.replace(/%PDF-[^\n]+/g, "").replace(/stream[\s\S]*?endstream/g, (streamObj) => {
|
|
1532
1631
|
const innerMatch = streamObj.match(/\((.*?)\)/g);
|
|
1533
1632
|
return innerMatch ? innerMatch.map((s) => decodePdfLiteral(s.slice(1, -1))).join(" ") : "";
|
|
1534
1633
|
}).replace(/obj[\s\S]*?endobj/g, (obj) => {
|
|
@@ -1538,8 +1637,17 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1538
1637
|
return cleaned || "PDF document with no extractable plain text stream.";
|
|
1539
1638
|
}
|
|
1540
1639
|
static chunkText(text, chunkSize = 500, overlap = 50) {
|
|
1541
|
-
if (!
|
|
1542
|
-
|
|
1640
|
+
if (!Number.isFinite(chunkSize) || chunkSize <= 0) {
|
|
1641
|
+
throw new RangeError(`[DocumentIngestionService] chunkSize must be a positive integer greater than 0. Received: ${chunkSize}`);
|
|
1642
|
+
}
|
|
1643
|
+
if (!Number.isFinite(overlap) || overlap < 0 || overlap >= chunkSize) {
|
|
1644
|
+
throw new RangeError(`[DocumentIngestionService] overlap must be non-negative and strictly less than chunkSize (${chunkSize}). Received: ${overlap}`);
|
|
1645
|
+
}
|
|
1646
|
+
if (!text || text.trim().length === 0) {
|
|
1647
|
+
return [];
|
|
1648
|
+
}
|
|
1649
|
+
if (text.length <= chunkSize) {
|
|
1650
|
+
return [text.trim()];
|
|
1543
1651
|
}
|
|
1544
1652
|
const chunks = [];
|
|
1545
1653
|
let startIndex = 0;
|
|
@@ -1561,6 +1669,9 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1561
1669
|
if (chunk.length > 0) {
|
|
1562
1670
|
chunks.push(chunk);
|
|
1563
1671
|
}
|
|
1672
|
+
if (endIndex >= text.length) {
|
|
1673
|
+
break;
|
|
1674
|
+
}
|
|
1564
1675
|
startIndex = Math.max(startIndex + 1, endIndex - overlap);
|
|
1565
1676
|
}
|
|
1566
1677
|
return chunks;
|
|
@@ -1569,11 +1680,19 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1569
1680
|
* Streaming chunk generator.
|
|
1570
1681
|
* Ingests chunks of text or buffers incrementally with natural backpressure,
|
|
1571
1682
|
* maintaining a constant O(1) memory footprint regardless of file size.
|
|
1683
|
+
* Preserves UTF-8 multibyte character boundaries across stream buffer splits.
|
|
1572
1684
|
*/
|
|
1573
1685
|
static async *chunkStream(textStream, chunkSize = 500, overlap = 50) {
|
|
1686
|
+
if (!Number.isFinite(chunkSize) || chunkSize <= 0) {
|
|
1687
|
+
throw new RangeError(`[DocumentIngestionService] chunkSize must be a positive integer greater than 0. Received: ${chunkSize}`);
|
|
1688
|
+
}
|
|
1689
|
+
if (!Number.isFinite(overlap) || overlap < 0 || overlap >= chunkSize) {
|
|
1690
|
+
throw new RangeError(`[DocumentIngestionService] overlap must be non-negative and strictly less than chunkSize (${chunkSize}). Received: ${overlap}`);
|
|
1691
|
+
}
|
|
1692
|
+
const decoder = new StringDecoder("utf-8");
|
|
1574
1693
|
let window = "";
|
|
1575
1694
|
for await (const rawChunk of textStream) {
|
|
1576
|
-
const chunkStr = Buffer.isBuffer(rawChunk) ?
|
|
1695
|
+
const chunkStr = Buffer.isBuffer(rawChunk) ? decoder.write(rawChunk) : String(rawChunk);
|
|
1577
1696
|
window += chunkStr;
|
|
1578
1697
|
while (window.length >= chunkSize) {
|
|
1579
1698
|
let endIndex = chunkSize;
|
|
@@ -1591,9 +1710,13 @@ var DocumentIngestionService = class _DocumentIngestionService {
|
|
|
1591
1710
|
if (emitted.length > 0) {
|
|
1592
1711
|
yield emitted;
|
|
1593
1712
|
}
|
|
1594
|
-
window = window.slice(Math.max(
|
|
1713
|
+
window = window.slice(Math.max(0, endIndex - overlap));
|
|
1595
1714
|
}
|
|
1596
1715
|
}
|
|
1716
|
+
const flushed = decoder.end();
|
|
1717
|
+
if (flushed) {
|
|
1718
|
+
window += flushed;
|
|
1719
|
+
}
|
|
1597
1720
|
const remaining = window.trim();
|
|
1598
1721
|
if (remaining.length > 0) {
|
|
1599
1722
|
yield remaining;
|
|
@@ -1941,6 +2064,12 @@ var MemoryVectorAdapter = class {
|
|
|
1941
2064
|
smlEngine;
|
|
1942
2065
|
documents = [];
|
|
1943
2066
|
bm25Index = new BM25Index();
|
|
2067
|
+
setSMLEngine(engine) {
|
|
2068
|
+
this.smlEngine = engine;
|
|
2069
|
+
}
|
|
2070
|
+
getSMLEngine() {
|
|
2071
|
+
return this.smlEngine;
|
|
2072
|
+
}
|
|
1944
2073
|
/**
|
|
1945
2074
|
* Adds documents to memory, computes their embeddings, and indexes them in BM25.
|
|
1946
2075
|
*/
|
|
@@ -2025,6 +2154,11 @@ var MemoryVectorAdapter = class {
|
|
|
2025
2154
|
|
|
2026
2155
|
// src/core/engine.ts
|
|
2027
2156
|
var RAGEngine = class {
|
|
2157
|
+
/**
|
|
2158
|
+
* Initializes a new instance of `RAGEngine` with the provided configuration.
|
|
2159
|
+
*
|
|
2160
|
+
* @param config - The engine configuration options (`EngineConfig`).
|
|
2161
|
+
*/
|
|
2028
2162
|
constructor(config) {
|
|
2029
2163
|
this.config = config;
|
|
2030
2164
|
if (config.tools?.items.some((tool) => tool.isMutating || tool.requiresConfirmation)) {
|
|
@@ -2040,8 +2174,22 @@ var RAGEngine = class {
|
|
|
2040
2174
|
config.cache?.ttlMs || 1e3 * 60 * 60 * 24
|
|
2041
2175
|
);
|
|
2042
2176
|
}
|
|
2043
|
-
this.smlEngine = new SMLEngine({
|
|
2177
|
+
this.smlEngine = new SMLEngine({
|
|
2178
|
+
modelName: config.smlConfig?.modelName,
|
|
2179
|
+
dtype: config.smlConfig?.dtype,
|
|
2180
|
+
cacheDir: config.smlConfig?.cacheDir,
|
|
2181
|
+
localFilesOnly: config.smlConfig?.localFilesOnly,
|
|
2182
|
+
cacheSize: config.smlConfig?.cacheSize,
|
|
2183
|
+
circuitBreakerThreshold: config.smlConfig?.circuitBreakerThreshold,
|
|
2184
|
+
circuitBreakerCooldownMs: config.smlConfig?.circuitBreakerCooldownMs
|
|
2185
|
+
});
|
|
2044
2186
|
const vectorStore = config.inputs?.vectorStore || new MemoryVectorAdapter(this.smlEngine);
|
|
2187
|
+
if (typeof vectorStore.setSMLEngine === "function") {
|
|
2188
|
+
vectorStore.setSMLEngine(this.smlEngine);
|
|
2189
|
+
}
|
|
2190
|
+
if (config.inputs?.faq && typeof config.inputs.faq.setSMLEngine === "function") {
|
|
2191
|
+
config.inputs.faq.setSMLEngine(this.smlEngine);
|
|
2192
|
+
}
|
|
2045
2193
|
this.config = {
|
|
2046
2194
|
...config,
|
|
2047
2195
|
inputs: {
|
|
@@ -2139,8 +2287,27 @@ var RAGEngine = class {
|
|
|
2139
2287
|
await this.toolRegistry.registerTool(tool);
|
|
2140
2288
|
}
|
|
2141
2289
|
/**
|
|
2142
|
-
* Executes the query lifecycle:
|
|
2143
|
-
* Security
|
|
2290
|
+
* Executes the complete RAG query lifecycle:
|
|
2291
|
+
* 1. Security Inspection (Prompt Injection Defense, PII Masking)
|
|
2292
|
+
* 2. Cache Lookup (Role & Tenant isolated caching)
|
|
2293
|
+
* 3. SML Semantic Routing (FAQ matching and Tool execution)
|
|
2294
|
+
* 4. Hybrid Dense/Sparse Retrieval (Vector search + BM25 keyword search)
|
|
2295
|
+
* 5. Untrusted Boundary Framing (Anti-indirect injection prompt wrapping)
|
|
2296
|
+
* 6. LLM Answer Synthesis & Citation Tagging
|
|
2297
|
+
*
|
|
2298
|
+
* @param userPrompt - The natural language query or question from the user.
|
|
2299
|
+
* @param context - Optional multi-tenant security context including `tenantId`, `userId`, and `roles`.
|
|
2300
|
+
* @returns Promise resolving to `RAGResponse` containing synthesized answer, citations, intent, and metrics.
|
|
2301
|
+
*
|
|
2302
|
+
* @example
|
|
2303
|
+
* ```typescript
|
|
2304
|
+
* const response = await engine.query('What is our return policy?', {
|
|
2305
|
+
* tenantId: 'tenant_123',
|
|
2306
|
+
* userId: 'usr_456',
|
|
2307
|
+
* roles: ['customer']
|
|
2308
|
+
* });
|
|
2309
|
+
* console.log(response.answer);
|
|
2310
|
+
* ```
|
|
2144
2311
|
*/
|
|
2145
2312
|
async query(userPrompt, context) {
|
|
2146
2313
|
const startTime = Date.now();
|
|
@@ -2577,7 +2744,9 @@ var RAGEvaluator = class {
|
|
|
2577
2744
|
* Proportion of retrieved documents in the top-K that are genuinely relevant.
|
|
2578
2745
|
*/
|
|
2579
2746
|
static precisionAtK(retrievedIds, relevantIds, k = 3) {
|
|
2580
|
-
|
|
2747
|
+
if (!Number.isFinite(k) || k <= 0) return 0;
|
|
2748
|
+
const uniqueRetrieved = Array.from(new Set(retrievedIds));
|
|
2749
|
+
const topK = uniqueRetrieved.slice(0, k);
|
|
2581
2750
|
if (topK.length === 0) return 0;
|
|
2582
2751
|
const relevantSet = new Set(relevantIds);
|
|
2583
2752
|
const hits = topK.filter((id) => relevantSet.has(id)).length;
|
|
@@ -2589,7 +2758,9 @@ var RAGEvaluator = class {
|
|
|
2589
2758
|
*/
|
|
2590
2759
|
static recallAtK(retrievedIds, relevantIds, k = 3) {
|
|
2591
2760
|
if (relevantIds.length === 0) return 1;
|
|
2592
|
-
|
|
2761
|
+
if (!Number.isFinite(k) || k <= 0) return 0;
|
|
2762
|
+
const uniqueRetrieved = Array.from(new Set(retrievedIds));
|
|
2763
|
+
const topK = uniqueRetrieved.slice(0, k);
|
|
2593
2764
|
const relevantSet = new Set(relevantIds);
|
|
2594
2765
|
const hits = topK.filter((id) => relevantSet.has(id)).length;
|
|
2595
2766
|
return Number((hits / relevantIds.length).toFixed(4));
|
|
@@ -2623,28 +2794,44 @@ var RAGEvaluator = class {
|
|
|
2623
2794
|
groundingScore: res.score
|
|
2624
2795
|
};
|
|
2625
2796
|
}
|
|
2797
|
+
/**
|
|
2798
|
+
* Evaluates Answer Faithfulness / Groundedness using deterministic heuristics.
|
|
2799
|
+
* Note: This measures lexical consistency, numerical overlap, and negation polarity.
|
|
2800
|
+
* It serves as a fast in-process heuristic filter and is not an external semantic LLM judge.
|
|
2801
|
+
*/
|
|
2626
2802
|
static evaluateFaithfulness(answer, contextTexts) {
|
|
2803
|
+
if (!answer || answer.trim().length === 0) {
|
|
2804
|
+
return {
|
|
2805
|
+
score: 0,
|
|
2806
|
+
lexicalGroundingScore: 0,
|
|
2807
|
+
totalSentences: 0,
|
|
2808
|
+
groundedSentences: 0,
|
|
2809
|
+
contradictionsDetected: [],
|
|
2810
|
+
ungroundedClaims: ["Empty answer provided"]
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2627
2813
|
const combinedContext = contextTexts.join(" ").toLowerCase();
|
|
2628
2814
|
const contextClean = combinedContext.replace(/[^\p{L}\p{N}\s]/gu, " ");
|
|
2629
2815
|
const contextWordTokens = new Set(contextClean.split(/\s+/).filter((w) => w.length > 2));
|
|
2630
2816
|
const contextNumbers = new Set(
|
|
2631
2817
|
(combinedContext.match(/\b\d+(?:[\.,]\d+)?\b/g) || []).map((n) => n.replace(",", "."))
|
|
2632
2818
|
);
|
|
2633
|
-
const sentences = answer.split(/(?<=[.!?])\s+/).map((s) => s.trim()).filter((s) => s.length >
|
|
2819
|
+
const sentences = answer.split(/(?<=[.!?])\s+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2634
2820
|
if (sentences.length === 0) {
|
|
2635
2821
|
return {
|
|
2636
|
-
score:
|
|
2637
|
-
lexicalGroundingScore:
|
|
2822
|
+
score: 0,
|
|
2823
|
+
lexicalGroundingScore: 0,
|
|
2638
2824
|
totalSentences: 0,
|
|
2639
2825
|
groundedSentences: 0,
|
|
2640
2826
|
contradictionsDetected: [],
|
|
2641
|
-
ungroundedClaims: []
|
|
2827
|
+
ungroundedClaims: ["No meaningful sentences detected"]
|
|
2642
2828
|
};
|
|
2643
2829
|
}
|
|
2644
2830
|
const ungroundedClaims = [];
|
|
2645
2831
|
const contradictionsDetected = [];
|
|
2646
2832
|
let groundedCount = 0;
|
|
2647
2833
|
let totalLexicalOverlapSum = 0;
|
|
2834
|
+
const negationTokens = /* @__PURE__ */ new Set(["not", "never", "cannot", "de\u011Fil", "yok", "olumsuz", "asla", "hay\u0131r"]);
|
|
2648
2835
|
for (const sentence of sentences) {
|
|
2649
2836
|
const lowerSentence = sentence.toLowerCase();
|
|
2650
2837
|
const sentenceNumbers = (lowerSentence.match(/\b\d+(?:[\.,]\d+)?\b/g) || []).map((n) => n.replace(",", "."));
|
|
@@ -2658,16 +2845,28 @@ var RAGEvaluator = class {
|
|
|
2658
2845
|
break;
|
|
2659
2846
|
}
|
|
2660
2847
|
}
|
|
2661
|
-
const
|
|
2848
|
+
const rawWords = lowerSentence.replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 0);
|
|
2849
|
+
const sentenceNegations = rawWords.filter((w) => negationTokens.has(w));
|
|
2850
|
+
let hasNegationMismatch = false;
|
|
2851
|
+
if (sentenceNegations.length > 0) {
|
|
2852
|
+
const contextHasNegation = sentenceNegations.some((neg) => contextWordTokens.has(neg) || combinedContext.includes(neg));
|
|
2853
|
+
if (!contextHasNegation) {
|
|
2854
|
+
hasNegationMismatch = true;
|
|
2855
|
+
contradictionsDetected.push(
|
|
2856
|
+
`Polarity Warning: Negation '${sentenceNegations.join(", ")}' in "${sentence}" absent from retrieved context.`
|
|
2857
|
+
);
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
const words = rawWords.filter((w) => w.length > 2);
|
|
2662
2861
|
if (words.length === 0) {
|
|
2663
|
-
if (!hasNumberContradiction) groundedCount++;
|
|
2862
|
+
if (!hasNumberContradiction && !hasNegationMismatch) groundedCount++;
|
|
2664
2863
|
totalLexicalOverlapSum += 1;
|
|
2665
2864
|
continue;
|
|
2666
2865
|
}
|
|
2667
2866
|
const groundedWords = words.filter((word) => contextWordTokens.has(word) || combinedContext.includes(word));
|
|
2668
2867
|
const overlapRatio = groundedWords.length / words.length;
|
|
2669
2868
|
totalLexicalOverlapSum += overlapRatio;
|
|
2670
|
-
if (overlapRatio >= 0.4 && !hasNumberContradiction) {
|
|
2869
|
+
if (overlapRatio >= 0.4 && !hasNumberContradiction && !hasNegationMismatch) {
|
|
2671
2870
|
groundedCount++;
|
|
2672
2871
|
} else {
|
|
2673
2872
|
ungroundedClaims.push(sentence);
|
|
@@ -2708,6 +2907,15 @@ var RAGEvaluator = class {
|
|
|
2708
2907
|
}
|
|
2709
2908
|
};
|
|
2710
2909
|
|
|
2910
|
+
// src/core/queue/job-queue.interface.ts
|
|
2911
|
+
var JobStatusValues = {
|
|
2912
|
+
PENDING: "pending",
|
|
2913
|
+
QUEUED: "queued",
|
|
2914
|
+
PROCESSING: "processing",
|
|
2915
|
+
COMPLETED: "completed",
|
|
2916
|
+
FAILED: "failed"
|
|
2917
|
+
};
|
|
2918
|
+
|
|
2711
2919
|
// src/core/queue/bullmq-queue.ts
|
|
2712
2920
|
import { Queue, Worker, UnrecoverableError } from "bullmq";
|
|
2713
2921
|
import { Redis } from "ioredis";
|
|
@@ -3389,13 +3597,29 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
3389
3597
|
apiKey;
|
|
3390
3598
|
model;
|
|
3391
3599
|
endpoint;
|
|
3392
|
-
|
|
3393
|
-
|
|
3600
|
+
temperature;
|
|
3601
|
+
constructor(configOrApiKey, model, endpoint) {
|
|
3602
|
+
let key = "";
|
|
3603
|
+
let resolvedModel = "";
|
|
3604
|
+
let resolvedEndpoint = "";
|
|
3605
|
+
let temp = 0.1;
|
|
3606
|
+
if (typeof configOrApiKey === "object" && configOrApiKey !== null) {
|
|
3607
|
+
key = configOrApiKey.apiKey || process.env.OPENAI_API_KEY || "";
|
|
3608
|
+
resolvedModel = configOrApiKey.model || process.env.OPENAI_MODEL || process.env.OPENAI_MODEL_FAST || "gpt-4o-mini";
|
|
3609
|
+
resolvedEndpoint = configOrApiKey.endpoint || process.env.OPENAI_ENDPOINT || "https://api.openai.com/v1/chat/completions";
|
|
3610
|
+
if (configOrApiKey.temperature !== void 0) temp = configOrApiKey.temperature;
|
|
3611
|
+
} else {
|
|
3612
|
+
key = configOrApiKey || process.env.OPENAI_API_KEY || "";
|
|
3613
|
+
resolvedModel = model || process.env.OPENAI_MODEL || process.env.OPENAI_MODEL_FAST || "gpt-4o-mini";
|
|
3614
|
+
resolvedEndpoint = endpoint || process.env.OPENAI_ENDPOINT || "https://api.openai.com/v1/chat/completions";
|
|
3615
|
+
}
|
|
3616
|
+
this.apiKey = key;
|
|
3394
3617
|
if (!this.apiKey) {
|
|
3395
3618
|
throw new Error("[OpenAIAdapter] API Key not found. Provide it in constructor or set OPENAI_API_KEY in .env");
|
|
3396
3619
|
}
|
|
3397
|
-
this.model =
|
|
3398
|
-
this.endpoint =
|
|
3620
|
+
this.model = resolvedModel;
|
|
3621
|
+
this.endpoint = resolvedEndpoint;
|
|
3622
|
+
this.temperature = temp;
|
|
3399
3623
|
}
|
|
3400
3624
|
static createFast(apiKey) {
|
|
3401
3625
|
return new _OpenAIAdapter(apiKey, process.env.OPENAI_MODEL_FAST || "gpt-4o-mini");
|
|
@@ -3411,7 +3635,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
3411
3635
|
const body = {
|
|
3412
3636
|
model: this.model,
|
|
3413
3637
|
messages,
|
|
3414
|
-
temperature:
|
|
3638
|
+
temperature: this.temperature
|
|
3415
3639
|
// Low temperature to reduce hallucination in RAG pipelines
|
|
3416
3640
|
};
|
|
3417
3641
|
if (request.tools && request.tools.length > 0) {
|
|
@@ -3461,15 +3685,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
3461
3685
|
var GeminiAdapter = class _GeminiAdapter {
|
|
3462
3686
|
apiKey;
|
|
3463
3687
|
model;
|
|
3464
|
-
|
|
3465
|
-
|
|
3688
|
+
temperature;
|
|
3689
|
+
constructor(configOrApiKey, model) {
|
|
3690
|
+
let key = "";
|
|
3691
|
+
let resolvedModel = "";
|
|
3692
|
+
let temp = 0.1;
|
|
3693
|
+
if (typeof configOrApiKey === "object" && configOrApiKey !== null) {
|
|
3694
|
+
key = configOrApiKey.apiKey || process.env.GEMINI_API_KEY || "";
|
|
3695
|
+
resolvedModel = configOrApiKey.model || process.env.GEMINI_MODEL || process.env.GEMINI_MODEL_FAST || "gemini-2.0-flash";
|
|
3696
|
+
if (configOrApiKey.temperature !== void 0) temp = configOrApiKey.temperature;
|
|
3697
|
+
} else {
|
|
3698
|
+
key = configOrApiKey || process.env.GEMINI_API_KEY || "";
|
|
3699
|
+
resolvedModel = model || process.env.GEMINI_MODEL || process.env.GEMINI_MODEL_FAST || "gemini-2.0-flash";
|
|
3700
|
+
}
|
|
3701
|
+
this.apiKey = key;
|
|
3466
3702
|
if (!this.apiKey) {
|
|
3467
3703
|
throw new Error("[GeminiAdapter] API Key not found. Provide it in constructor or set GEMINI_API_KEY in .env");
|
|
3468
3704
|
}
|
|
3469
|
-
this.model =
|
|
3705
|
+
this.model = resolvedModel;
|
|
3706
|
+
this.temperature = temp;
|
|
3470
3707
|
}
|
|
3471
3708
|
static createFast(apiKey) {
|
|
3472
|
-
return new _GeminiAdapter(apiKey, process.env.GEMINI_MODEL_FAST || "gemini-
|
|
3709
|
+
return new _GeminiAdapter(apiKey, process.env.GEMINI_MODEL_FAST || "gemini-2.0-flash");
|
|
3473
3710
|
}
|
|
3474
3711
|
static createSmart(apiKey) {
|
|
3475
3712
|
return new _GeminiAdapter(apiKey, process.env.GEMINI_MODEL_SMART || "gemini-1.5-pro");
|
|
@@ -3484,7 +3721,7 @@ var GeminiAdapter = class _GeminiAdapter {
|
|
|
3484
3721
|
}
|
|
3485
3722
|
],
|
|
3486
3723
|
generationConfig: {
|
|
3487
|
-
temperature:
|
|
3724
|
+
temperature: this.temperature
|
|
3488
3725
|
// Low temperature to reduce hallucination in RAG pipelines
|
|
3489
3726
|
}
|
|
3490
3727
|
};
|
|
@@ -3548,18 +3785,34 @@ var GeminiAdapter = class _GeminiAdapter {
|
|
|
3548
3785
|
|
|
3549
3786
|
// src/adapters/llm/openrouter.adapter.ts
|
|
3550
3787
|
var OpenRouterAdapter = class _OpenRouterAdapter extends OpenAIAdapter {
|
|
3551
|
-
constructor(
|
|
3788
|
+
constructor(configOrApiKey, model, endpoint = "https://openrouter.ai/api/v1/chat/completions") {
|
|
3552
3789
|
if (process.env.ALLOW_PUBLIC_OPENSOURCE_LLM === "false") {
|
|
3553
3790
|
throw new Error(
|
|
3554
3791
|
"[OpenRouterAdapter] Blocked by security policy: ALLOW_PUBLIC_OPENSOURCE_LLM is set to false in .env. Corporate prompts cannot be routed to public external open-source models."
|
|
3555
3792
|
);
|
|
3556
3793
|
}
|
|
3557
|
-
|
|
3794
|
+
let key = "";
|
|
3795
|
+
let resolvedModel = "";
|
|
3796
|
+
let resolvedEndpoint = endpoint;
|
|
3797
|
+
let temp = 0.1;
|
|
3798
|
+
if (typeof configOrApiKey === "object" && configOrApiKey !== null) {
|
|
3799
|
+
key = configOrApiKey.apiKey || process.env.OPENROUTER_API_KEY || "";
|
|
3800
|
+
resolvedModel = configOrApiKey.model || process.env.OPENROUTER_MODEL || process.env.OPENROUTER_MODEL_FAST || "meta-llama/llama-3.2-3b-instruct:free";
|
|
3801
|
+
if (configOrApiKey.endpoint) resolvedEndpoint = configOrApiKey.endpoint;
|
|
3802
|
+
if (configOrApiKey.temperature !== void 0) temp = configOrApiKey.temperature;
|
|
3803
|
+
} else {
|
|
3804
|
+
key = configOrApiKey || process.env.OPENROUTER_API_KEY || "";
|
|
3805
|
+
resolvedModel = model || process.env.OPENROUTER_MODEL || process.env.OPENROUTER_MODEL_FAST || "meta-llama/llama-3.2-3b-instruct:free";
|
|
3806
|
+
}
|
|
3558
3807
|
if (!key) {
|
|
3559
3808
|
throw new Error("[OpenRouterAdapter] API Key not found. Provide it in constructor or set OPENROUTER_API_KEY in .env");
|
|
3560
3809
|
}
|
|
3561
|
-
|
|
3562
|
-
|
|
3810
|
+
super({
|
|
3811
|
+
apiKey: key,
|
|
3812
|
+
model: resolvedModel,
|
|
3813
|
+
endpoint: resolvedEndpoint,
|
|
3814
|
+
temperature: temp
|
|
3815
|
+
});
|
|
3563
3816
|
}
|
|
3564
3817
|
static createFast(apiKey) {
|
|
3565
3818
|
return new _OpenRouterAdapter(apiKey, process.env.OPENROUTER_MODEL_FAST || "meta-llama/llama-3.2-3b-instruct:free");
|
|
@@ -3716,11 +3969,24 @@ var FallbackLLMProvider = class {
|
|
|
3716
3969
|
this.providers = providers;
|
|
3717
3970
|
this.logFailover = options?.logFailover ?? true;
|
|
3718
3971
|
}
|
|
3972
|
+
getProviderName(provider, index) {
|
|
3973
|
+
if (provider.name && typeof provider.name === "string") {
|
|
3974
|
+
return provider.name;
|
|
3975
|
+
}
|
|
3976
|
+
if (provider.model && typeof provider.model === "string") {
|
|
3977
|
+
const ctor = provider.constructor?.name && provider.constructor.name !== "Object" ? provider.constructor.name : "LLMProvider";
|
|
3978
|
+
return `${ctor}(${provider.model})`;
|
|
3979
|
+
}
|
|
3980
|
+
if (provider.constructor?.name && provider.constructor.name !== "Object") {
|
|
3981
|
+
return provider.constructor.name;
|
|
3982
|
+
}
|
|
3983
|
+
return `Provider#${index + 1}`;
|
|
3984
|
+
}
|
|
3719
3985
|
async generate(request) {
|
|
3720
3986
|
const failureErrors = [];
|
|
3721
3987
|
for (let i = 0; i < this.providers.length; i++) {
|
|
3722
3988
|
const provider = this.providers[i];
|
|
3723
|
-
const providerName = provider
|
|
3989
|
+
const providerName = this.getProviderName(provider, i);
|
|
3724
3990
|
try {
|
|
3725
3991
|
return await provider.generate(request);
|
|
3726
3992
|
} catch (error) {
|
|
@@ -3728,7 +3994,7 @@ var FallbackLLMProvider = class {
|
|
|
3728
3994
|
failureErrors.push({ providerName, error: errorMessage });
|
|
3729
3995
|
if (this.logFailover) {
|
|
3730
3996
|
const nextProvider = this.providers[i + 1];
|
|
3731
|
-
const nextName = nextProvider ? nextProvider
|
|
3997
|
+
const nextName = nextProvider ? this.getProviderName(nextProvider, i + 1) : "None";
|
|
3732
3998
|
console.warn(
|
|
3733
3999
|
`[FallbackLLMProvider] ${providerName} failed: "${errorMessage}". Failing over to next provider: ${nextName}`
|
|
3734
4000
|
);
|
|
@@ -3857,8 +4123,12 @@ var TieredLLMProvider = class _TieredLLMProvider {
|
|
|
3857
4123
|
// src/adapters/rules/static-rules.adapter.ts
|
|
3858
4124
|
var StaticRulesAdapter = class {
|
|
3859
4125
|
rules;
|
|
3860
|
-
constructor(rules) {
|
|
3861
|
-
this.rules = rules
|
|
4126
|
+
constructor(rules = []) {
|
|
4127
|
+
this.rules = rules.map((r) => {
|
|
4128
|
+
if (typeof r === "string") return r;
|
|
4129
|
+
if (r && typeof r === "object" && typeof r.rule === "string") return r.rule;
|
|
4130
|
+
return String(r);
|
|
4131
|
+
});
|
|
3862
4132
|
}
|
|
3863
4133
|
// Optional tenantId can be used for tenant-specific rules
|
|
3864
4134
|
async getActiveRules(tenantId) {
|
|
@@ -3915,6 +4185,12 @@ var LocalFaqAdapter = class {
|
|
|
3915
4185
|
this.smlEngine = options?.smlEngine || new SMLEngine();
|
|
3916
4186
|
this.defaultThreshold = options?.defaultMatchThreshold ?? 0.6;
|
|
3917
4187
|
}
|
|
4188
|
+
setSMLEngine(engine) {
|
|
4189
|
+
this.smlEngine = engine;
|
|
4190
|
+
}
|
|
4191
|
+
getSMLEngine() {
|
|
4192
|
+
return this.smlEngine;
|
|
4193
|
+
}
|
|
3918
4194
|
/**
|
|
3919
4195
|
* Initializes the adapter by reading the JSON file and caching embeddings in RAM.
|
|
3920
4196
|
*/
|
|
@@ -4474,6 +4750,7 @@ export {
|
|
|
4474
4750
|
IngestionWorker,
|
|
4475
4751
|
InjectionDetector,
|
|
4476
4752
|
InputSanitizer,
|
|
4753
|
+
JobStatusValues,
|
|
4477
4754
|
LocalFaqAdapter,
|
|
4478
4755
|
MemoryConfirmationNonceStore,
|
|
4479
4756
|
MemoryVectorAdapter,
|
|
@@ -4491,6 +4768,7 @@ export {
|
|
|
4491
4768
|
RedisCacheAdapter,
|
|
4492
4769
|
RedisConfirmationNonceStore,
|
|
4493
4770
|
SMLEngine,
|
|
4771
|
+
SMLModelPresets,
|
|
4494
4772
|
SecurityGuard,
|
|
4495
4773
|
StaticRulesAdapter,
|
|
4496
4774
|
TieredLLMProvider,
|