@retrivora-ai/rag-engine 1.9.7 → 1.9.9
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/README.md +136 -136
- package/dist/{ILLMProvider-Bhk6zJOK.d.mts → ILLMProvider-DMxLyTdq.d.mts} +59 -4
- package/dist/{ILLMProvider-Bhk6zJOK.d.ts → ILLMProvider-DMxLyTdq.d.ts} +59 -4
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +2327 -474
- package/dist/handlers/index.mjs +2329 -473
- package/dist/{index-B9J_XEh0.d.ts → index-CfkqZd2Y.d.ts} +12 -2
- package/dist/{index-C3SVtPYg.d.mts → index-DXd29KMq.d.mts} +27 -52
- package/dist/{index-Bu7T6xgr.d.ts → index-D_bOdJML.d.ts} +27 -52
- package/dist/{index-BJ4cd-t5.d.mts → index-xygonxpW.d.mts} +12 -2
- package/dist/index.css +783 -550
- package/dist/index.d.mts +35 -7
- package/dist/index.d.ts +35 -7
- package/dist/index.js +419 -282
- package/dist/index.mjs +426 -292
- package/dist/server.d.mts +65 -6
- package/dist/server.d.ts +65 -6
- package/dist/server.js +2185 -317
- package/dist/server.mjs +2185 -317
- package/package.json +13 -8
- package/src/app/constants.tsx +37 -7
- package/src/app/page.tsx +2 -0
- package/src/components/ChatWidget.tsx +2 -1
- package/src/components/ChatWindow.tsx +4 -1
- package/src/components/CodeViewer.tsx +19 -14
- package/src/components/MarkdownComponents.tsx +44 -1
- package/src/components/MessageBubble.tsx +162 -50
- package/src/components/constants.tsx +228 -0
- package/src/config/RagConfig.ts +48 -2
- package/src/config/constants.ts +4 -0
- package/src/config/serverConfig.ts +15 -0
- package/src/core/ConfigResolver.ts +38 -6
- package/src/core/DatabaseStorage.ts +469 -0
- package/src/core/LicenseVerifier.ts +260 -0
- package/src/core/MultiAgentCoordinator.ts +239 -0
- package/src/core/Pipeline.ts +151 -18
- package/src/core/Retrivora.ts +7 -0
- package/src/core/VectorPlugin.ts +12 -3
- package/src/core/mcp.ts +261 -0
- package/src/handlers/index.ts +449 -63
- package/src/hooks/useRagChat.ts +96 -42
- package/src/hooks/useStoredMessages.ts +15 -4
- package/src/index.ts +3 -0
- package/src/llm/LLMFactory.ts +9 -1
- package/src/llm/providers/GroqProvider.ts +176 -0
- package/src/llm/providers/QwenProvider.ts +191 -0
- package/src/server.ts +7 -0
- package/src/types/chat.ts +14 -0
- package/src/types/props.ts +12 -0
- package/.env.example +0 -80
- package/LICENSE.txt +0 -21
- package/src/components/AmbientBackground.tsx +0 -29
- package/src/components/ArchitectureCard.tsx +0 -17
- package/src/components/ArchitectureCardsSection.tsx +0 -15
- package/src/components/DocViewer.tsx +0 -103
- package/src/components/Documentation.tsx +0 -121
- package/src/components/Hero.tsx +0 -59
- package/src/components/Lifecycle.tsx +0 -37
- package/src/components/Navbar.tsx +0 -55
package/dist/server.js
CHANGED
|
@@ -80,9 +80,9 @@ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")])
|
|
|
80
80
|
function isRecord(value) {
|
|
81
81
|
return typeof value === "object" && value !== null;
|
|
82
82
|
}
|
|
83
|
-
function resolvePath(obj,
|
|
84
|
-
if (!
|
|
85
|
-
return
|
|
83
|
+
function resolvePath(obj, path2) {
|
|
84
|
+
if (!path2 || !obj) return void 0;
|
|
85
|
+
return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
|
|
86
86
|
if (!isRecord(current) && !Array.isArray(current)) {
|
|
87
87
|
return void 0;
|
|
88
88
|
}
|
|
@@ -192,7 +192,7 @@ var init_PineconeProvider = __esm({
|
|
|
192
192
|
static getHealthChecker() {
|
|
193
193
|
return {
|
|
194
194
|
async check(config) {
|
|
195
|
-
var
|
|
195
|
+
var _a2, _b;
|
|
196
196
|
const opts = config.options || {};
|
|
197
197
|
const indexName = config.indexName;
|
|
198
198
|
const timestamp = Date.now();
|
|
@@ -200,7 +200,7 @@ var init_PineconeProvider = __esm({
|
|
|
200
200
|
const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
|
|
201
201
|
const client = new Pinecone2({ apiKey: opts.apiKey });
|
|
202
202
|
const indexes = await client.listIndexes();
|
|
203
|
-
const indexNames = (_b = (
|
|
203
|
+
const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
204
204
|
if (!indexNames.includes(indexName)) {
|
|
205
205
|
return {
|
|
206
206
|
healthy: false,
|
|
@@ -227,10 +227,10 @@ var init_PineconeProvider = __esm({
|
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
229
|
async initialize() {
|
|
230
|
-
var
|
|
230
|
+
var _a2, _b;
|
|
231
231
|
this.client = new import_pinecone.Pinecone({ apiKey: this.apiKey });
|
|
232
232
|
const indexes = await this.client.listIndexes();
|
|
233
|
-
const names = (_b = (
|
|
233
|
+
const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
234
234
|
if (!names.includes(this.indexName)) {
|
|
235
235
|
throw new Error(
|
|
236
236
|
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
@@ -242,12 +242,12 @@ var init_PineconeProvider = __esm({
|
|
|
242
242
|
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
243
243
|
}
|
|
244
244
|
async upsert(doc, namespace) {
|
|
245
|
-
var
|
|
245
|
+
var _a2;
|
|
246
246
|
await this.index(namespace).upsert({
|
|
247
247
|
records: [{
|
|
248
248
|
id: String(doc.id),
|
|
249
249
|
values: doc.vector,
|
|
250
|
-
metadata: __spreadValues({ content: doc.content }, (
|
|
250
|
+
metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
|
|
251
251
|
}]
|
|
252
252
|
});
|
|
253
253
|
}
|
|
@@ -255,29 +255,29 @@ var init_PineconeProvider = __esm({
|
|
|
255
255
|
const BATCH = 100;
|
|
256
256
|
for (let i = 0; i < docs.length; i += BATCH) {
|
|
257
257
|
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
258
|
-
var
|
|
258
|
+
var _a2;
|
|
259
259
|
return {
|
|
260
260
|
id: String(d.id),
|
|
261
261
|
values: d.vector,
|
|
262
|
-
metadata: __spreadValues({ content: d.content }, (
|
|
262
|
+
metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
|
|
263
263
|
};
|
|
264
264
|
});
|
|
265
265
|
await this.index(namespace).upsert({ records });
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
async query(vector, topK, namespace, filter) {
|
|
269
|
-
var
|
|
269
|
+
var _a2;
|
|
270
270
|
const pineconeFilter = this.sanitizeFilter(filter);
|
|
271
271
|
const result = await this.index(namespace).query(__spreadValues({
|
|
272
272
|
vector,
|
|
273
273
|
topK,
|
|
274
274
|
includeMetadata: true
|
|
275
275
|
}, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
|
|
276
|
-
return ((
|
|
277
|
-
var
|
|
276
|
+
return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
|
|
277
|
+
var _a3, _b;
|
|
278
278
|
return {
|
|
279
279
|
id: m.id,
|
|
280
|
-
score: (
|
|
280
|
+
score: (_a3 = m.score) != null ? _a3 : 0,
|
|
281
281
|
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
282
282
|
metadata: m.metadata
|
|
283
283
|
};
|
|
@@ -316,13 +316,13 @@ var init_PostgreSQLProvider = __esm({
|
|
|
316
316
|
init_BaseVectorProvider();
|
|
317
317
|
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
318
318
|
constructor(config) {
|
|
319
|
-
var
|
|
319
|
+
var _a2;
|
|
320
320
|
super(config);
|
|
321
321
|
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
322
322
|
const opts = config.options;
|
|
323
323
|
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
324
324
|
this.connectionString = opts.connectionString;
|
|
325
|
-
this.dimensions = (
|
|
325
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
|
|
326
326
|
}
|
|
327
327
|
static getValidator() {
|
|
328
328
|
return {
|
|
@@ -403,7 +403,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
405
|
async upsert(doc, namespace = "") {
|
|
406
|
-
var
|
|
406
|
+
var _a2;
|
|
407
407
|
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
408
408
|
await this.pool.query(
|
|
409
409
|
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
@@ -413,7 +413,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
413
413
|
content = EXCLUDED.content,
|
|
414
414
|
metadata = EXCLUDED.metadata,
|
|
415
415
|
embedding = EXCLUDED.embedding`,
|
|
416
|
-
[doc.id, namespace, doc.content, JSON.stringify((
|
|
416
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
|
|
417
417
|
);
|
|
418
418
|
}
|
|
419
419
|
async batchUpsert(docs, namespace = "") {
|
|
@@ -426,9 +426,9 @@ var init_PostgreSQLProvider = __esm({
|
|
|
426
426
|
const batch = docs.slice(i, i + BATCH_SIZE);
|
|
427
427
|
const values = [];
|
|
428
428
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
429
|
-
var
|
|
429
|
+
var _a2;
|
|
430
430
|
const offset = idx * 5;
|
|
431
|
-
values.push(doc.id, namespace, doc.content, JSON.stringify((
|
|
431
|
+
values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
|
|
432
432
|
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
|
|
433
433
|
}).join(", ");
|
|
434
434
|
const query = `
|
|
@@ -511,8 +511,8 @@ var init_PostgreSQLProvider = __esm({
|
|
|
511
511
|
|
|
512
512
|
// src/utils/synonyms.ts
|
|
513
513
|
function resolveMetadataValue(meta, uiKey) {
|
|
514
|
-
var
|
|
515
|
-
const synonyms = (
|
|
514
|
+
var _a2;
|
|
515
|
+
const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
|
|
516
516
|
const keys = Object.keys(meta);
|
|
517
517
|
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
518
518
|
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
@@ -599,14 +599,14 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
599
599
|
init_synonyms();
|
|
600
600
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
601
601
|
constructor(config) {
|
|
602
|
-
var
|
|
602
|
+
var _a2, _b, _c;
|
|
603
603
|
super(config);
|
|
604
604
|
const opts = config.options || {};
|
|
605
605
|
if (!opts.connectionString) {
|
|
606
606
|
throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
|
|
607
607
|
}
|
|
608
608
|
this.connectionString = opts.connectionString;
|
|
609
|
-
this.dimensions = (
|
|
609
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
|
|
610
610
|
this.tables = [];
|
|
611
611
|
const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
|
|
612
612
|
this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
|
|
@@ -664,11 +664,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
664
664
|
* Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
|
|
665
665
|
*/
|
|
666
666
|
async batchUpsert(docs, namespace = "") {
|
|
667
|
-
var
|
|
667
|
+
var _a2;
|
|
668
668
|
if (docs.length === 0) return;
|
|
669
669
|
const docsByFile = {};
|
|
670
670
|
for (const doc of docs) {
|
|
671
|
-
const fileName = ((
|
|
671
|
+
const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
|
|
672
672
|
if (!docsByFile[fileName]) docsByFile[fileName] = [];
|
|
673
673
|
docsByFile[fileName].push(doc);
|
|
674
674
|
}
|
|
@@ -721,11 +721,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
721
721
|
const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
|
|
722
722
|
const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
|
|
723
723
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
724
|
-
var
|
|
724
|
+
var _a3, _b;
|
|
725
725
|
const offset = idx * (5 + csvHeaders.length);
|
|
726
726
|
values.push(doc.id);
|
|
727
727
|
for (const h of csvHeaders) {
|
|
728
|
-
values.push(String(((
|
|
728
|
+
values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
|
|
729
729
|
}
|
|
730
730
|
values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
|
|
731
731
|
const docPlaceholders = [];
|
|
@@ -764,7 +764,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
764
764
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
765
765
|
*/
|
|
766
766
|
async query(vector, topK, _namespace, _filter) {
|
|
767
|
-
var
|
|
767
|
+
var _a2;
|
|
768
768
|
if (!this.pool) {
|
|
769
769
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
770
770
|
}
|
|
@@ -795,11 +795,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
795
795
|
const filterParams = [];
|
|
796
796
|
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
797
797
|
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
798
|
-
var
|
|
798
|
+
var _a4;
|
|
799
799
|
filterParams.push(String(val));
|
|
800
800
|
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
801
801
|
const paramIdx = baseOffset + filterParams.length;
|
|
802
|
-
const synonyms = (
|
|
802
|
+
const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
|
|
803
803
|
const keysToCheck = [key, ...synonyms];
|
|
804
804
|
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
805
805
|
`metadata->>'${k}'`,
|
|
@@ -868,7 +868,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
868
868
|
}
|
|
869
869
|
const tableResults = [];
|
|
870
870
|
for (const row of result.rows) {
|
|
871
|
-
const
|
|
871
|
+
const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
|
|
872
872
|
delete rest.embedding;
|
|
873
873
|
delete rest.vector_score;
|
|
874
874
|
delete rest.keyword_score;
|
|
@@ -897,10 +897,10 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
897
897
|
}
|
|
898
898
|
allResults.sort((a, b) => b.score - a.score);
|
|
899
899
|
if (allResults.length === 0) return [];
|
|
900
|
-
const bestMatchTable = (
|
|
900
|
+
const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
|
|
901
901
|
const finalSorted = allResults.filter((res) => {
|
|
902
|
-
var
|
|
903
|
-
return ((
|
|
902
|
+
var _a3;
|
|
903
|
+
return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
|
|
904
904
|
});
|
|
905
905
|
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
906
906
|
console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
@@ -1305,14 +1305,14 @@ var init_QdrantProvider = __esm({
|
|
|
1305
1305
|
* Samples points from the collection to discover available payload fields.
|
|
1306
1306
|
*/
|
|
1307
1307
|
async discoverSchema() {
|
|
1308
|
-
var
|
|
1308
|
+
var _a2;
|
|
1309
1309
|
try {
|
|
1310
1310
|
const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
|
|
1311
1311
|
limit: 20,
|
|
1312
1312
|
with_payload: true,
|
|
1313
1313
|
with_vector: false
|
|
1314
1314
|
});
|
|
1315
|
-
const points = ((
|
|
1315
|
+
const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
|
|
1316
1316
|
const keys = /* @__PURE__ */ new Set();
|
|
1317
1317
|
for (const point of points) {
|
|
1318
1318
|
const payload = point.payload || {};
|
|
@@ -1338,12 +1338,12 @@ var init_QdrantProvider = __esm({
|
|
|
1338
1338
|
* Ensures the collection exists. Creates it if missing.
|
|
1339
1339
|
*/
|
|
1340
1340
|
async ensureCollection() {
|
|
1341
|
-
var
|
|
1341
|
+
var _a2;
|
|
1342
1342
|
try {
|
|
1343
1343
|
await this.http.get(`/collections/${this.indexName}`);
|
|
1344
1344
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
1345
1345
|
} catch (err) {
|
|
1346
|
-
if (import_axios4.default.isAxiosError(err) && ((
|
|
1346
|
+
if (import_axios4.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1347
1347
|
const opts = this.config.options;
|
|
1348
1348
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1349
1349
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
@@ -1363,7 +1363,7 @@ var init_QdrantProvider = __esm({
|
|
|
1363
1363
|
* Ensures that a payload field has an index.
|
|
1364
1364
|
*/
|
|
1365
1365
|
async ensureIndex(fieldName, schema = "keyword") {
|
|
1366
|
-
var
|
|
1366
|
+
var _a2;
|
|
1367
1367
|
let fullPath = fieldName;
|
|
1368
1368
|
if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
|
|
1369
1369
|
fullPath = `${this.metadataField}.${fieldName}`;
|
|
@@ -1376,7 +1376,7 @@ var init_QdrantProvider = __esm({
|
|
|
1376
1376
|
console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
|
|
1377
1377
|
} catch (err) {
|
|
1378
1378
|
let status;
|
|
1379
|
-
if (import_axios4.default.isAxiosError(err)) status = (
|
|
1379
|
+
if (import_axios4.default.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
|
|
1380
1380
|
if (status === 409) return;
|
|
1381
1381
|
console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
|
|
1382
1382
|
}
|
|
@@ -1405,7 +1405,7 @@ var init_QdrantProvider = __esm({
|
|
|
1405
1405
|
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
1406
1406
|
}
|
|
1407
1407
|
async query(vector, topK, namespace, _filter) {
|
|
1408
|
-
var
|
|
1408
|
+
var _a2;
|
|
1409
1409
|
const must = [];
|
|
1410
1410
|
if (namespace) {
|
|
1411
1411
|
must.push({ key: "namespace", match: { value: namespace } });
|
|
@@ -1427,7 +1427,7 @@ var init_QdrantProvider = __esm({
|
|
|
1427
1427
|
limit: topK,
|
|
1428
1428
|
with_payload: true,
|
|
1429
1429
|
params: {
|
|
1430
|
-
hnsw_ef: ((
|
|
1430
|
+
hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
|
|
1431
1431
|
exact: false
|
|
1432
1432
|
},
|
|
1433
1433
|
filter: must.length > 0 ? { must } : void 0
|
|
@@ -1522,13 +1522,13 @@ var init_ChromaDBProvider = __esm({
|
|
|
1522
1522
|
* Get or create the ChromaDB collection.
|
|
1523
1523
|
*/
|
|
1524
1524
|
async initialize() {
|
|
1525
|
-
var
|
|
1525
|
+
var _a2;
|
|
1526
1526
|
try {
|
|
1527
1527
|
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1528
1528
|
this.collectionId = data.id;
|
|
1529
1529
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1530
1530
|
} catch (err) {
|
|
1531
|
-
if (import_axios5.default.isAxiosError(err) && ((
|
|
1531
|
+
if (import_axios5.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1532
1532
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1533
1533
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1534
1534
|
name: this.indexName
|
|
@@ -1749,7 +1749,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1749
1749
|
await this.http.post("/v1/batch/objects", payload);
|
|
1750
1750
|
}
|
|
1751
1751
|
async query(vector, topK, namespace, _filter) {
|
|
1752
|
-
var
|
|
1752
|
+
var _a2, _b;
|
|
1753
1753
|
const queryText = _filter == null ? void 0 : _filter.queryText;
|
|
1754
1754
|
const sanitizedFilter = this.sanitizeFilter(_filter);
|
|
1755
1755
|
const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
|
|
@@ -1775,7 +1775,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1775
1775
|
`
|
|
1776
1776
|
};
|
|
1777
1777
|
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1778
|
-
const results = ((_b = (
|
|
1778
|
+
const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1779
1779
|
return results.map((res) => ({
|
|
1780
1780
|
id: res["_additional"].id,
|
|
1781
1781
|
score: 1 - res["_additional"].distance,
|
|
@@ -1828,10 +1828,10 @@ var init_WeaviateProvider = __esm({
|
|
|
1828
1828
|
return `{ operator: And, operands: [${operands.join(", ")}] }`;
|
|
1829
1829
|
}
|
|
1830
1830
|
weaviateOperand(key, value) {
|
|
1831
|
-
const
|
|
1832
|
-
if (typeof value === "number") return `{ ${
|
|
1833
|
-
if (typeof value === "boolean") return `{ ${
|
|
1834
|
-
return `{ ${
|
|
1831
|
+
const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
|
|
1832
|
+
if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
|
|
1833
|
+
if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
|
|
1834
|
+
return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
|
|
1835
1835
|
}
|
|
1836
1836
|
};
|
|
1837
1837
|
}
|
|
@@ -1858,21 +1858,21 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1858
1858
|
}
|
|
1859
1859
|
}
|
|
1860
1860
|
async initialize() {
|
|
1861
|
-
var
|
|
1861
|
+
var _a2;
|
|
1862
1862
|
this.http = import_axios8.default.create({
|
|
1863
1863
|
baseURL: this.opts.baseUrl,
|
|
1864
1864
|
headers: __spreadValues({
|
|
1865
1865
|
"Content-Type": "application/json"
|
|
1866
1866
|
}, this.opts.headers),
|
|
1867
|
-
timeout: (
|
|
1867
|
+
timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
|
|
1868
1868
|
});
|
|
1869
1869
|
if (!await this.ping()) {
|
|
1870
1870
|
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1871
1871
|
}
|
|
1872
1872
|
}
|
|
1873
1873
|
async upsert(doc, namespace) {
|
|
1874
|
-
var
|
|
1875
|
-
const endpoint = (
|
|
1874
|
+
var _a2, _b, _c;
|
|
1875
|
+
const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
|
|
1876
1876
|
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1877
1877
|
id: "{{id}}",
|
|
1878
1878
|
vector: "{{vector}}",
|
|
@@ -1905,8 +1905,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1905
1905
|
}
|
|
1906
1906
|
}
|
|
1907
1907
|
async query(vector, topK, namespace, filter) {
|
|
1908
|
-
var
|
|
1909
|
-
const endpoint = (
|
|
1908
|
+
var _a2, _b;
|
|
1909
|
+
const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
|
|
1910
1910
|
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1911
1911
|
vector: "{{vector}}",
|
|
1912
1912
|
limit: "{{topK}}",
|
|
@@ -1932,12 +1932,12 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
return results.map((item) => {
|
|
1935
|
-
var
|
|
1935
|
+
var _a3, _b2, _c, _d, _e, _f, _g2;
|
|
1936
1936
|
return {
|
|
1937
|
-
id: item[(
|
|
1937
|
+
id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
|
|
1938
1938
|
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1939
1939
|
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1940
|
-
metadata: (
|
|
1940
|
+
metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
|
|
1941
1941
|
};
|
|
1942
1942
|
});
|
|
1943
1943
|
} catch (error) {
|
|
@@ -1947,8 +1947,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1947
1947
|
}
|
|
1948
1948
|
}
|
|
1949
1949
|
async delete(id, namespace) {
|
|
1950
|
-
var
|
|
1951
|
-
const endpoint = (
|
|
1950
|
+
var _a2, _b;
|
|
1951
|
+
const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
|
|
1952
1952
|
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1953
1953
|
id: "{{id}}",
|
|
1954
1954
|
namespace: "{{namespace}}"
|
|
@@ -1966,8 +1966,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1966
1966
|
}
|
|
1967
1967
|
}
|
|
1968
1968
|
async deleteNamespace(namespace) {
|
|
1969
|
-
var
|
|
1970
|
-
const endpoint = (
|
|
1969
|
+
var _a2;
|
|
1970
|
+
const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
|
|
1971
1971
|
try {
|
|
1972
1972
|
await this.http.post(endpoint, { namespace });
|
|
1973
1973
|
} catch (error) {
|
|
@@ -1977,9 +1977,9 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1977
1977
|
}
|
|
1978
1978
|
}
|
|
1979
1979
|
async ping() {
|
|
1980
|
-
var
|
|
1980
|
+
var _a2;
|
|
1981
1981
|
try {
|
|
1982
|
-
const endpoint = (
|
|
1982
|
+
const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
|
|
1983
1983
|
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
1984
1984
|
return response.status >= 200 && response.status < 300;
|
|
1985
1985
|
} catch (e) {
|
|
@@ -2084,8 +2084,10 @@ __export(server_exports, {
|
|
|
2084
2084
|
EmbeddingFailedException: () => EmbeddingFailedException,
|
|
2085
2085
|
EmbeddingStrategy: () => EmbeddingStrategy,
|
|
2086
2086
|
EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
|
|
2087
|
+
GroqProvider: () => GroqProvider,
|
|
2087
2088
|
LLMFactory: () => LLMFactory,
|
|
2088
2089
|
LLM_PROFILES: () => LLM_PROFILES,
|
|
2090
|
+
LicenseVerifier: () => LicenseVerifier,
|
|
2089
2091
|
MilvusProvider: () => MilvusProvider,
|
|
2090
2092
|
MongoDBProvider: () => MongoDBProvider,
|
|
2091
2093
|
MultiTablePostgresProvider: () => MultiTablePostgresProvider,
|
|
@@ -2099,6 +2101,7 @@ __export(server_exports, {
|
|
|
2099
2101
|
ProviderNotFoundException: () => ProviderNotFoundException,
|
|
2100
2102
|
ProviderRegistry: () => ProviderRegistry,
|
|
2101
2103
|
QdrantProvider: () => QdrantProvider,
|
|
2104
|
+
QwenProvider: () => QwenProvider,
|
|
2102
2105
|
RateLimitException: () => RateLimitException,
|
|
2103
2106
|
RedisProvider: () => RedisProvider,
|
|
2104
2107
|
RetrievalException: () => RetrievalException,
|
|
@@ -2110,10 +2113,13 @@ __export(server_exports, {
|
|
|
2110
2113
|
VectorPlugin: () => VectorPlugin,
|
|
2111
2114
|
WeaviateProvider: () => WeaviateProvider,
|
|
2112
2115
|
createChatHandler: () => createChatHandler,
|
|
2116
|
+
createFeedbackHandler: () => createFeedbackHandler,
|
|
2113
2117
|
createFromPreset: () => createFromPreset,
|
|
2114
2118
|
createHealthHandler: () => createHealthHandler,
|
|
2119
|
+
createHistoryHandler: () => createHistoryHandler,
|
|
2115
2120
|
createIngestHandler: () => createIngestHandler,
|
|
2116
2121
|
createRagHandler: () => createRagHandler,
|
|
2122
|
+
createSessionsHandler: () => createSessionsHandler,
|
|
2117
2123
|
createStreamHandler: () => createStreamHandler,
|
|
2118
2124
|
createUploadHandler: () => createUploadHandler,
|
|
2119
2125
|
getRagConfig: () => getRagConfig,
|
|
@@ -2148,6 +2154,8 @@ var LLM_PROVIDERS = [
|
|
|
2148
2154
|
"anthropic",
|
|
2149
2155
|
"ollama",
|
|
2150
2156
|
"gemini",
|
|
2157
|
+
"groq",
|
|
2158
|
+
"qwen",
|
|
2151
2159
|
"rest",
|
|
2152
2160
|
"universal_rest",
|
|
2153
2161
|
"custom"
|
|
@@ -2156,6 +2164,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2156
2164
|
"openai",
|
|
2157
2165
|
"ollama",
|
|
2158
2166
|
"gemini",
|
|
2167
|
+
"qwen",
|
|
2159
2168
|
"rest",
|
|
2160
2169
|
"universal_rest",
|
|
2161
2170
|
"custom"
|
|
@@ -2164,6 +2173,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2164
2173
|
"openai",
|
|
2165
2174
|
"ollama",
|
|
2166
2175
|
"gemini",
|
|
2176
|
+
"qwen",
|
|
2167
2177
|
"rest",
|
|
2168
2178
|
"universal_rest"
|
|
2169
2179
|
];
|
|
@@ -2171,8 +2181,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2171
2181
|
|
|
2172
2182
|
// src/config/serverConfig.ts
|
|
2173
2183
|
function readString(env, name) {
|
|
2174
|
-
var
|
|
2175
|
-
const value = (
|
|
2184
|
+
var _a2;
|
|
2185
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2176
2186
|
return value ? value : void 0;
|
|
2177
2187
|
}
|
|
2178
2188
|
function readNumber(env, name, fallback) {
|
|
@@ -2185,8 +2195,8 @@ function readNumber(env, name, fallback) {
|
|
|
2185
2195
|
return parsed;
|
|
2186
2196
|
}
|
|
2187
2197
|
function readEnum(env, name, fallback, allowed) {
|
|
2188
|
-
var
|
|
2189
|
-
const value = (
|
|
2198
|
+
var _a2;
|
|
2199
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2190
2200
|
if (allowed.includes(value)) {
|
|
2191
2201
|
return value;
|
|
2192
2202
|
}
|
|
@@ -2196,15 +2206,15 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2196
2206
|
return getEnvConfig(env, baseConfig);
|
|
2197
2207
|
}
|
|
2198
2208
|
function getEnvConfig(env = process.env, base) {
|
|
2199
|
-
var
|
|
2200
|
-
const projectId = (_c = (_b = (
|
|
2209
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa;
|
|
2210
|
+
const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
|
|
2201
2211
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2202
2212
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2203
2213
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2204
2214
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2205
2215
|
const vectorDbOptions = {};
|
|
2206
2216
|
if (vectorProvider === "pinecone") {
|
|
2207
|
-
vectorDbOptions.apiKey = (
|
|
2217
|
+
vectorDbOptions.apiKey = (_g2 = (_f = readString(env, "PINECONE_API_KEY")) != null ? _f : (_e = (_d = base == null ? void 0 : base.vectorDb) == null ? void 0 : _d.options) == null ? void 0 : _e.apiKey) != null ? _g2 : "";
|
|
2208
2218
|
vectorDbOptions.indexName = (_l = (_i = readString(env, "PINECONE_INDEX")) != null ? _i : (_h = base == null ? void 0 : base.vectorDb) == null ? void 0 : _h.indexName) != null ? _l : (_k = (_j = base == null ? void 0 : base.vectorDb) == null ? void 0 : _j.options) == null ? void 0 : _k.indexName;
|
|
2209
2219
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2210
2220
|
vectorDbOptions.connectionString = (_q = (_p = (_m = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _m : readString(env, "POSTGRES_URL")) != null ? _p : (_o = (_n = base == null ? void 0 : base.vectorDb) == null ? void 0 : _n.options) == null ? void 0 : _o.connectionString) != null ? _q : "";
|
|
@@ -2266,17 +2276,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2266
2276
|
rest: "default",
|
|
2267
2277
|
custom: "default"
|
|
2268
2278
|
};
|
|
2269
|
-
return __spreadValues({
|
|
2279
|
+
return __spreadProps(__spreadValues({
|
|
2270
2280
|
projectId,
|
|
2281
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2271
2282
|
vectorDb: {
|
|
2272
2283
|
provider: vectorProvider,
|
|
2273
|
-
indexName: (
|
|
2284
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2274
2285
|
options: vectorDbOptions
|
|
2275
2286
|
},
|
|
2276
2287
|
llm: {
|
|
2277
2288
|
provider: llmProvider,
|
|
2278
|
-
model: (
|
|
2279
|
-
apiKey: (
|
|
2289
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2290
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2280
2291
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2281
2292
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2282
2293
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2289,7 +2300,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2289
2300
|
},
|
|
2290
2301
|
embedding: {
|
|
2291
2302
|
provider: embeddingProvider,
|
|
2292
|
-
model: (
|
|
2303
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2293
2304
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2294
2305
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2295
2306
|
dimensions: embeddingDimensions,
|
|
@@ -2300,30 +2311,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2300
2311
|
}
|
|
2301
2312
|
},
|
|
2302
2313
|
ui: {
|
|
2303
|
-
title: (
|
|
2304
|
-
subtitle: (
|
|
2305
|
-
primaryColor: (
|
|
2306
|
-
accentColor: (
|
|
2307
|
-
logoUrl: (
|
|
2308
|
-
placeholder: (
|
|
2309
|
-
showSources: ((
|
|
2310
|
-
welcomeMessage: (
|
|
2311
|
-
visualStyle: (
|
|
2312
|
-
borderRadius: (
|
|
2313
|
-
allowUpload: ((
|
|
2314
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2315
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2316
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2317
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2318
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2319
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2320
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2321
|
+
welcomeMessage: (_Ca = (_Ba = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _Ba : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Ca : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
2322
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2323
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2324
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2314
2325
|
},
|
|
2315
2326
|
rag: {
|
|
2316
2327
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2317
2328
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2318
2329
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2319
2330
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2320
|
-
filterableFields: (
|
|
2331
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2321
2332
|
// Query pipeline toggles — read from .env.local
|
|
2322
2333
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2323
2334
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2324
2335
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2325
|
-
architecture: (
|
|
2326
|
-
chunkingStrategy: (
|
|
2336
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2337
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2327
2338
|
uiMapping: (() => {
|
|
2328
2339
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2329
2340
|
if (!raw) return void 0;
|
|
@@ -2333,6 +2344,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2333
2344
|
return void 0;
|
|
2334
2345
|
}
|
|
2335
2346
|
})()
|
|
2347
|
+
},
|
|
2348
|
+
telemetry: {
|
|
2349
|
+
enabled: readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_Ma = base == null ? void 0 : base.telemetry) == null ? void 0 : _Ma.enabled) || false,
|
|
2350
|
+
url: (_Qa = (_Pa = (_Na = readString(env, "TELEMETRY_URL")) != null ? _Na : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _Pa : (_Oa = base == null ? void 0 : base.telemetry) == null ? void 0 : _Oa.url) != null ? _Qa : "/api/telemetry"
|
|
2336
2351
|
}
|
|
2337
2352
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2338
2353
|
graphDb: {
|
|
@@ -2343,7 +2358,19 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2343
2358
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2344
2359
|
}
|
|
2345
2360
|
}
|
|
2346
|
-
} : {})
|
|
2361
|
+
} : {}), {
|
|
2362
|
+
mcpServers: (() => {
|
|
2363
|
+
var _a3;
|
|
2364
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2365
|
+
if (!raw) return void 0;
|
|
2366
|
+
try {
|
|
2367
|
+
return JSON.parse(raw);
|
|
2368
|
+
} catch (e) {
|
|
2369
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2370
|
+
return void 0;
|
|
2371
|
+
}
|
|
2372
|
+
})()
|
|
2373
|
+
});
|
|
2347
2374
|
}
|
|
2348
2375
|
|
|
2349
2376
|
// src/core/ConfigResolver.ts
|
|
@@ -2369,7 +2396,8 @@ var ConfigResolver = class {
|
|
|
2369
2396
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2370
2397
|
}) : envConfig.embedding,
|
|
2371
2398
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2372
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2399
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2400
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2373
2401
|
});
|
|
2374
2402
|
}
|
|
2375
2403
|
/**
|
|
@@ -2378,10 +2406,10 @@ var ConfigResolver = class {
|
|
|
2378
2406
|
* fallback behavior.
|
|
2379
2407
|
*/
|
|
2380
2408
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2381
|
-
var
|
|
2409
|
+
var _a2;
|
|
2382
2410
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2383
2411
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2384
|
-
vectorDb: (
|
|
2412
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2385
2413
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2386
2414
|
});
|
|
2387
2415
|
return this.resolve(normalized, env);
|
|
@@ -2401,28 +2429,52 @@ var ConfigResolver = class {
|
|
|
2401
2429
|
}
|
|
2402
2430
|
}
|
|
2403
2431
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2404
|
-
var
|
|
2432
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2405
2433
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2406
2434
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2407
2435
|
if (retrieval) {
|
|
2408
|
-
normalized.topK = (
|
|
2436
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2409
2437
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2410
2438
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2411
2439
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
2412
|
-
if (retrieval.strategy === "agentic") normalized.architecture = "
|
|
2413
|
-
if (retrieval.strategy === "contextual-compression")
|
|
2440
|
+
if (retrieval.strategy === "agentic") normalized.architecture = "multi-agent";
|
|
2441
|
+
if (retrieval.strategy === "contextual-compression") {
|
|
2442
|
+
normalized.useReranking = true;
|
|
2443
|
+
normalized.architecture = (_e = normalized.architecture) != null ? _e : "retrieve-and-rerank";
|
|
2444
|
+
}
|
|
2414
2445
|
}
|
|
2415
2446
|
if (workflow == null ? void 0 : workflow.type) {
|
|
2416
2447
|
const type = workflow.type;
|
|
2417
|
-
if (type === "
|
|
2418
|
-
|
|
2419
|
-
|
|
2448
|
+
if (type === "naive-rag") {
|
|
2449
|
+
normalized.architecture = "naive";
|
|
2450
|
+
normalized.useReranking = false;
|
|
2451
|
+
normalized.useGraphRetrieval = false;
|
|
2452
|
+
} else if (type === "retrieve-and-rerank") {
|
|
2453
|
+
normalized.architecture = "retrieve-and-rerank";
|
|
2454
|
+
normalized.useReranking = true;
|
|
2455
|
+
} else if (type === "multimodal-rag") {
|
|
2456
|
+
normalized.architecture = "multimodal";
|
|
2457
|
+
} else if (type === "graph-rag") {
|
|
2420
2458
|
normalized.architecture = "graph";
|
|
2421
2459
|
normalized.useGraphRetrieval = true;
|
|
2460
|
+
} else if (type === "hybrid-rag") {
|
|
2461
|
+
normalized.architecture = "hybrid";
|
|
2462
|
+
} else if (type === "agentic-router") {
|
|
2463
|
+
normalized.architecture = "agentic-router";
|
|
2464
|
+
} else if (type === "multi-agent-rag" || type === "multi-agent" || type === "agentic" || type === "agentic-rag") {
|
|
2465
|
+
normalized.architecture = "multi-agent";
|
|
2422
2466
|
} else if (type === "simple-rag" || type === "rag") {
|
|
2423
|
-
normalized.architecture = (
|
|
2467
|
+
normalized.architecture = (_f = normalized.architecture) != null ? _f : "naive";
|
|
2424
2468
|
}
|
|
2425
2469
|
}
|
|
2470
|
+
if (normalized.architecture === "retrieve-and-rerank") {
|
|
2471
|
+
normalized.useReranking = true;
|
|
2472
|
+
} else if (normalized.architecture === "graph") {
|
|
2473
|
+
normalized.useGraphRetrieval = true;
|
|
2474
|
+
} else if (normalized.architecture === "naive") {
|
|
2475
|
+
normalized.useReranking = false;
|
|
2476
|
+
normalized.useGraphRetrieval = false;
|
|
2477
|
+
}
|
|
2426
2478
|
return normalized;
|
|
2427
2479
|
}
|
|
2428
2480
|
};
|
|
@@ -2487,8 +2539,8 @@ var OpenAIProvider = class {
|
|
|
2487
2539
|
const apiKey = config.apiKey;
|
|
2488
2540
|
const modelName = config.model;
|
|
2489
2541
|
try {
|
|
2490
|
-
const
|
|
2491
|
-
const client = new
|
|
2542
|
+
const OpenAI4 = await import("openai");
|
|
2543
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2492
2544
|
const models = await client.models.list();
|
|
2493
2545
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2494
2546
|
return {
|
|
@@ -2509,8 +2561,8 @@ var OpenAIProvider = class {
|
|
|
2509
2561
|
};
|
|
2510
2562
|
}
|
|
2511
2563
|
async chat(messages, context, options) {
|
|
2512
|
-
var
|
|
2513
|
-
const basePrompt = (_b = (
|
|
2564
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2565
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2514
2566
|
const systemMessage = {
|
|
2515
2567
|
role: "system",
|
|
2516
2568
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2529,12 +2581,12 @@ var OpenAIProvider = class {
|
|
|
2529
2581
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2530
2582
|
stop: options == null ? void 0 : options.stop
|
|
2531
2583
|
});
|
|
2532
|
-
return (_i = (_h = (
|
|
2584
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2533
2585
|
}
|
|
2534
2586
|
chatStream(messages, context, options) {
|
|
2535
2587
|
return __asyncGenerator(this, null, function* () {
|
|
2536
|
-
var
|
|
2537
|
-
const basePrompt = (_b = (
|
|
2588
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2589
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2538
2590
|
const systemMessage = {
|
|
2539
2591
|
role: "system",
|
|
2540
2592
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2560,7 +2612,7 @@ var OpenAIProvider = class {
|
|
|
2560
2612
|
try {
|
|
2561
2613
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2562
2614
|
const chunk = temp.value;
|
|
2563
|
-
const content = ((_h = (
|
|
2615
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2564
2616
|
if (content) yield content;
|
|
2565
2617
|
}
|
|
2566
2618
|
} catch (temp) {
|
|
@@ -2580,8 +2632,8 @@ var OpenAIProvider = class {
|
|
|
2580
2632
|
return results[0];
|
|
2581
2633
|
}
|
|
2582
2634
|
async batchEmbed(texts, options) {
|
|
2583
|
-
var
|
|
2584
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2635
|
+
var _a2, _b, _c, _d, _e;
|
|
2636
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-3-small";
|
|
2585
2637
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2586
2638
|
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
2587
2639
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2658,8 +2710,8 @@ var AnthropicProvider = class {
|
|
|
2658
2710
|
};
|
|
2659
2711
|
}
|
|
2660
2712
|
async chat(messages, context, options) {
|
|
2661
|
-
var
|
|
2662
|
-
const basePrompt = (_b = (
|
|
2713
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2714
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2663
2715
|
const system = buildSystemContent(basePrompt, context);
|
|
2664
2716
|
const anthropicMessages = messages.map((m) => ({
|
|
2665
2717
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2670,7 +2722,7 @@ var AnthropicProvider = class {
|
|
|
2670
2722
|
const extraParams = {};
|
|
2671
2723
|
if (isThinkingEnabled && isClaude37) {
|
|
2672
2724
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2673
|
-
const maxTokens = (
|
|
2725
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2674
2726
|
const budget = Math.min(
|
|
2675
2727
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2676
2728
|
maxTokens - 1
|
|
@@ -2697,8 +2749,8 @@ var AnthropicProvider = class {
|
|
|
2697
2749
|
}
|
|
2698
2750
|
chatStream(messages, context, options) {
|
|
2699
2751
|
return __asyncGenerator(this, null, function* () {
|
|
2700
|
-
var
|
|
2701
|
-
const basePrompt = (_b = (
|
|
2752
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2753
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2702
2754
|
const system = buildSystemContent(basePrompt, context);
|
|
2703
2755
|
const anthropicMessages = messages.map((m) => ({
|
|
2704
2756
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2709,7 +2761,7 @@ var AnthropicProvider = class {
|
|
|
2709
2761
|
const extraParams = {};
|
|
2710
2762
|
if (isThinkingEnabled && isClaude37) {
|
|
2711
2763
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2712
|
-
const maxTokens = (
|
|
2764
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2713
2765
|
const budget = Math.min(
|
|
2714
2766
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2715
2767
|
maxTokens - 1
|
|
@@ -2782,8 +2834,8 @@ var AnthropicProvider = class {
|
|
|
2782
2834
|
var import_axios = __toESM(require("axios"));
|
|
2783
2835
|
var OllamaProvider = class {
|
|
2784
2836
|
constructor(llmConfig, embeddingConfig) {
|
|
2785
|
-
var
|
|
2786
|
-
const baseURL = (
|
|
2837
|
+
var _a2, _b;
|
|
2838
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2787
2839
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2788
2840
|
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2789
2841
|
this.llmConfig = llmConfig;
|
|
@@ -2841,8 +2893,8 @@ var OllamaProvider = class {
|
|
|
2841
2893
|
};
|
|
2842
2894
|
}
|
|
2843
2895
|
async chat(messages, context, options) {
|
|
2844
|
-
var
|
|
2845
|
-
const basePrompt = (_b = (
|
|
2896
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2897
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2846
2898
|
const system = buildSystemContent(basePrompt, context);
|
|
2847
2899
|
const { data } = await this.http.post("/api/chat", {
|
|
2848
2900
|
model: this.llmConfig.model,
|
|
@@ -2860,8 +2912,8 @@ var OllamaProvider = class {
|
|
|
2860
2912
|
}
|
|
2861
2913
|
chatStream(messages, context, options) {
|
|
2862
2914
|
return __asyncGenerator(this, null, function* () {
|
|
2863
|
-
var
|
|
2864
|
-
const basePrompt = (_b = (
|
|
2915
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2916
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2865
2917
|
const system = buildSystemContent(basePrompt, context);
|
|
2866
2918
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2867
2919
|
model: this.llmConfig.model,
|
|
@@ -2890,7 +2942,7 @@ var OllamaProvider = class {
|
|
|
2890
2942
|
if (!line.trim()) continue;
|
|
2891
2943
|
try {
|
|
2892
2944
|
const json = JSON.parse(line);
|
|
2893
|
-
if ((
|
|
2945
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2894
2946
|
yield json.message.content;
|
|
2895
2947
|
}
|
|
2896
2948
|
if (json.done) return;
|
|
@@ -2919,10 +2971,10 @@ var OllamaProvider = class {
|
|
|
2919
2971
|
});
|
|
2920
2972
|
}
|
|
2921
2973
|
async embed(text, options) {
|
|
2922
|
-
var
|
|
2923
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2974
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2975
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "nomic-embed-text";
|
|
2924
2976
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2925
|
-
const client = baseURL !== ((
|
|
2977
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2926
2978
|
let prompt = text;
|
|
2927
2979
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2928
2980
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -3021,9 +3073,9 @@ var GeminiProvider = class {
|
|
|
3021
3073
|
static getHealthChecker() {
|
|
3022
3074
|
return {
|
|
3023
3075
|
async check(config) {
|
|
3024
|
-
var
|
|
3076
|
+
var _a2, _b;
|
|
3025
3077
|
const timestamp = Date.now();
|
|
3026
|
-
const apiKey = (_b = (
|
|
3078
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
3027
3079
|
const modelName = sanitizeModel(config.model);
|
|
3028
3080
|
try {
|
|
3029
3081
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -3053,16 +3105,16 @@ var GeminiProvider = class {
|
|
|
3053
3105
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
3054
3106
|
* API key differs from the LLM API key. */
|
|
3055
3107
|
get embeddingClient() {
|
|
3056
|
-
var
|
|
3057
|
-
if (((
|
|
3108
|
+
var _a2;
|
|
3109
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
3058
3110
|
return buildClient(this.embeddingConfig.apiKey);
|
|
3059
3111
|
}
|
|
3060
3112
|
return this.client;
|
|
3061
3113
|
}
|
|
3062
3114
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
3063
3115
|
resolveEmbeddingModel(optionsModel) {
|
|
3064
|
-
var
|
|
3065
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3116
|
+
var _a2, _b;
|
|
3117
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
3066
3118
|
}
|
|
3067
3119
|
/**
|
|
3068
3120
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3082,8 +3134,8 @@ var GeminiProvider = class {
|
|
|
3082
3134
|
// ILLMProvider — chat
|
|
3083
3135
|
// -------------------------------------------------------------------------
|
|
3084
3136
|
async chat(messages, context, options) {
|
|
3085
|
-
var
|
|
3086
|
-
const basePrompt = (_b = (
|
|
3137
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3138
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3087
3139
|
const model = this.client.getGenerativeModel({
|
|
3088
3140
|
model: this.llmConfig.model,
|
|
3089
3141
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3100,8 +3152,8 @@ var GeminiProvider = class {
|
|
|
3100
3152
|
}
|
|
3101
3153
|
chatStream(messages, context, options) {
|
|
3102
3154
|
return __asyncGenerator(this, null, function* () {
|
|
3103
|
-
var
|
|
3104
|
-
const basePrompt = (_b = (
|
|
3155
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3156
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3105
3157
|
const model = this.client.getGenerativeModel({
|
|
3106
3158
|
model: this.llmConfig.model,
|
|
3107
3159
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3136,11 +3188,11 @@ var GeminiProvider = class {
|
|
|
3136
3188
|
// ILLMProvider — embeddings
|
|
3137
3189
|
// -------------------------------------------------------------------------
|
|
3138
3190
|
async embed(text, options) {
|
|
3139
|
-
var
|
|
3191
|
+
var _a2, _b;
|
|
3140
3192
|
const content = applyPrefix(
|
|
3141
3193
|
text,
|
|
3142
3194
|
options == null ? void 0 : options.taskType,
|
|
3143
|
-
(
|
|
3195
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3144
3196
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3145
3197
|
);
|
|
3146
3198
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3157,7 +3209,7 @@ var GeminiProvider = class {
|
|
|
3157
3209
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3158
3210
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3159
3211
|
const requests = texts.map((text) => {
|
|
3160
|
-
var
|
|
3212
|
+
var _a2, _b;
|
|
3161
3213
|
return {
|
|
3162
3214
|
content: {
|
|
3163
3215
|
role: "user",
|
|
@@ -3165,7 +3217,7 @@ var GeminiProvider = class {
|
|
|
3165
3217
|
text: applyPrefix(
|
|
3166
3218
|
text,
|
|
3167
3219
|
options == null ? void 0 : options.taskType,
|
|
3168
|
-
(
|
|
3220
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3169
3221
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3170
3222
|
)
|
|
3171
3223
|
}]
|
|
@@ -3182,8 +3234,8 @@ var GeminiProvider = class {
|
|
|
3182
3234
|
throw err;
|
|
3183
3235
|
});
|
|
3184
3236
|
return response.embeddings.map((e) => {
|
|
3185
|
-
var
|
|
3186
|
-
return (
|
|
3237
|
+
var _a2;
|
|
3238
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3187
3239
|
});
|
|
3188
3240
|
}
|
|
3189
3241
|
// -------------------------------------------------------------------------
|
|
@@ -3203,6 +3255,325 @@ var GeminiProvider = class {
|
|
|
3203
3255
|
}
|
|
3204
3256
|
};
|
|
3205
3257
|
|
|
3258
|
+
// src/llm/providers/GroqProvider.ts
|
|
3259
|
+
var import_openai2 = __toESM(require("openai"));
|
|
3260
|
+
var GroqProvider = class {
|
|
3261
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3262
|
+
void embeddingConfig;
|
|
3263
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3264
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3265
|
+
this.client = new import_openai2.default({
|
|
3266
|
+
apiKey,
|
|
3267
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3268
|
+
});
|
|
3269
|
+
this.llmConfig = llmConfig;
|
|
3270
|
+
}
|
|
3271
|
+
static getValidator() {
|
|
3272
|
+
return {
|
|
3273
|
+
validate(config) {
|
|
3274
|
+
const errors = [];
|
|
3275
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3276
|
+
errors.push({
|
|
3277
|
+
field: "llm.apiKey",
|
|
3278
|
+
message: "Groq API key is required",
|
|
3279
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3280
|
+
severity: "error"
|
|
3281
|
+
});
|
|
3282
|
+
}
|
|
3283
|
+
if (!config.model) {
|
|
3284
|
+
errors.push({
|
|
3285
|
+
field: "llm.model",
|
|
3286
|
+
message: "Groq model name is required",
|
|
3287
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3288
|
+
severity: "error"
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
return errors;
|
|
3292
|
+
}
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3295
|
+
static getHealthChecker() {
|
|
3296
|
+
return {
|
|
3297
|
+
async check(config) {
|
|
3298
|
+
const timestamp = Date.now();
|
|
3299
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3300
|
+
const modelName = config.model;
|
|
3301
|
+
try {
|
|
3302
|
+
const OpenAI4 = await import("openai");
|
|
3303
|
+
const client = new OpenAI4.default({
|
|
3304
|
+
apiKey,
|
|
3305
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3306
|
+
});
|
|
3307
|
+
const models = await client.models.list();
|
|
3308
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3309
|
+
return {
|
|
3310
|
+
healthy: true,
|
|
3311
|
+
provider: "groq",
|
|
3312
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3313
|
+
timestamp
|
|
3314
|
+
};
|
|
3315
|
+
} catch (error) {
|
|
3316
|
+
return {
|
|
3317
|
+
healthy: false,
|
|
3318
|
+
provider: "groq",
|
|
3319
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3320
|
+
timestamp
|
|
3321
|
+
};
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
};
|
|
3325
|
+
}
|
|
3326
|
+
async chat(messages, context, options) {
|
|
3327
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3328
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3329
|
+
const systemMessage = {
|
|
3330
|
+
role: "system",
|
|
3331
|
+
content: buildSystemContent(basePrompt, context)
|
|
3332
|
+
};
|
|
3333
|
+
const formattedMessages = [
|
|
3334
|
+
systemMessage,
|
|
3335
|
+
...messages.map((m) => ({
|
|
3336
|
+
role: m.role,
|
|
3337
|
+
content: m.content
|
|
3338
|
+
}))
|
|
3339
|
+
];
|
|
3340
|
+
const completion = await this.client.chat.completions.create({
|
|
3341
|
+
model: this.llmConfig.model,
|
|
3342
|
+
messages: formattedMessages,
|
|
3343
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3344
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3345
|
+
stop: options == null ? void 0 : options.stop
|
|
3346
|
+
});
|
|
3347
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3348
|
+
}
|
|
3349
|
+
chatStream(messages, context, options) {
|
|
3350
|
+
return __asyncGenerator(this, null, function* () {
|
|
3351
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3352
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3353
|
+
const systemMessage = {
|
|
3354
|
+
role: "system",
|
|
3355
|
+
content: buildSystemContent(basePrompt, context)
|
|
3356
|
+
};
|
|
3357
|
+
const formattedMessages = [
|
|
3358
|
+
systemMessage,
|
|
3359
|
+
...messages.map((m) => ({
|
|
3360
|
+
role: m.role,
|
|
3361
|
+
content: m.content
|
|
3362
|
+
}))
|
|
3363
|
+
];
|
|
3364
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3365
|
+
model: this.llmConfig.model,
|
|
3366
|
+
messages: formattedMessages,
|
|
3367
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3368
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3369
|
+
stop: options == null ? void 0 : options.stop,
|
|
3370
|
+
stream: true
|
|
3371
|
+
}));
|
|
3372
|
+
if (!stream) {
|
|
3373
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3374
|
+
}
|
|
3375
|
+
try {
|
|
3376
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3377
|
+
const chunk = temp.value;
|
|
3378
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3379
|
+
if (content) yield content;
|
|
3380
|
+
}
|
|
3381
|
+
} catch (temp) {
|
|
3382
|
+
error = [temp];
|
|
3383
|
+
} finally {
|
|
3384
|
+
try {
|
|
3385
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3386
|
+
} finally {
|
|
3387
|
+
if (error)
|
|
3388
|
+
throw error[0];
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
async embed(text, options) {
|
|
3394
|
+
void text;
|
|
3395
|
+
void options;
|
|
3396
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3397
|
+
}
|
|
3398
|
+
async batchEmbed(texts, options) {
|
|
3399
|
+
void texts;
|
|
3400
|
+
void options;
|
|
3401
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3402
|
+
}
|
|
3403
|
+
async ping() {
|
|
3404
|
+
try {
|
|
3405
|
+
await this.client.models.list();
|
|
3406
|
+
return true;
|
|
3407
|
+
} catch (err) {
|
|
3408
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3409
|
+
return false;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
};
|
|
3413
|
+
|
|
3414
|
+
// src/llm/providers/QwenProvider.ts
|
|
3415
|
+
var import_openai3 = __toESM(require("openai"));
|
|
3416
|
+
var QwenProvider = class {
|
|
3417
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3418
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3419
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3420
|
+
this.client = new import_openai3.default({
|
|
3421
|
+
apiKey,
|
|
3422
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3423
|
+
});
|
|
3424
|
+
this.llmConfig = llmConfig;
|
|
3425
|
+
this.embeddingConfig = embeddingConfig;
|
|
3426
|
+
}
|
|
3427
|
+
static getValidator() {
|
|
3428
|
+
return {
|
|
3429
|
+
validate(config) {
|
|
3430
|
+
const errors = [];
|
|
3431
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3432
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3433
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3434
|
+
errors.push({
|
|
3435
|
+
field: `${prefix}.apiKey`,
|
|
3436
|
+
message: "Qwen API key is required",
|
|
3437
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3438
|
+
severity: "error"
|
|
3439
|
+
});
|
|
3440
|
+
}
|
|
3441
|
+
if (!config.model) {
|
|
3442
|
+
errors.push({
|
|
3443
|
+
field: `${prefix}.model`,
|
|
3444
|
+
message: "Qwen model name is required",
|
|
3445
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3446
|
+
severity: "error"
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
return errors;
|
|
3450
|
+
}
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
static getHealthChecker() {
|
|
3454
|
+
return {
|
|
3455
|
+
async check(config) {
|
|
3456
|
+
const timestamp = Date.now();
|
|
3457
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3458
|
+
const modelName = config.model;
|
|
3459
|
+
try {
|
|
3460
|
+
const OpenAI4 = await import("openai");
|
|
3461
|
+
const client = new OpenAI4.default({
|
|
3462
|
+
apiKey,
|
|
3463
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3464
|
+
});
|
|
3465
|
+
const models = await client.models.list();
|
|
3466
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3467
|
+
return {
|
|
3468
|
+
healthy: true,
|
|
3469
|
+
provider: "qwen",
|
|
3470
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3471
|
+
timestamp
|
|
3472
|
+
};
|
|
3473
|
+
} catch (error) {
|
|
3474
|
+
return {
|
|
3475
|
+
healthy: false,
|
|
3476
|
+
provider: "qwen",
|
|
3477
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3478
|
+
timestamp
|
|
3479
|
+
};
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
async chat(messages, context, options) {
|
|
3485
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3486
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3487
|
+
const systemMessage = {
|
|
3488
|
+
role: "system",
|
|
3489
|
+
content: buildSystemContent(basePrompt, context)
|
|
3490
|
+
};
|
|
3491
|
+
const formattedMessages = [
|
|
3492
|
+
systemMessage,
|
|
3493
|
+
...messages.map((m) => ({
|
|
3494
|
+
role: m.role,
|
|
3495
|
+
content: m.content
|
|
3496
|
+
}))
|
|
3497
|
+
];
|
|
3498
|
+
const completion = await this.client.chat.completions.create({
|
|
3499
|
+
model: this.llmConfig.model,
|
|
3500
|
+
messages: formattedMessages,
|
|
3501
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3502
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3503
|
+
stop: options == null ? void 0 : options.stop
|
|
3504
|
+
});
|
|
3505
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3506
|
+
}
|
|
3507
|
+
chatStream(messages, context, options) {
|
|
3508
|
+
return __asyncGenerator(this, null, function* () {
|
|
3509
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3510
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3511
|
+
const systemMessage = {
|
|
3512
|
+
role: "system",
|
|
3513
|
+
content: buildSystemContent(basePrompt, context)
|
|
3514
|
+
};
|
|
3515
|
+
const formattedMessages = [
|
|
3516
|
+
systemMessage,
|
|
3517
|
+
...messages.map((m) => ({
|
|
3518
|
+
role: m.role,
|
|
3519
|
+
content: m.content
|
|
3520
|
+
}))
|
|
3521
|
+
];
|
|
3522
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3523
|
+
model: this.llmConfig.model,
|
|
3524
|
+
messages: formattedMessages,
|
|
3525
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3526
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3527
|
+
stop: options == null ? void 0 : options.stop,
|
|
3528
|
+
stream: true
|
|
3529
|
+
}));
|
|
3530
|
+
if (!stream) {
|
|
3531
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3532
|
+
}
|
|
3533
|
+
try {
|
|
3534
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3535
|
+
const chunk = temp.value;
|
|
3536
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3537
|
+
if (content) yield content;
|
|
3538
|
+
}
|
|
3539
|
+
} catch (temp) {
|
|
3540
|
+
error = [temp];
|
|
3541
|
+
} finally {
|
|
3542
|
+
try {
|
|
3543
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3544
|
+
} finally {
|
|
3545
|
+
if (error)
|
|
3546
|
+
throw error[0];
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
});
|
|
3550
|
+
}
|
|
3551
|
+
async embed(text, options) {
|
|
3552
|
+
const results = await this.batchEmbed([text], options);
|
|
3553
|
+
return results[0];
|
|
3554
|
+
}
|
|
3555
|
+
async batchEmbed(texts, options) {
|
|
3556
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3557
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-v1";
|
|
3558
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3559
|
+
const client = apiKey !== this.llmConfig.apiKey ? new import_openai3.default({
|
|
3560
|
+
apiKey,
|
|
3561
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3562
|
+
}) : this.client;
|
|
3563
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3564
|
+
return response.data.map((d) => d.embedding);
|
|
3565
|
+
}
|
|
3566
|
+
async ping() {
|
|
3567
|
+
try {
|
|
3568
|
+
await this.client.models.list();
|
|
3569
|
+
return true;
|
|
3570
|
+
} catch (err) {
|
|
3571
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3572
|
+
return false;
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
};
|
|
3576
|
+
|
|
3206
3577
|
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3207
3578
|
var import_axios2 = __toESM(require("axios"));
|
|
3208
3579
|
init_templateUtils();
|
|
@@ -3286,10 +3657,10 @@ var VECTOR_PROFILES = {
|
|
|
3286
3657
|
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3287
3658
|
var UniversalLLMAdapter = class {
|
|
3288
3659
|
constructor(config) {
|
|
3289
|
-
var
|
|
3660
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3290
3661
|
this.model = config.model;
|
|
3291
3662
|
const llmConfig = config;
|
|
3292
|
-
const options = (
|
|
3663
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3293
3664
|
let profile = {};
|
|
3294
3665
|
if (typeof options.profile === "string") {
|
|
3295
3666
|
profile = LLM_PROFILES[options.profile] || {};
|
|
@@ -3301,7 +3672,7 @@ var UniversalLLMAdapter = class {
|
|
|
3301
3672
|
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3302
3673
|
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3303
3674
|
this.apiKey = config.apiKey;
|
|
3304
|
-
this.baseUrl = (
|
|
3675
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3305
3676
|
if (!this.baseUrl) {
|
|
3306
3677
|
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3307
3678
|
}
|
|
@@ -3315,8 +3686,8 @@ var UniversalLLMAdapter = class {
|
|
|
3315
3686
|
});
|
|
3316
3687
|
}
|
|
3317
3688
|
async chat(messages, context) {
|
|
3318
|
-
var
|
|
3319
|
-
const
|
|
3689
|
+
var _a2, _b;
|
|
3690
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3320
3691
|
const formattedMessages = [
|
|
3321
3692
|
{ role: "system", content: `${this.systemPrompt}
|
|
3322
3693
|
|
|
@@ -3340,7 +3711,7 @@ ${context != null ? context : "None"}` },
|
|
|
3340
3711
|
temperature: this.temperature
|
|
3341
3712
|
};
|
|
3342
3713
|
}
|
|
3343
|
-
const { data } = await this.http.post(
|
|
3714
|
+
const { data } = await this.http.post(path2, payload);
|
|
3344
3715
|
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3345
3716
|
const result = resolvePath(data, extractPath);
|
|
3346
3717
|
if (result === void 0) {
|
|
@@ -3355,9 +3726,9 @@ ${context != null ? context : "None"}` },
|
|
|
3355
3726
|
*/
|
|
3356
3727
|
chatStream(messages, context) {
|
|
3357
3728
|
return __asyncGenerator(this, null, function* () {
|
|
3358
|
-
var
|
|
3359
|
-
const
|
|
3360
|
-
const url = `${this.baseUrl.replace(/\/$/, "")}${
|
|
3729
|
+
var _a2, _b, _c;
|
|
3730
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3731
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3361
3732
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3362
3733
|
const formattedMessages = [
|
|
3363
3734
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3435,8 +3806,8 @@ ${context != null ? context : "None"}` },
|
|
|
3435
3806
|
});
|
|
3436
3807
|
}
|
|
3437
3808
|
async embed(text) {
|
|
3438
|
-
var
|
|
3439
|
-
const
|
|
3809
|
+
var _a2, _b;
|
|
3810
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3440
3811
|
let payload;
|
|
3441
3812
|
if (this.opts.embedPayloadTemplate) {
|
|
3442
3813
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3449,7 +3820,7 @@ ${context != null ? context : "None"}` },
|
|
|
3449
3820
|
input: text
|
|
3450
3821
|
};
|
|
3451
3822
|
}
|
|
3452
|
-
const { data } = await this.http.post(
|
|
3823
|
+
const { data } = await this.http.post(path2, payload);
|
|
3453
3824
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3454
3825
|
const vector = resolvePath(data, extractPath);
|
|
3455
3826
|
if (!Array.isArray(vector)) {
|
|
@@ -3517,13 +3888,13 @@ var AuthenticationException = class extends RetrivoraError {
|
|
|
3517
3888
|
}
|
|
3518
3889
|
};
|
|
3519
3890
|
function wrapError(err, defaultCode, defaultMessage) {
|
|
3520
|
-
var
|
|
3891
|
+
var _a2;
|
|
3521
3892
|
if (err instanceof RetrivoraError) {
|
|
3522
3893
|
return err;
|
|
3523
3894
|
}
|
|
3524
3895
|
const error = err;
|
|
3525
3896
|
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3526
|
-
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((
|
|
3897
|
+
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
|
|
3527
3898
|
const code = error == null ? void 0 : error.code;
|
|
3528
3899
|
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3529
3900
|
return new RateLimitException(message, err);
|
|
@@ -3587,6 +3958,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3587
3958
|
"anthropic",
|
|
3588
3959
|
"ollama",
|
|
3589
3960
|
"gemini",
|
|
3961
|
+
"groq",
|
|
3962
|
+
"qwen",
|
|
3590
3963
|
"rest",
|
|
3591
3964
|
"universal_rest",
|
|
3592
3965
|
"custom",
|
|
@@ -3594,7 +3967,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3594
3967
|
];
|
|
3595
3968
|
}
|
|
3596
3969
|
static create(llmConfig, embeddingConfig) {
|
|
3597
|
-
var
|
|
3970
|
+
var _a2, _b, _c;
|
|
3598
3971
|
switch (llmConfig.provider) {
|
|
3599
3972
|
case "openai":
|
|
3600
3973
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3604,12 +3977,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3604
3977
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3605
3978
|
case "gemini":
|
|
3606
3979
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3980
|
+
case "groq":
|
|
3981
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3982
|
+
case "qwen":
|
|
3983
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3607
3984
|
case "rest":
|
|
3608
3985
|
case "universal_rest":
|
|
3609
3986
|
case "custom":
|
|
3610
3987
|
return new UniversalLLMAdapter(llmConfig);
|
|
3611
3988
|
default: {
|
|
3612
|
-
const providerName = String((
|
|
3989
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3613
3990
|
const customFactory = customProviders.get(providerName);
|
|
3614
3991
|
if (customFactory) {
|
|
3615
3992
|
return customFactory(llmConfig);
|
|
@@ -3646,6 +4023,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3646
4023
|
return OllamaProvider;
|
|
3647
4024
|
case "gemini":
|
|
3648
4025
|
return GeminiProvider;
|
|
4026
|
+
case "groq":
|
|
4027
|
+
return GroqProvider;
|
|
4028
|
+
case "qwen":
|
|
4029
|
+
return QwenProvider;
|
|
3649
4030
|
case "rest":
|
|
3650
4031
|
case "universal_rest":
|
|
3651
4032
|
case "custom":
|
|
@@ -3707,7 +4088,7 @@ var ProviderRegistry = class {
|
|
|
3707
4088
|
return null;
|
|
3708
4089
|
}
|
|
3709
4090
|
static async loadVectorProviderClass(provider) {
|
|
3710
|
-
var
|
|
4091
|
+
var _a2;
|
|
3711
4092
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3712
4093
|
switch (provider) {
|
|
3713
4094
|
case "pinecone": {
|
|
@@ -3716,7 +4097,7 @@ var ProviderRegistry = class {
|
|
|
3716
4097
|
}
|
|
3717
4098
|
case "pgvector":
|
|
3718
4099
|
case "postgresql": {
|
|
3719
|
-
const postgresMode = ((
|
|
4100
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3720
4101
|
if (postgresMode === "single") {
|
|
3721
4102
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3722
4103
|
return PostgreSQLProvider2;
|
|
@@ -3936,6 +4317,211 @@ var ConfigValidator = class {
|
|
|
3936
4317
|
}
|
|
3937
4318
|
};
|
|
3938
4319
|
|
|
4320
|
+
// src/core/LicenseVerifier.ts
|
|
4321
|
+
var crypto2 = __toESM(require("crypto"));
|
|
4322
|
+
var LicenseVerifier = class {
|
|
4323
|
+
/**
|
|
4324
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
4325
|
+
*
|
|
4326
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
4327
|
+
* @param currentProjectId - Project namespace ID.
|
|
4328
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
4329
|
+
*/
|
|
4330
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
4331
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4332
|
+
const now = Date.now();
|
|
4333
|
+
if (licenseKey) {
|
|
4334
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
4335
|
+
const cached = this.cache.get(cacheKey);
|
|
4336
|
+
if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
|
|
4337
|
+
const currentTimestampSec = Math.floor(now / 1e3);
|
|
4338
|
+
if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
|
|
4339
|
+
this.cache.delete(cacheKey);
|
|
4340
|
+
} else {
|
|
4341
|
+
return cached.payload;
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
if (!licenseKey) {
|
|
4346
|
+
if (isProduction) {
|
|
4347
|
+
throw new ConfigurationException(
|
|
4348
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
4349
|
+
);
|
|
4350
|
+
}
|
|
4351
|
+
console.warn(
|
|
4352
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
4353
|
+
);
|
|
4354
|
+
return {
|
|
4355
|
+
projectId: currentProjectId,
|
|
4356
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
4357
|
+
// Valid for 24h
|
|
4358
|
+
tier: "hobby"
|
|
4359
|
+
};
|
|
4360
|
+
}
|
|
4361
|
+
try {
|
|
4362
|
+
const parts = licenseKey.split(".");
|
|
4363
|
+
if (parts.length !== 3) {
|
|
4364
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
4365
|
+
}
|
|
4366
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
4367
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
4368
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
4369
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
4370
|
+
const data = Buffer.from(dataToVerify);
|
|
4371
|
+
const isValid = crypto2.verify(
|
|
4372
|
+
"sha256",
|
|
4373
|
+
data,
|
|
4374
|
+
publicKey,
|
|
4375
|
+
signature
|
|
4376
|
+
);
|
|
4377
|
+
if (!isValid) {
|
|
4378
|
+
throw new Error("Signature verification failed.");
|
|
4379
|
+
}
|
|
4380
|
+
const payload = JSON.parse(
|
|
4381
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4382
|
+
);
|
|
4383
|
+
if (!payload.projectId) {
|
|
4384
|
+
throw new Error('License payload is missing "projectId".');
|
|
4385
|
+
}
|
|
4386
|
+
if (payload.projectId !== currentProjectId) {
|
|
4387
|
+
throw new Error(
|
|
4388
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
if (!payload.expiresAt) {
|
|
4392
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
4393
|
+
}
|
|
4394
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
4395
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
4396
|
+
throw new Error(
|
|
4397
|
+
`License key has expired. Expiration: ${new Date(
|
|
4398
|
+
payload.expiresAt * 1e3
|
|
4399
|
+
).toDateString()}`
|
|
4400
|
+
);
|
|
4401
|
+
}
|
|
4402
|
+
if (isProduction && provider) {
|
|
4403
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
4404
|
+
const normalizedProvider = provider.toLowerCase();
|
|
4405
|
+
if (tier === "hobby") {
|
|
4406
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
4407
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
4408
|
+
throw new Error(
|
|
4409
|
+
`The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
4410
|
+
);
|
|
4411
|
+
}
|
|
4412
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
4413
|
+
const allowedPro = [
|
|
4414
|
+
"postgresql",
|
|
4415
|
+
"pgvector",
|
|
4416
|
+
"supabase",
|
|
4417
|
+
"pinecone",
|
|
4418
|
+
"qdrant",
|
|
4419
|
+
"mongodb",
|
|
4420
|
+
"milvus",
|
|
4421
|
+
"chroma",
|
|
4422
|
+
"chromadb"
|
|
4423
|
+
];
|
|
4424
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
4425
|
+
throw new Error(
|
|
4426
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
4427
|
+
);
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
if (licenseKey) {
|
|
4432
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
4433
|
+
this.cache.set(cacheKey, { payload, cachedAt: now });
|
|
4434
|
+
}
|
|
4435
|
+
return payload;
|
|
4436
|
+
} catch (err) {
|
|
4437
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4438
|
+
throw new ConfigurationException(
|
|
4439
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
4440
|
+
);
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
static async verifyIP(licenseKey) {
|
|
4444
|
+
if (!licenseKey) return;
|
|
4445
|
+
try {
|
|
4446
|
+
const parts = licenseKey.split(".");
|
|
4447
|
+
if (parts.length !== 3) return;
|
|
4448
|
+
const [, payloadB64] = parts;
|
|
4449
|
+
const payload = JSON.parse(
|
|
4450
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4451
|
+
);
|
|
4452
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
4453
|
+
if (tier === "enterprise" || tier === "custom") {
|
|
4454
|
+
return;
|
|
4455
|
+
}
|
|
4456
|
+
if (payload.ipv4 || payload.ipv6) {
|
|
4457
|
+
let currentIpv4 = "";
|
|
4458
|
+
let currentIpv6 = "";
|
|
4459
|
+
try {
|
|
4460
|
+
const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
4461
|
+
const data = await res.json();
|
|
4462
|
+
currentIpv4 = data.ip;
|
|
4463
|
+
} catch (e) {
|
|
4464
|
+
}
|
|
4465
|
+
try {
|
|
4466
|
+
const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
4467
|
+
const data = await res.json();
|
|
4468
|
+
currentIpv6 = data.ip;
|
|
4469
|
+
} catch (e) {
|
|
4470
|
+
}
|
|
4471
|
+
const localIps = [];
|
|
4472
|
+
try {
|
|
4473
|
+
const osModule = require("os");
|
|
4474
|
+
const interfaces = osModule.networkInterfaces();
|
|
4475
|
+
for (const name of Object.keys(interfaces)) {
|
|
4476
|
+
for (const iface of interfaces[name] || []) {
|
|
4477
|
+
if (!iface.internal) {
|
|
4478
|
+
localIps.push(iface.address);
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
} catch (e) {
|
|
4483
|
+
}
|
|
4484
|
+
const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
|
|
4485
|
+
const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
|
|
4486
|
+
if (payload.ipv4 && payload.ipv6) {
|
|
4487
|
+
if (!isIpv4Match && !isIpv6Match) {
|
|
4488
|
+
throw new Error(
|
|
4489
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
4490
|
+
);
|
|
4491
|
+
}
|
|
4492
|
+
} else if (payload.ipv4 && !isIpv4Match) {
|
|
4493
|
+
throw new Error(
|
|
4494
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
|
|
4495
|
+
);
|
|
4496
|
+
} else if (payload.ipv6 && !isIpv6Match) {
|
|
4497
|
+
throw new Error(
|
|
4498
|
+
`License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
4499
|
+
);
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
} catch (err) {
|
|
4503
|
+
if (err.message.includes("License key access restricted")) {
|
|
4504
|
+
throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
};
|
|
4509
|
+
// A simple in-memory cache to save CPU overhead of cryptographic signature checks.
|
|
4510
|
+
LicenseVerifier.cache = /* @__PURE__ */ new Map();
|
|
4511
|
+
LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
|
|
4512
|
+
// Cache verified license for 60 seconds
|
|
4513
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
4514
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
4515
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
4516
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
4517
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
4518
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
4519
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
4520
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
4521
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
4522
|
+
MwIDAQAB
|
|
4523
|
+
-----END PUBLIC KEY-----`;
|
|
4524
|
+
|
|
3939
4525
|
// src/rag/DocumentChunker.ts
|
|
3940
4526
|
var DocumentChunker = class {
|
|
3941
4527
|
constructor(chunkSize = 1e3, chunkOverlap = 200, separators = ["\n# ", "\n## ", "\n### ", "\n#### ", "\n\n", "\n", " ", ""]) {
|
|
@@ -4165,11 +4751,11 @@ var LlamaIndexIngestor = class {
|
|
|
4165
4751
|
* than standard character-count splitting.
|
|
4166
4752
|
*/
|
|
4167
4753
|
async chunk(text, options = {}) {
|
|
4168
|
-
var
|
|
4754
|
+
var _a2, _b;
|
|
4169
4755
|
try {
|
|
4170
4756
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4171
4757
|
const splitter = new SentenceSplitter({
|
|
4172
|
-
chunkSize: (
|
|
4758
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4173
4759
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4174
4760
|
});
|
|
4175
4761
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4278,7 +4864,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4278
4864
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4279
4865
|
*/
|
|
4280
4866
|
async run(input, chatHistory = []) {
|
|
4281
|
-
var
|
|
4867
|
+
var _a2, _b, _c;
|
|
4282
4868
|
if (!this.agent) {
|
|
4283
4869
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4284
4870
|
}
|
|
@@ -4289,14 +4875,445 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4289
4875
|
const response = await this.agent.invoke({
|
|
4290
4876
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4291
4877
|
});
|
|
4292
|
-
const lastMessage = (
|
|
4293
|
-
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4294
|
-
return lastMessage.content;
|
|
4295
|
-
}
|
|
4296
|
-
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
4297
|
-
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4298
|
-
}
|
|
4299
|
-
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
4878
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4879
|
+
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4880
|
+
return lastMessage.content;
|
|
4881
|
+
}
|
|
4882
|
+
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
4883
|
+
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4884
|
+
}
|
|
4885
|
+
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
4886
|
+
}
|
|
4887
|
+
};
|
|
4888
|
+
|
|
4889
|
+
// src/core/mcp.ts
|
|
4890
|
+
var import_child_process = require("child_process");
|
|
4891
|
+
var MCPClient = class {
|
|
4892
|
+
constructor(config) {
|
|
4893
|
+
this.config = config;
|
|
4894
|
+
this.messageIdCounter = 0;
|
|
4895
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4896
|
+
this.stdioBuffer = "";
|
|
4897
|
+
this.initialized = false;
|
|
4898
|
+
}
|
|
4899
|
+
getNextMessageId() {
|
|
4900
|
+
return ++this.messageIdCounter;
|
|
4901
|
+
}
|
|
4902
|
+
/**
|
|
4903
|
+
* Connect and initialize the MCP server connection.
|
|
4904
|
+
*/
|
|
4905
|
+
async connect() {
|
|
4906
|
+
if (this.initialized) return;
|
|
4907
|
+
if (this.config.transport === "stdio") {
|
|
4908
|
+
await this.connectStdio();
|
|
4909
|
+
} else {
|
|
4910
|
+
await this.connectSSE();
|
|
4911
|
+
}
|
|
4912
|
+
try {
|
|
4913
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4914
|
+
protocolVersion: "2024-11-05",
|
|
4915
|
+
capabilities: {},
|
|
4916
|
+
clientInfo: {
|
|
4917
|
+
name: "retrivora-sdk",
|
|
4918
|
+
version: "1.0.0"
|
|
4919
|
+
}
|
|
4920
|
+
});
|
|
4921
|
+
await this.sendNotification("notifications/initialized");
|
|
4922
|
+
this.initialized = true;
|
|
4923
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4924
|
+
} catch (err) {
|
|
4925
|
+
this.disconnect();
|
|
4926
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
async connectStdio() {
|
|
4930
|
+
var _a2;
|
|
4931
|
+
const cmd = this.config.command;
|
|
4932
|
+
if (!cmd) {
|
|
4933
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4934
|
+
}
|
|
4935
|
+
const args = this.config.args || [];
|
|
4936
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4937
|
+
this.childProcess = (0, import_child_process.spawn)(cmd, args, { env, shell: true });
|
|
4938
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4939
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4940
|
+
}
|
|
4941
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4942
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4943
|
+
this.processStdioLines();
|
|
4944
|
+
});
|
|
4945
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4946
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4947
|
+
});
|
|
4948
|
+
this.childProcess.on("close", (code) => {
|
|
4949
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4950
|
+
this.disconnect();
|
|
4951
|
+
});
|
|
4952
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4953
|
+
}
|
|
4954
|
+
processStdioLines() {
|
|
4955
|
+
let newlineIndex;
|
|
4956
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4957
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4958
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4959
|
+
if (!line) continue;
|
|
4960
|
+
try {
|
|
4961
|
+
const payload = JSON.parse(line);
|
|
4962
|
+
if (payload.id !== void 0) {
|
|
4963
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4964
|
+
if (req) {
|
|
4965
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4966
|
+
if (payload.error) {
|
|
4967
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4968
|
+
} else {
|
|
4969
|
+
req.resolve(payload.result);
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
} catch (e) {
|
|
4974
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4975
|
+
}
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
async connectSSE() {
|
|
4979
|
+
if (!this.config.url) {
|
|
4980
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4981
|
+
}
|
|
4982
|
+
this.sseUrl = this.config.url;
|
|
4983
|
+
}
|
|
4984
|
+
async sendJsonRpc(method, params) {
|
|
4985
|
+
const id = this.getNextMessageId();
|
|
4986
|
+
const request = {
|
|
4987
|
+
jsonrpc: "2.0",
|
|
4988
|
+
id,
|
|
4989
|
+
method,
|
|
4990
|
+
params
|
|
4991
|
+
};
|
|
4992
|
+
if (this.config.transport === "stdio") {
|
|
4993
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4994
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4995
|
+
}
|
|
4996
|
+
return new Promise((resolve, reject) => {
|
|
4997
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4998
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4999
|
+
});
|
|
5000
|
+
} else {
|
|
5001
|
+
if (!this.sseUrl) {
|
|
5002
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
5003
|
+
}
|
|
5004
|
+
const response = await fetch(this.sseUrl, {
|
|
5005
|
+
method: "POST",
|
|
5006
|
+
headers: { "Content-Type": "application/json" },
|
|
5007
|
+
body: JSON.stringify(request)
|
|
5008
|
+
});
|
|
5009
|
+
if (!response.ok) {
|
|
5010
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
5011
|
+
}
|
|
5012
|
+
const payload = await response.json();
|
|
5013
|
+
if (payload.error) {
|
|
5014
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
5015
|
+
}
|
|
5016
|
+
return payload.result;
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
5019
|
+
async sendNotification(method, params) {
|
|
5020
|
+
var _a2;
|
|
5021
|
+
const notification = {
|
|
5022
|
+
jsonrpc: "2.0",
|
|
5023
|
+
method,
|
|
5024
|
+
params
|
|
5025
|
+
};
|
|
5026
|
+
if (this.config.transport === "stdio") {
|
|
5027
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
5028
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
5029
|
+
}
|
|
5030
|
+
} else if (this.sseUrl) {
|
|
5031
|
+
await fetch(this.sseUrl, {
|
|
5032
|
+
method: "POST",
|
|
5033
|
+
headers: { "Content-Type": "application/json" },
|
|
5034
|
+
body: JSON.stringify(notification)
|
|
5035
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
/**
|
|
5039
|
+
* List all tools offered by the MCP server.
|
|
5040
|
+
*/
|
|
5041
|
+
async listTools() {
|
|
5042
|
+
await this.connect();
|
|
5043
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
5044
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
5045
|
+
}
|
|
5046
|
+
/**
|
|
5047
|
+
* Execute a tool on the MCP server.
|
|
5048
|
+
*/
|
|
5049
|
+
async callTool(name, args = {}) {
|
|
5050
|
+
await this.connect();
|
|
5051
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
5052
|
+
}
|
|
5053
|
+
disconnect() {
|
|
5054
|
+
this.initialized = false;
|
|
5055
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
5056
|
+
this.pendingRequests.clear();
|
|
5057
|
+
if (this.childProcess) {
|
|
5058
|
+
try {
|
|
5059
|
+
this.childProcess.kill();
|
|
5060
|
+
} catch (e) {
|
|
5061
|
+
}
|
|
5062
|
+
this.childProcess = void 0;
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
};
|
|
5066
|
+
var MCPRegistry = class {
|
|
5067
|
+
constructor(servers = []) {
|
|
5068
|
+
this.clients = [];
|
|
5069
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
5070
|
+
}
|
|
5071
|
+
async getAllTools() {
|
|
5072
|
+
const list = [];
|
|
5073
|
+
await Promise.all(
|
|
5074
|
+
this.clients.map(async (client) => {
|
|
5075
|
+
try {
|
|
5076
|
+
const tools = await client.listTools();
|
|
5077
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
5078
|
+
} catch (e) {
|
|
5079
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
5080
|
+
}
|
|
5081
|
+
})
|
|
5082
|
+
);
|
|
5083
|
+
return list;
|
|
5084
|
+
}
|
|
5085
|
+
async callTool(toolName, args = {}) {
|
|
5086
|
+
for (const client of this.clients) {
|
|
5087
|
+
try {
|
|
5088
|
+
const tools = await client.listTools();
|
|
5089
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
5090
|
+
return await client.callTool(toolName, args);
|
|
5091
|
+
}
|
|
5092
|
+
} catch (e) {
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5095
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
5096
|
+
}
|
|
5097
|
+
disconnectAll() {
|
|
5098
|
+
this.clients.forEach((c) => c.disconnect());
|
|
5099
|
+
}
|
|
5100
|
+
};
|
|
5101
|
+
|
|
5102
|
+
// src/core/MultiAgentCoordinator.ts
|
|
5103
|
+
var MultiAgentCoordinator = class {
|
|
5104
|
+
constructor(options) {
|
|
5105
|
+
var _a2;
|
|
5106
|
+
this.llmProvider = options.llmProvider;
|
|
5107
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
5108
|
+
this.documentSearch = options.documentSearch;
|
|
5109
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
5110
|
+
}
|
|
5111
|
+
/**
|
|
5112
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
5113
|
+
*/
|
|
5114
|
+
async run(question, history = []) {
|
|
5115
|
+
const generator = this.runStream(question, history);
|
|
5116
|
+
let finalReply = "";
|
|
5117
|
+
const sources = [];
|
|
5118
|
+
try {
|
|
5119
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
5120
|
+
const chunk = temp.value;
|
|
5121
|
+
if (typeof chunk === "string") {
|
|
5122
|
+
finalReply += chunk;
|
|
5123
|
+
} else if (chunk && typeof chunk === "object") {
|
|
5124
|
+
if ("reply" in chunk && chunk.reply) {
|
|
5125
|
+
finalReply += chunk.reply;
|
|
5126
|
+
}
|
|
5127
|
+
if ("sources" in chunk && chunk.sources) {
|
|
5128
|
+
sources.push(...chunk.sources);
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
} catch (temp) {
|
|
5133
|
+
error = [temp];
|
|
5134
|
+
} finally {
|
|
5135
|
+
try {
|
|
5136
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
5137
|
+
} finally {
|
|
5138
|
+
if (error)
|
|
5139
|
+
throw error[0];
|
|
5140
|
+
}
|
|
5141
|
+
}
|
|
5142
|
+
return {
|
|
5143
|
+
reply: finalReply,
|
|
5144
|
+
sources
|
|
5145
|
+
};
|
|
5146
|
+
}
|
|
5147
|
+
/**
|
|
5148
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
5149
|
+
*/
|
|
5150
|
+
runStream(_0) {
|
|
5151
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
5152
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
5153
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
5154
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
5155
|
+
|
|
5156
|
+
Available Tools:
|
|
5157
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
5158
|
+
|
|
5159
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
5160
|
+
${mcpTools.map((mt) => {
|
|
5161
|
+
var _a2;
|
|
5162
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
5163
|
+
}).join("\n")}
|
|
5164
|
+
|
|
5165
|
+
Tool Calling Protocol:
|
|
5166
|
+
If you need to call a tool, write:
|
|
5167
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
5168
|
+
And then STOP generating immediately.
|
|
5169
|
+
|
|
5170
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
5171
|
+
`;
|
|
5172
|
+
const supervisorHistory = [
|
|
5173
|
+
{ role: "system", content: systemPrompt },
|
|
5174
|
+
...history,
|
|
5175
|
+
{ role: "user", content: question }
|
|
5176
|
+
];
|
|
5177
|
+
let iteration = 0;
|
|
5178
|
+
const allSources = [];
|
|
5179
|
+
while (iteration < this.maxIterations) {
|
|
5180
|
+
iteration++;
|
|
5181
|
+
const context = "";
|
|
5182
|
+
let fullModelResponse = "";
|
|
5183
|
+
let textBuffer = "";
|
|
5184
|
+
let inThinking = false;
|
|
5185
|
+
let toolCallDetected = null;
|
|
5186
|
+
if (!this.llmProvider.chatStream) {
|
|
5187
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
5188
|
+
fullModelResponse = reply;
|
|
5189
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
5190
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
5191
|
+
let thinkingText = "";
|
|
5192
|
+
let answerText = reply;
|
|
5193
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
5194
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
5195
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
5196
|
+
yield { type: "thinking", text: thinkingText };
|
|
5197
|
+
}
|
|
5198
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5199
|
+
if (toolMatch) {
|
|
5200
|
+
const toolName = toolMatch[1];
|
|
5201
|
+
const toolArgsStr = toolMatch[2];
|
|
5202
|
+
try {
|
|
5203
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5204
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5205
|
+
} catch (e) {
|
|
5206
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5207
|
+
}
|
|
5208
|
+
} else {
|
|
5209
|
+
yield answerText;
|
|
5210
|
+
}
|
|
5211
|
+
} else {
|
|
5212
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
5213
|
+
try {
|
|
5214
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
5215
|
+
const chunk = temp.value;
|
|
5216
|
+
fullModelResponse += chunk;
|
|
5217
|
+
textBuffer += chunk;
|
|
5218
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
5219
|
+
inThinking = true;
|
|
5220
|
+
const idx = textBuffer.indexOf("<think>");
|
|
5221
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
5222
|
+
}
|
|
5223
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
5224
|
+
inThinking = false;
|
|
5225
|
+
const idx = textBuffer.indexOf("</think>");
|
|
5226
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
5227
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
5228
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
5229
|
+
}
|
|
5230
|
+
if (inThinking && textBuffer.length > 0) {
|
|
5231
|
+
yield { type: "thinking", text: textBuffer };
|
|
5232
|
+
textBuffer = "";
|
|
5233
|
+
}
|
|
5234
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
5235
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
5236
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
5237
|
+
if (precedingText.trim()) {
|
|
5238
|
+
yield precedingText;
|
|
5239
|
+
}
|
|
5240
|
+
textBuffer = textBuffer.slice(idx);
|
|
5241
|
+
}
|
|
5242
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
5243
|
+
yield textBuffer;
|
|
5244
|
+
textBuffer = "";
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
} catch (temp) {
|
|
5248
|
+
error = [temp];
|
|
5249
|
+
} finally {
|
|
5250
|
+
try {
|
|
5251
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
5252
|
+
} finally {
|
|
5253
|
+
if (error)
|
|
5254
|
+
throw error[0];
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
if (textBuffer.trim()) {
|
|
5258
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5259
|
+
if (toolMatch) {
|
|
5260
|
+
const toolName = toolMatch[1];
|
|
5261
|
+
const toolArgsStr = toolMatch[2];
|
|
5262
|
+
try {
|
|
5263
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5264
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5265
|
+
} catch (e) {
|
|
5266
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5267
|
+
}
|
|
5268
|
+
} else {
|
|
5269
|
+
yield textBuffer;
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
5274
|
+
if (toolCallDetected) {
|
|
5275
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
5276
|
+
yield {
|
|
5277
|
+
type: "thinking",
|
|
5278
|
+
text: `
|
|
5279
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
5280
|
+
`
|
|
5281
|
+
};
|
|
5282
|
+
let toolResultText = "";
|
|
5283
|
+
try {
|
|
5284
|
+
if (toolName === "document_search") {
|
|
5285
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
5286
|
+
toolResultText = `document_search returned:
|
|
5287
|
+
${searchRes.reply}
|
|
5288
|
+
|
|
5289
|
+
Sources count: ${searchRes.sources.length}`;
|
|
5290
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
5291
|
+
allSources.push(...searchRes.sources);
|
|
5292
|
+
yield { reply: "", sources: searchRes.sources };
|
|
5293
|
+
}
|
|
5294
|
+
} else {
|
|
5295
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
5296
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
5297
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
5298
|
+
}
|
|
5299
|
+
} catch (err) {
|
|
5300
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
5301
|
+
}
|
|
5302
|
+
supervisorHistory.push({
|
|
5303
|
+
role: "user",
|
|
5304
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
5305
|
+
${toolResultText}`
|
|
5306
|
+
});
|
|
5307
|
+
yield {
|
|
5308
|
+
type: "thinking",
|
|
5309
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
5310
|
+
`
|
|
5311
|
+
};
|
|
5312
|
+
} else {
|
|
5313
|
+
break;
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5316
|
+
});
|
|
4300
5317
|
}
|
|
4301
5318
|
};
|
|
4302
5319
|
|
|
@@ -4626,7 +5643,7 @@ var QueryProcessor = class {
|
|
|
4626
5643
|
* @param validFields Optional list of known filterable fields to look for
|
|
4627
5644
|
*/
|
|
4628
5645
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4629
|
-
var
|
|
5646
|
+
var _a2, _b, _c, _d;
|
|
4630
5647
|
if (!question.trim()) return [];
|
|
4631
5648
|
const hints = /* @__PURE__ */ new Map();
|
|
4632
5649
|
const addHint = (value, field) => {
|
|
@@ -4706,7 +5723,7 @@ var QueryProcessor = class {
|
|
|
4706
5723
|
];
|
|
4707
5724
|
for (const p of universalPatterns) {
|
|
4708
5725
|
for (const match of question.matchAll(p.regex)) {
|
|
4709
|
-
const val = p.group ? (
|
|
5726
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4710
5727
|
if (!val) continue;
|
|
4711
5728
|
if (p.field) addHint(val, p.field);
|
|
4712
5729
|
else addHint(val);
|
|
@@ -4930,11 +5947,11 @@ var LLMRouter = class {
|
|
|
4930
5947
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4931
5948
|
*/
|
|
4932
5949
|
async initialize(prebuiltDefault) {
|
|
4933
|
-
var
|
|
5950
|
+
var _a2;
|
|
4934
5951
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4935
5952
|
this.models.set("default", defaultModel);
|
|
4936
5953
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4937
|
-
const providerFastDefault = (
|
|
5954
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4938
5955
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4939
5956
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4940
5957
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4953,8 +5970,8 @@ var LLMRouter = class {
|
|
|
4953
5970
|
* Falls back to 'default' if the requested role is not registered.
|
|
4954
5971
|
*/
|
|
4955
5972
|
get(role) {
|
|
4956
|
-
var
|
|
4957
|
-
const provider = (
|
|
5973
|
+
var _a2;
|
|
5974
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4958
5975
|
if (!provider) {
|
|
4959
5976
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4960
5977
|
}
|
|
@@ -4972,7 +5989,7 @@ var UITransformer = class _UITransformer {
|
|
|
4972
5989
|
* Prefer `analyzeAndDecide()` in production.
|
|
4973
5990
|
*/
|
|
4974
5991
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4975
|
-
var
|
|
5992
|
+
var _a2, _b, _c;
|
|
4976
5993
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4977
5994
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4978
5995
|
}
|
|
@@ -4992,7 +6009,7 @@ var UITransformer = class _UITransformer {
|
|
|
4992
6009
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4993
6010
|
}
|
|
4994
6011
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4995
|
-
return (
|
|
6012
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4996
6013
|
}
|
|
4997
6014
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4998
6015
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5317,11 +6334,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5317
6334
|
};
|
|
5318
6335
|
}
|
|
5319
6336
|
static transformToPieChart(data, profile, query = "") {
|
|
5320
|
-
var
|
|
6337
|
+
var _a2;
|
|
5321
6338
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5322
6339
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5323
|
-
var
|
|
5324
|
-
return String((
|
|
6340
|
+
var _a3;
|
|
6341
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5325
6342
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5326
6343
|
if (categories.length === 0) return null;
|
|
5327
6344
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5331,7 +6348,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5331
6348
|
});
|
|
5332
6349
|
return {
|
|
5333
6350
|
type: "pie_chart",
|
|
5334
|
-
title: `Distribution by ${(
|
|
6351
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5335
6352
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5336
6353
|
data: pieData
|
|
5337
6354
|
};
|
|
@@ -5341,8 +6358,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5341
6358
|
const valueField = profile.numericFields[0];
|
|
5342
6359
|
const buckets = /* @__PURE__ */ new Map();
|
|
5343
6360
|
profile.records.forEach((record) => {
|
|
5344
|
-
var
|
|
5345
|
-
const timestamp = String((
|
|
6361
|
+
var _a2, _b, _c;
|
|
6362
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5346
6363
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5347
6364
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5348
6365
|
});
|
|
@@ -5355,23 +6372,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5355
6372
|
};
|
|
5356
6373
|
}
|
|
5357
6374
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5358
|
-
var
|
|
6375
|
+
var _a2;
|
|
5359
6376
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5360
6377
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5361
6378
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5362
6379
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5363
6380
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5364
|
-
var
|
|
6381
|
+
var _a3, _b, _c, _d, _e;
|
|
5365
6382
|
const meta = item.metadata || {};
|
|
5366
6383
|
const label = String(
|
|
5367
|
-
(_c = (_b = (
|
|
6384
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5368
6385
|
);
|
|
5369
6386
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5370
6387
|
return { category: label, value: Number(value) };
|
|
5371
6388
|
});
|
|
5372
6389
|
return {
|
|
5373
6390
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5374
|
-
title: dimension ? `${(
|
|
6391
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5375
6392
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5376
6393
|
data: fallbackData
|
|
5377
6394
|
};
|
|
@@ -5406,11 +6423,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5406
6423
|
if (fields.length < 2) return null;
|
|
5407
6424
|
const [xField, yField] = fields;
|
|
5408
6425
|
const points = profile.records.map((record) => {
|
|
5409
|
-
var
|
|
6426
|
+
var _a2;
|
|
5410
6427
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5411
6428
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5412
6429
|
if (x === null || y === null) return null;
|
|
5413
|
-
return { x, y, label: String((
|
|
6430
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5414
6431
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5415
6432
|
if (points.length === 0) return null;
|
|
5416
6433
|
return {
|
|
@@ -5440,9 +6457,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5440
6457
|
static transformToRadarChart(data) {
|
|
5441
6458
|
const attributeMap = {};
|
|
5442
6459
|
data.forEach((item) => {
|
|
5443
|
-
var
|
|
6460
|
+
var _a2, _b, _c;
|
|
5444
6461
|
const meta = item.metadata || {};
|
|
5445
|
-
const seriesName = String((_c = (_b = (
|
|
6462
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5446
6463
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5447
6464
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5448
6465
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5524,22 +6541,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5524
6541
|
return null;
|
|
5525
6542
|
}
|
|
5526
6543
|
static normalizeTransformation(payload) {
|
|
5527
|
-
var
|
|
6544
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5528
6545
|
if (!payload || typeof payload !== "object") return null;
|
|
5529
6546
|
const p = payload;
|
|
5530
6547
|
const type = this.normalizeVisualizationType(
|
|
5531
|
-
String((_c = (_b = (
|
|
6548
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5532
6549
|
);
|
|
5533
6550
|
if (!type) return null;
|
|
5534
6551
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5535
6552
|
const description = p.description ? String(p.description) : void 0;
|
|
5536
|
-
const rawData = (_j = (_i = (_h = (
|
|
6553
|
+
const rawData = (_j = (_i = (_h = (_g2 = (_f = p.data) != null ? _f : p.table) != null ? _g2 : p.rows) != null ? _h : p.items) != null ? _i : p.content) != null ? _j : null;
|
|
5537
6554
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5538
6555
|
const transformation = { type, title, description, data };
|
|
5539
6556
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5540
6557
|
}
|
|
5541
6558
|
static normalizeVisualizationType(type) {
|
|
5542
|
-
var
|
|
6559
|
+
var _a2;
|
|
5543
6560
|
const mapping = {
|
|
5544
6561
|
pie: "pie_chart",
|
|
5545
6562
|
pie_chart: "pie_chart",
|
|
@@ -5567,7 +6584,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5567
6584
|
product_carousel: "product_carousel",
|
|
5568
6585
|
carousel: "carousel"
|
|
5569
6586
|
};
|
|
5570
|
-
return (
|
|
6587
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5571
6588
|
}
|
|
5572
6589
|
static validateTransformation(t) {
|
|
5573
6590
|
const { type, data } = t;
|
|
@@ -5769,16 +6786,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5769
6786
|
return null;
|
|
5770
6787
|
}
|
|
5771
6788
|
static selectDimensionField(profile, query) {
|
|
5772
|
-
var
|
|
6789
|
+
var _a2, _b;
|
|
5773
6790
|
const productCategory = profile.categoricalFields.find(
|
|
5774
6791
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5775
6792
|
);
|
|
5776
6793
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5777
|
-
return (_b = (
|
|
6794
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5778
6795
|
}
|
|
5779
6796
|
static selectNumericField(profile, query) {
|
|
5780
|
-
var
|
|
5781
|
-
return (
|
|
6797
|
+
var _a2;
|
|
6798
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5782
6799
|
}
|
|
5783
6800
|
static rankFieldsByQuery(fields, query) {
|
|
5784
6801
|
const q = query.toLowerCase();
|
|
@@ -5807,8 +6824,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5807
6824
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5808
6825
|
const result = {};
|
|
5809
6826
|
profile.records.forEach((record) => {
|
|
5810
|
-
var
|
|
5811
|
-
const category = String((
|
|
6827
|
+
var _a2, _b, _c;
|
|
6828
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5812
6829
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5813
6830
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5814
6831
|
});
|
|
@@ -5887,8 +6904,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5887
6904
|
static aggregateByCategory(data, categories) {
|
|
5888
6905
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5889
6906
|
data.forEach((item) => {
|
|
5890
|
-
var
|
|
5891
|
-
const cat = (
|
|
6907
|
+
var _a2;
|
|
6908
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5892
6909
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5893
6910
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5894
6911
|
});
|
|
@@ -5896,17 +6913,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5896
6913
|
}
|
|
5897
6914
|
static extractTimeSeriesData(data) {
|
|
5898
6915
|
return data.map((item) => {
|
|
5899
|
-
var
|
|
6916
|
+
var _a2, _b, _c, _d, _e;
|
|
5900
6917
|
const meta = item.metadata || {};
|
|
5901
6918
|
return {
|
|
5902
|
-
timestamp: (_b = (
|
|
6919
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5903
6920
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5904
6921
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5905
6922
|
};
|
|
5906
6923
|
});
|
|
5907
6924
|
}
|
|
5908
6925
|
static extractNumericValue(meta) {
|
|
5909
|
-
var
|
|
6926
|
+
var _a2;
|
|
5910
6927
|
const preferredKeys = [
|
|
5911
6928
|
"value",
|
|
5912
6929
|
"count",
|
|
@@ -5921,7 +6938,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5921
6938
|
"price"
|
|
5922
6939
|
];
|
|
5923
6940
|
for (const key of preferredKeys) {
|
|
5924
|
-
const raw = (
|
|
6941
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5925
6942
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5926
6943
|
if (Number.isFinite(value)) return value;
|
|
5927
6944
|
}
|
|
@@ -6067,8 +7084,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
6067
7084
|
let inStock = 0;
|
|
6068
7085
|
let outOfStock = 0;
|
|
6069
7086
|
data.forEach((d) => {
|
|
6070
|
-
var
|
|
6071
|
-
const cat = (
|
|
7087
|
+
var _a2, _b;
|
|
7088
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
6072
7089
|
if (cat === category) {
|
|
6073
7090
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
6074
7091
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -6112,9 +7129,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
6112
7129
|
}
|
|
6113
7130
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
6114
7131
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
6115
|
-
var
|
|
7132
|
+
var _a2;
|
|
6116
7133
|
if (!meta) return void 0;
|
|
6117
|
-
const mapping = (
|
|
7134
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
6118
7135
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
6119
7136
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
6120
7137
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -6123,13 +7140,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6123
7140
|
return resolveMetadataValue(meta, uiKey);
|
|
6124
7141
|
}
|
|
6125
7142
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6126
|
-
var
|
|
7143
|
+
var _a2;
|
|
6127
7144
|
const meta = item.metadata || {};
|
|
6128
7145
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6129
7146
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6130
7147
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6131
7148
|
const description = this.cleanProductDescription(
|
|
6132
|
-
(
|
|
7149
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6133
7150
|
);
|
|
6134
7151
|
if (name || this.isProductData(item)) {
|
|
6135
7152
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6237,10 +7254,10 @@ RULES:
|
|
|
6237
7254
|
}
|
|
6238
7255
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6239
7256
|
const items = sources.map((s, i) => {
|
|
6240
|
-
var
|
|
7257
|
+
var _a2, _b, _c, _d;
|
|
6241
7258
|
return {
|
|
6242
7259
|
index: i + 1,
|
|
6243
|
-
content: (_b = (
|
|
7260
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6244
7261
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6245
7262
|
score: (_d = s.score) != null ? _d : 0
|
|
6246
7263
|
};
|
|
@@ -6433,9 +7450,11 @@ var Pipeline = class {
|
|
|
6433
7450
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6434
7451
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6435
7452
|
this.initialised = false;
|
|
6436
|
-
|
|
7453
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7454
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7455
|
+
var _a2, _b, _c, _d, _e;
|
|
6437
7456
|
this.chunker = new DocumentChunker(
|
|
6438
|
-
(_b = (
|
|
7457
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6439
7458
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6440
7459
|
);
|
|
6441
7460
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6451,7 +7470,7 @@ var Pipeline = class {
|
|
|
6451
7470
|
return this.initialised ? this.llmProvider : void 0;
|
|
6452
7471
|
}
|
|
6453
7472
|
async initialize() {
|
|
6454
|
-
var
|
|
7473
|
+
var _a2, _b, _c, _d;
|
|
6455
7474
|
if (this.initialised) return;
|
|
6456
7475
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6457
7476
|
|
|
@@ -6494,12 +7513,47 @@ var Pipeline = class {
|
|
|
6494
7513
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6495
7514
|
}
|
|
6496
7515
|
await this.vectorDB.initialize();
|
|
6497
|
-
if (((
|
|
7516
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7517
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7518
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7519
|
+
llmProvider: this.llmProvider,
|
|
7520
|
+
mcpRegistry: this.mcpRegistry,
|
|
7521
|
+
documentSearch: async (query) => {
|
|
7522
|
+
return this.runNormalQuery(query);
|
|
7523
|
+
}
|
|
7524
|
+
});
|
|
6498
7525
|
this.agent = new LangChainAgent(this, this.config);
|
|
6499
7526
|
await this.agent.initialize(this.llmProvider);
|
|
6500
7527
|
}
|
|
7528
|
+
if ((_d = (_c = this.config.rag) == null ? void 0 : _c.cag) == null ? void 0 : _d.enabled) {
|
|
7529
|
+
await this.loadColdContext(this.config.projectId);
|
|
7530
|
+
}
|
|
6501
7531
|
this.initialised = true;
|
|
6502
7532
|
}
|
|
7533
|
+
async loadColdContext(ns) {
|
|
7534
|
+
var _a2, _b;
|
|
7535
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7536
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7537
|
+
try {
|
|
7538
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7539
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7540
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7541
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7542
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7543
|
+
if (coldMatches.length > 0) {
|
|
7544
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7545
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7546
|
+
this.coldContexts.set(ns, formatted);
|
|
7547
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7548
|
+
} else {
|
|
7549
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7550
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7551
|
+
}
|
|
7552
|
+
} catch (err) {
|
|
7553
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7554
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7555
|
+
}
|
|
7556
|
+
}
|
|
6503
7557
|
/**
|
|
6504
7558
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6505
7559
|
*/
|
|
@@ -6531,12 +7585,12 @@ var Pipeline = class {
|
|
|
6531
7585
|
}
|
|
6532
7586
|
/** Step 1: Chunk the document content. */
|
|
6533
7587
|
async prepareChunks(doc) {
|
|
6534
|
-
var
|
|
7588
|
+
var _a2, _b;
|
|
6535
7589
|
if (this.llamaIngestor) {
|
|
6536
7590
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6537
7591
|
docId: doc.docId,
|
|
6538
7592
|
metadata: doc.metadata,
|
|
6539
|
-
chunkSize: (
|
|
7593
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6540
7594
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6541
7595
|
});
|
|
6542
7596
|
}
|
|
@@ -6607,12 +7661,37 @@ var Pipeline = class {
|
|
|
6607
7661
|
extractionOptions
|
|
6608
7662
|
);
|
|
6609
7663
|
}
|
|
7664
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7665
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7666
|
+
let reply = "";
|
|
7667
|
+
let sources = [];
|
|
7668
|
+
try {
|
|
7669
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7670
|
+
const chunk = temp.value;
|
|
7671
|
+
if (typeof chunk === "string") {
|
|
7672
|
+
reply += chunk;
|
|
7673
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7674
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7675
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7676
|
+
}
|
|
7677
|
+
}
|
|
7678
|
+
} catch (temp) {
|
|
7679
|
+
error = [temp];
|
|
7680
|
+
} finally {
|
|
7681
|
+
try {
|
|
7682
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7683
|
+
} finally {
|
|
7684
|
+
if (error)
|
|
7685
|
+
throw error[0];
|
|
7686
|
+
}
|
|
7687
|
+
}
|
|
7688
|
+
return { reply, sources };
|
|
7689
|
+
}
|
|
6610
7690
|
async ask(question, history = [], namespace) {
|
|
6611
|
-
var
|
|
7691
|
+
var _a2, _b;
|
|
6612
7692
|
await this.initialize();
|
|
6613
|
-
if (((
|
|
6614
|
-
|
|
6615
|
-
return { reply: agentReply, sources: [] };
|
|
7693
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7694
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6616
7695
|
}
|
|
6617
7696
|
const stream = this.askStream(question, history, namespace);
|
|
6618
7697
|
let reply = "";
|
|
@@ -6644,6 +7723,47 @@ var Pipeline = class {
|
|
|
6644
7723
|
}
|
|
6645
7724
|
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
6646
7725
|
}
|
|
7726
|
+
askStream(_0) {
|
|
7727
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7728
|
+
var _a2, _b;
|
|
7729
|
+
yield new __await(this.initialize());
|
|
7730
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7731
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7732
|
+
try {
|
|
7733
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7734
|
+
const chunk = temp.value;
|
|
7735
|
+
yield chunk;
|
|
7736
|
+
}
|
|
7737
|
+
} catch (temp) {
|
|
7738
|
+
error = [temp];
|
|
7739
|
+
} finally {
|
|
7740
|
+
try {
|
|
7741
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7742
|
+
} finally {
|
|
7743
|
+
if (error)
|
|
7744
|
+
throw error[0];
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7747
|
+
return;
|
|
7748
|
+
}
|
|
7749
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7750
|
+
try {
|
|
7751
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7752
|
+
const chunk = temp2.value;
|
|
7753
|
+
yield chunk;
|
|
7754
|
+
}
|
|
7755
|
+
} catch (temp2) {
|
|
7756
|
+
error2 = [temp2];
|
|
7757
|
+
} finally {
|
|
7758
|
+
try {
|
|
7759
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7760
|
+
} finally {
|
|
7761
|
+
if (error2)
|
|
7762
|
+
throw error2[0];
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
});
|
|
7766
|
+
}
|
|
6647
7767
|
/**
|
|
6648
7768
|
* High-performance streaming RAG flow.
|
|
6649
7769
|
* Yields text chunks first, then the retrieval metadata + observability trace at the end.
|
|
@@ -6654,12 +7774,12 @@ var Pipeline = class {
|
|
|
6654
7774
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6655
7775
|
* - SchemaMapper.train runs while answer generation streams
|
|
6656
7776
|
*/
|
|
6657
|
-
|
|
7777
|
+
askStreamInternal(_0) {
|
|
6658
7778
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6659
|
-
var
|
|
7779
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
|
|
6660
7780
|
yield new __await(this.initialize());
|
|
6661
7781
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6662
|
-
const topK = (_b = (
|
|
7782
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6663
7783
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6664
7784
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6665
7785
|
const requestStart = performance.now();
|
|
@@ -6672,20 +7792,21 @@ var Pipeline = class {
|
|
|
6672
7792
|
}
|
|
6673
7793
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6674
7794
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6675
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7795
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6676
7796
|
if (numericPredicates.length > 0) {
|
|
6677
7797
|
filter.__numericPredicates = numericPredicates;
|
|
6678
7798
|
}
|
|
6679
7799
|
const embedStart = performance.now();
|
|
6680
7800
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6681
7801
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6682
|
-
const
|
|
7802
|
+
const arch = (_h = this.config.rag) == null ? void 0 : _h.architecture;
|
|
7803
|
+
const useGraph = arch !== "naive" && arch !== "retrieve-and-rerank" && this.graphDB && ((_i = this.config.rag) == null ? void 0 : _i.useGraphRetrieval);
|
|
6683
7804
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6684
7805
|
QueryProcessor.determineRetrievalStrategy(
|
|
6685
7806
|
searchQuery,
|
|
6686
7807
|
useGraph ? this.llmRouter.get("fast") : void 0,
|
|
6687
|
-
(
|
|
6688
|
-
(
|
|
7808
|
+
(_j = this.config.rag) == null ? void 0 : _j.graphKeywords,
|
|
7809
|
+
(_k = this.config.rag) == null ? void 0 : _k.vectorKeywords
|
|
6689
7810
|
),
|
|
6690
7811
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6691
7812
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6695,7 +7816,7 @@ var Pipeline = class {
|
|
|
6695
7816
|
if (!cachedVector && queryVector.length > 0) {
|
|
6696
7817
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6697
7818
|
}
|
|
6698
|
-
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((
|
|
7819
|
+
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_l = this.config.rag) == null ? void 0 : _l.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
|
|
6699
7820
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6700
7821
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6701
7822
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6708,7 +7829,8 @@ var Pipeline = class {
|
|
|
6708
7829
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6709
7830
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6710
7831
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6711
|
-
|
|
7832
|
+
const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
|
|
7833
|
+
if (!hasNumericPredicates && useReranking) {
|
|
6712
7834
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6713
7835
|
} else if (!wantsExhaustiveList) {
|
|
6714
7836
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6738,6 +7860,32 @@ ${graphContext}
|
|
|
6738
7860
|
VECTOR CONTEXT:
|
|
6739
7861
|
${context}`;
|
|
6740
7862
|
}
|
|
7863
|
+
if ((_o = (_n = this.config.rag) == null ? void 0 : _n.cag) == null ? void 0 : _o.enabled) {
|
|
7864
|
+
if (!this.coldContexts.has(ns)) {
|
|
7865
|
+
yield new __await(this.loadColdContext(ns));
|
|
7866
|
+
}
|
|
7867
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7868
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7869
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7870
|
+
${coldContext}
|
|
7871
|
+
|
|
7872
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7873
|
+
${context}`;
|
|
7874
|
+
}
|
|
7875
|
+
}
|
|
7876
|
+
yield {
|
|
7877
|
+
reply: "",
|
|
7878
|
+
sources: sources.map((s) => {
|
|
7879
|
+
var _a3;
|
|
7880
|
+
return {
|
|
7881
|
+
id: s.id,
|
|
7882
|
+
score: s.score,
|
|
7883
|
+
content: s.content,
|
|
7884
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7885
|
+
namespace: ns
|
|
7886
|
+
};
|
|
7887
|
+
})
|
|
7888
|
+
};
|
|
6741
7889
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6742
7890
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6743
7891
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6765,10 +7913,10 @@ ${context}`;
|
|
|
6765
7913
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6766
7914
|
const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
|
|
6767
7915
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6768
|
-
const isNativeThinking = isClaude37 && (((
|
|
7916
|
+
const isNativeThinking = isClaude37 && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
|
|
6769
7917
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6770
7918
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6771
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7919
|
+
const isSimulatedThinking = !isNativeThinking && (((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === true || ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) === "enabled" || isReasoningModel && ((_u = this.config.llm.options) == null ? void 0 : _u.thinking) !== false);
|
|
6772
7920
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6773
7921
|
if (isSimulatedThinking) {
|
|
6774
7922
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
@@ -6776,7 +7924,7 @@ ${context}`;
|
|
|
6776
7924
|
const hardenedHistory = [...history];
|
|
6777
7925
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6778
7926
|
const messages = [...hardenedHistory, userQuestion];
|
|
6779
|
-
const systemPrompt = (
|
|
7927
|
+
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
6780
7928
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6781
7929
|
let fullReply = "";
|
|
6782
7930
|
let thinkingText = "";
|
|
@@ -6887,7 +8035,7 @@ ${context}`;
|
|
|
6887
8035
|
}
|
|
6888
8036
|
yield fullReply;
|
|
6889
8037
|
}
|
|
6890
|
-
const runHallucination = ((
|
|
8038
|
+
const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_x = this.config.llm.options) == null ? void 0 : _x.hallucinationScoring) !== false;
|
|
6891
8039
|
if (runHallucination) {
|
|
6892
8040
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6893
8041
|
}
|
|
@@ -6896,7 +8044,7 @@ ${context}`;
|
|
|
6896
8044
|
const latency = {
|
|
6897
8045
|
embedMs: Math.round(embedMs),
|
|
6898
8046
|
retrieveMs: Math.round(retrieveMs),
|
|
6899
|
-
rerankMs: ((
|
|
8047
|
+
rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
|
|
6900
8048
|
generateMs: Math.round(generateMs),
|
|
6901
8049
|
totalMs: Math.round(totalMs)
|
|
6902
8050
|
};
|
|
@@ -6909,33 +8057,63 @@ ${context}`;
|
|
|
6909
8057
|
totalTokens: promptTokens + completionTokens,
|
|
6910
8058
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6911
8059
|
};
|
|
8060
|
+
const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
|
|
6912
8061
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6913
8062
|
uiTransformationPromise,
|
|
6914
|
-
hallucinationScoringPromise
|
|
8063
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6915
8064
|
]));
|
|
6916
|
-
const
|
|
8065
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6917
8066
|
requestId,
|
|
6918
8067
|
query: question,
|
|
6919
8068
|
rewrittenQuery,
|
|
6920
8069
|
systemPrompt,
|
|
6921
8070
|
userPrompt: question + finalRestrictionSuffix,
|
|
6922
8071
|
chunks: sources.map((s) => {
|
|
6923
|
-
var
|
|
8072
|
+
var _a3;
|
|
6924
8073
|
return {
|
|
6925
8074
|
id: s.id,
|
|
6926
8075
|
score: s.score,
|
|
6927
8076
|
content: s.content,
|
|
6928
|
-
metadata: (
|
|
8077
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6929
8078
|
namespace: ns
|
|
6930
8079
|
};
|
|
6931
8080
|
}),
|
|
6932
8081
|
latency,
|
|
6933
8082
|
tokens,
|
|
6934
8083
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6935
|
-
},
|
|
6936
|
-
hallucinationScore:
|
|
6937
|
-
hallucinationReason:
|
|
8084
|
+
}, hScore ? {
|
|
8085
|
+
hallucinationScore: hScore.score,
|
|
8086
|
+
hallucinationReason: hScore.reason
|
|
6938
8087
|
} : {});
|
|
8088
|
+
const trace = buildTrace(hallucinationResult);
|
|
8089
|
+
if ((_A = this.config.telemetry) == null ? void 0 : _A.enabled) {
|
|
8090
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
8091
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
8092
|
+
(async () => {
|
|
8093
|
+
try {
|
|
8094
|
+
let finalTrace = trace;
|
|
8095
|
+
if (!awaitHallucination && runHallucination) {
|
|
8096
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
8097
|
+
if (backgroundScoreResult) {
|
|
8098
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
8101
|
+
await fetch(absoluteUrl, {
|
|
8102
|
+
method: "POST",
|
|
8103
|
+
headers: {
|
|
8104
|
+
"Content-Type": "application/json"
|
|
8105
|
+
},
|
|
8106
|
+
body: JSON.stringify({
|
|
8107
|
+
trace: finalTrace,
|
|
8108
|
+
licenseKey: this.config.licenseKey,
|
|
8109
|
+
projectId: ns
|
|
8110
|
+
})
|
|
8111
|
+
});
|
|
8112
|
+
} catch (err) {
|
|
8113
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
8114
|
+
}
|
|
8115
|
+
})();
|
|
8116
|
+
}
|
|
6939
8117
|
yield {
|
|
6940
8118
|
reply: "",
|
|
6941
8119
|
sources,
|
|
@@ -6955,7 +8133,7 @@ ${context}`;
|
|
|
6955
8133
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6956
8134
|
*/
|
|
6957
8135
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6958
|
-
var
|
|
8136
|
+
var _a2;
|
|
6959
8137
|
if (!sources || sources.length === 0) {
|
|
6960
8138
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6961
8139
|
}
|
|
@@ -6969,7 +8147,7 @@ ${context}`;
|
|
|
6969
8147
|
);
|
|
6970
8148
|
}
|
|
6971
8149
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6972
|
-
const disableLlmUiTransform = ((
|
|
8150
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6973
8151
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6974
8152
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6975
8153
|
}
|
|
@@ -6987,9 +8165,9 @@ ${context}`;
|
|
|
6987
8165
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6988
8166
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6989
8167
|
})).sort((a, b) => {
|
|
6990
|
-
var
|
|
8168
|
+
var _a2, _b;
|
|
6991
8169
|
const primary = predicates[0];
|
|
6992
|
-
const aValue = (
|
|
8170
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6993
8171
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6994
8172
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6995
8173
|
});
|
|
@@ -7061,8 +8239,8 @@ ${context}`;
|
|
|
7061
8239
|
return Number.isFinite(numeric) ? numeric : null;
|
|
7062
8240
|
}
|
|
7063
8241
|
async retrieve(query, options) {
|
|
7064
|
-
var
|
|
7065
|
-
const ns = (
|
|
8242
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
8243
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
7066
8244
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
7067
8245
|
const cacheKey = `${ns}::${query}`;
|
|
7068
8246
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -7094,7 +8272,7 @@ ${context}`;
|
|
|
7094
8272
|
) : [];
|
|
7095
8273
|
const resolvedSources = [];
|
|
7096
8274
|
for (const source of sources) {
|
|
7097
|
-
const parentId = (
|
|
8275
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
7098
8276
|
if (parentId) {
|
|
7099
8277
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
7100
8278
|
resolvedSources.push(source);
|
|
@@ -7176,8 +8354,15 @@ var Retrivora = class {
|
|
|
7176
8354
|
this.pipeline = new Pipeline(this.config);
|
|
7177
8355
|
}
|
|
7178
8356
|
async initialize() {
|
|
8357
|
+
var _a2;
|
|
7179
8358
|
try {
|
|
7180
8359
|
await ConfigValidator.validateAndThrow(this.config);
|
|
8360
|
+
LicenseVerifier.verify(
|
|
8361
|
+
this.config.licenseKey,
|
|
8362
|
+
this.config.projectId,
|
|
8363
|
+
(_a2 = this.config.vectorDb) == null ? void 0 : _a2.provider
|
|
8364
|
+
);
|
|
8365
|
+
await LicenseVerifier.verifyIP(this.config.licenseKey);
|
|
7181
8366
|
} catch (err) {
|
|
7182
8367
|
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
7183
8368
|
}
|
|
@@ -7351,11 +8536,20 @@ var ProviderHealthCheck = class {
|
|
|
7351
8536
|
// src/core/VectorPlugin.ts
|
|
7352
8537
|
var VectorPlugin = class {
|
|
7353
8538
|
constructor(hostConfig) {
|
|
7354
|
-
|
|
7355
|
-
this.
|
|
8539
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8540
|
+
this.config = resolvedConfig;
|
|
8541
|
+
this.validationPromise = (async () => {
|
|
8542
|
+
var _a2;
|
|
8543
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8544
|
+
LicenseVerifier.verify(
|
|
8545
|
+
resolvedConfig.licenseKey,
|
|
8546
|
+
resolvedConfig.projectId,
|
|
8547
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8548
|
+
);
|
|
8549
|
+
})();
|
|
7356
8550
|
this.validationPromise.catch(() => {
|
|
7357
8551
|
});
|
|
7358
|
-
this.pipeline = new Pipeline(
|
|
8552
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7359
8553
|
}
|
|
7360
8554
|
/**
|
|
7361
8555
|
* Get the current resolved configuration.
|
|
@@ -7491,13 +8685,13 @@ var ConfigBuilder = class {
|
|
|
7491
8685
|
* Configure the vector database provider
|
|
7492
8686
|
*/
|
|
7493
8687
|
vectorDb(provider, options) {
|
|
7494
|
-
var
|
|
8688
|
+
var _a2;
|
|
7495
8689
|
if (provider === "auto") {
|
|
7496
8690
|
this._vectorDb = this._autoDetectVectorDb();
|
|
7497
8691
|
} else {
|
|
7498
8692
|
this._vectorDb = {
|
|
7499
8693
|
provider,
|
|
7500
|
-
indexName: (
|
|
8694
|
+
indexName: (_a2 = options == null ? void 0 : options.indexName) != null ? _a2 : "default",
|
|
7501
8695
|
options: __spreadValues({}, options)
|
|
7502
8696
|
};
|
|
7503
8697
|
}
|
|
@@ -7507,7 +8701,7 @@ var ConfigBuilder = class {
|
|
|
7507
8701
|
* Configure the LLM provider for chat
|
|
7508
8702
|
*/
|
|
7509
8703
|
llm(provider, model, apiKey, options) {
|
|
7510
|
-
var
|
|
8704
|
+
var _a2, _b;
|
|
7511
8705
|
if (provider === "auto") {
|
|
7512
8706
|
this._llm = this._autoDetectLLM();
|
|
7513
8707
|
} else {
|
|
@@ -7516,7 +8710,7 @@ var ConfigBuilder = class {
|
|
|
7516
8710
|
model: model != null ? model : "default-model",
|
|
7517
8711
|
apiKey,
|
|
7518
8712
|
systemPrompt: options == null ? void 0 : options.systemPrompt,
|
|
7519
|
-
maxTokens: (
|
|
8713
|
+
maxTokens: (_a2 = options == null ? void 0 : options.maxTokens) != null ? _a2 : 1024,
|
|
7520
8714
|
temperature: (_b = options == null ? void 0 : options.temperature) != null ? _b : 0.7,
|
|
7521
8715
|
baseUrl: options == null ? void 0 : options.baseUrl,
|
|
7522
8716
|
options
|
|
@@ -7559,8 +8753,8 @@ var ConfigBuilder = class {
|
|
|
7559
8753
|
* Set RAG-specific pipeline parameters
|
|
7560
8754
|
*/
|
|
7561
8755
|
rag(options) {
|
|
7562
|
-
var
|
|
7563
|
-
this._rag = __spreadValues(__spreadValues({}, (
|
|
8756
|
+
var _a2;
|
|
8757
|
+
this._rag = __spreadValues(__spreadValues({}, (_a2 = this._rag) != null ? _a2 : {}), options);
|
|
7564
8758
|
return this;
|
|
7565
8759
|
}
|
|
7566
8760
|
/**
|
|
@@ -7576,7 +8770,7 @@ var ConfigBuilder = class {
|
|
|
7576
8770
|
* Throws if required fields (projectId, vectorDb, llm, embedding) are not set.
|
|
7577
8771
|
*/
|
|
7578
8772
|
build() {
|
|
7579
|
-
var
|
|
8773
|
+
var _a2;
|
|
7580
8774
|
const missing = [];
|
|
7581
8775
|
if (!this._projectId) missing.push('projectId (call .projectId("my-app"))');
|
|
7582
8776
|
if (!this._vectorDb) missing.push('vectorDb (call .vectorDb("pinecone", { ... }))');
|
|
@@ -7588,7 +8782,7 @@ var ConfigBuilder = class {
|
|
|
7588
8782
|
${missing.join("\n ")}`
|
|
7589
8783
|
);
|
|
7590
8784
|
}
|
|
7591
|
-
const ragConfig = (
|
|
8785
|
+
const ragConfig = (_a2 = this._rag) != null ? _a2 : { chunkSize: 1e3, chunkOverlap: 200, topK: 5 };
|
|
7592
8786
|
if (process.env.RAG_USE_GRAPH_RETRIEVAL === "true") {
|
|
7593
8787
|
ragConfig.useGraphRetrieval = true;
|
|
7594
8788
|
}
|
|
@@ -7684,8 +8878,8 @@ var DocumentParser = class {
|
|
|
7684
8878
|
* Extract text from a File or Buffer based on its type.
|
|
7685
8879
|
*/
|
|
7686
8880
|
static async parse(file, fileName, mimeType) {
|
|
7687
|
-
var
|
|
7688
|
-
const extension = (
|
|
8881
|
+
var _a2;
|
|
8882
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7689
8883
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7690
8884
|
return this.readAsText(file);
|
|
7691
8885
|
}
|
|
@@ -7752,6 +8946,497 @@ init_UniversalVectorProvider();
|
|
|
7752
8946
|
|
|
7753
8947
|
// src/handlers/index.ts
|
|
7754
8948
|
var import_server = require("next/server");
|
|
8949
|
+
|
|
8950
|
+
// src/core/DatabaseStorage.ts
|
|
8951
|
+
var fs = __toESM(require("fs"));
|
|
8952
|
+
var path = __toESM(require("path"));
|
|
8953
|
+
var DatabaseStorage = class {
|
|
8954
|
+
constructor(config) {
|
|
8955
|
+
// Dynamic PG Pool
|
|
8956
|
+
this.pgPool = null;
|
|
8957
|
+
// Dynamic MongoDB Client
|
|
8958
|
+
this.mongoClient = null;
|
|
8959
|
+
this.mongoDbName = "";
|
|
8960
|
+
// Filesystem fallback configuration
|
|
8961
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8962
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8963
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8964
|
+
var _a2, _b, _c, _d, _e;
|
|
8965
|
+
this.config = config;
|
|
8966
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8967
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8968
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8969
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8970
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8971
|
+
}
|
|
8972
|
+
/**
|
|
8973
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8974
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8975
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8976
|
+
*/
|
|
8977
|
+
checkPremiumSubscription() {
|
|
8978
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8979
|
+
return;
|
|
8980
|
+
}
|
|
8981
|
+
if (!this.config.licenseKey) {
|
|
8982
|
+
throw new Error(
|
|
8983
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8984
|
+
);
|
|
8985
|
+
}
|
|
8986
|
+
try {
|
|
8987
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8988
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8989
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8990
|
+
throw new Error(
|
|
8991
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8992
|
+
);
|
|
8993
|
+
}
|
|
8994
|
+
} catch (err) {
|
|
8995
|
+
throw new Error(
|
|
8996
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8997
|
+
);
|
|
8998
|
+
}
|
|
8999
|
+
}
|
|
9000
|
+
checkHistoryEnabled() {
|
|
9001
|
+
var _a2, _b;
|
|
9002
|
+
this.checkPremiumSubscription();
|
|
9003
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
9004
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
9005
|
+
}
|
|
9006
|
+
}
|
|
9007
|
+
checkFeedbackEnabled() {
|
|
9008
|
+
var _a2, _b;
|
|
9009
|
+
this.checkPremiumSubscription();
|
|
9010
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
9011
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
9014
|
+
async getPGPool() {
|
|
9015
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
9016
|
+
const _g2 = global;
|
|
9017
|
+
if (_g2[globalKey]) {
|
|
9018
|
+
this.pgPool = _g2[globalKey];
|
|
9019
|
+
return this.pgPool;
|
|
9020
|
+
}
|
|
9021
|
+
const opts = this.config.vectorDb.options;
|
|
9022
|
+
if (!opts.connectionString) {
|
|
9023
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
9024
|
+
}
|
|
9025
|
+
const { Pool: Pool3 } = await import("pg");
|
|
9026
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
9027
|
+
_g2[globalKey] = this.pgPool;
|
|
9028
|
+
const client = await this.pgPool.connect();
|
|
9029
|
+
try {
|
|
9030
|
+
await client.query(`
|
|
9031
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
9032
|
+
id TEXT PRIMARY KEY,
|
|
9033
|
+
session_id TEXT NOT NULL,
|
|
9034
|
+
role TEXT NOT NULL,
|
|
9035
|
+
content TEXT NOT NULL,
|
|
9036
|
+
sources JSONB,
|
|
9037
|
+
ui_transformation JSONB,
|
|
9038
|
+
trace JSONB,
|
|
9039
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
9040
|
+
)
|
|
9041
|
+
`);
|
|
9042
|
+
await client.query(`
|
|
9043
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
9044
|
+
id TEXT PRIMARY KEY,
|
|
9045
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
9046
|
+
session_id TEXT NOT NULL,
|
|
9047
|
+
rating TEXT NOT NULL,
|
|
9048
|
+
comment TEXT,
|
|
9049
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
9050
|
+
)
|
|
9051
|
+
`);
|
|
9052
|
+
} finally {
|
|
9053
|
+
client.release();
|
|
9054
|
+
}
|
|
9055
|
+
return this.pgPool;
|
|
9056
|
+
}
|
|
9057
|
+
async getMongoClient() {
|
|
9058
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
9059
|
+
const _g2 = global;
|
|
9060
|
+
if (_g2[globalKey]) {
|
|
9061
|
+
this.mongoClient = _g2[globalKey];
|
|
9062
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
9063
|
+
return this.mongoClient;
|
|
9064
|
+
}
|
|
9065
|
+
const opts = this.config.vectorDb.options;
|
|
9066
|
+
if (!opts.uri || !opts.database) {
|
|
9067
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
9068
|
+
}
|
|
9069
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
9070
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
9071
|
+
await this.mongoClient.connect();
|
|
9072
|
+
_g2[globalKey] = this.mongoClient;
|
|
9073
|
+
this.mongoDbName = opts.database;
|
|
9074
|
+
return this.mongoClient;
|
|
9075
|
+
}
|
|
9076
|
+
getMongoDb() {
|
|
9077
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
9078
|
+
}
|
|
9079
|
+
// Helper for FS fallback reads
|
|
9080
|
+
readLocalFile(filePath) {
|
|
9081
|
+
if (!fs.existsSync(filePath)) return [];
|
|
9082
|
+
try {
|
|
9083
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
9084
|
+
return JSON.parse(raw) || [];
|
|
9085
|
+
} catch (e) {
|
|
9086
|
+
return [];
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
9089
|
+
// Helper for FS fallback writes
|
|
9090
|
+
writeLocalFile(filePath, data) {
|
|
9091
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
9092
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
9093
|
+
}
|
|
9094
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9095
|
+
}
|
|
9096
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
9097
|
+
async saveMessage(sessionId, message) {
|
|
9098
|
+
this.checkHistoryEnabled();
|
|
9099
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9100
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9101
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9102
|
+
const pool = await this.getPGPool();
|
|
9103
|
+
await pool.query(
|
|
9104
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
9105
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
9106
|
+
ON CONFLICT (id) DO UPDATE
|
|
9107
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
9108
|
+
[
|
|
9109
|
+
msgId,
|
|
9110
|
+
sessionId,
|
|
9111
|
+
message.role,
|
|
9112
|
+
message.content,
|
|
9113
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
9114
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
9115
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
9116
|
+
createdAt
|
|
9117
|
+
]
|
|
9118
|
+
);
|
|
9119
|
+
} else if (this.provider === "mongodb") {
|
|
9120
|
+
await this.getMongoClient();
|
|
9121
|
+
const db = this.getMongoDb();
|
|
9122
|
+
const col = db.collection(this.historyTableName);
|
|
9123
|
+
await col.updateOne(
|
|
9124
|
+
{ id: msgId },
|
|
9125
|
+
{
|
|
9126
|
+
$set: {
|
|
9127
|
+
id: msgId,
|
|
9128
|
+
session_id: sessionId,
|
|
9129
|
+
role: message.role,
|
|
9130
|
+
content: message.content,
|
|
9131
|
+
sources: message.sources || null,
|
|
9132
|
+
ui_transformation: message.uiTransformation || null,
|
|
9133
|
+
trace: message.trace || null,
|
|
9134
|
+
created_at: createdAt
|
|
9135
|
+
}
|
|
9136
|
+
},
|
|
9137
|
+
{ upsert: true }
|
|
9138
|
+
);
|
|
9139
|
+
} else {
|
|
9140
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9141
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
9142
|
+
const item = {
|
|
9143
|
+
id: msgId,
|
|
9144
|
+
session_id: sessionId,
|
|
9145
|
+
role: message.role,
|
|
9146
|
+
content: message.content,
|
|
9147
|
+
sources: message.sources || null,
|
|
9148
|
+
ui_transformation: message.uiTransformation || null,
|
|
9149
|
+
trace: message.trace || null,
|
|
9150
|
+
created_at: createdAt
|
|
9151
|
+
};
|
|
9152
|
+
if (index !== -1) {
|
|
9153
|
+
history[index] = item;
|
|
9154
|
+
} else {
|
|
9155
|
+
history.push(item);
|
|
9156
|
+
}
|
|
9157
|
+
this.writeLocalFile(this.historyFile, history);
|
|
9158
|
+
}
|
|
9159
|
+
}
|
|
9160
|
+
async getHistory(sessionId) {
|
|
9161
|
+
this.checkHistoryEnabled();
|
|
9162
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9163
|
+
const pool = await this.getPGPool();
|
|
9164
|
+
const res = await pool.query(
|
|
9165
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
9166
|
+
FROM ${this.historyTableName}
|
|
9167
|
+
WHERE session_id = $1
|
|
9168
|
+
ORDER BY created_at ASC`,
|
|
9169
|
+
[sessionId]
|
|
9170
|
+
);
|
|
9171
|
+
return res.rows;
|
|
9172
|
+
} else if (this.provider === "mongodb") {
|
|
9173
|
+
await this.getMongoClient();
|
|
9174
|
+
const db = this.getMongoDb();
|
|
9175
|
+
const col = db.collection(this.historyTableName);
|
|
9176
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
9177
|
+
return items.map((item) => ({
|
|
9178
|
+
id: item.id,
|
|
9179
|
+
role: item.role,
|
|
9180
|
+
content: item.content,
|
|
9181
|
+
sources: item.sources,
|
|
9182
|
+
uiTransformation: item.ui_transformation,
|
|
9183
|
+
trace: item.trace,
|
|
9184
|
+
createdAt: item.created_at
|
|
9185
|
+
}));
|
|
9186
|
+
} else {
|
|
9187
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9188
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
9191
|
+
async clearHistory(sessionId) {
|
|
9192
|
+
this.checkHistoryEnabled();
|
|
9193
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9194
|
+
const pool = await this.getPGPool();
|
|
9195
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
9196
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
9197
|
+
} else if (this.provider === "mongodb") {
|
|
9198
|
+
await this.getMongoClient();
|
|
9199
|
+
const db = this.getMongoDb();
|
|
9200
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
9201
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
9202
|
+
} else {
|
|
9203
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9204
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
9205
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
9206
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
9207
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
9208
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
9209
|
+
}
|
|
9210
|
+
}
|
|
9211
|
+
async listSessions() {
|
|
9212
|
+
this.checkHistoryEnabled();
|
|
9213
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9214
|
+
const pool = await this.getPGPool();
|
|
9215
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
9216
|
+
return res.rows.map((r) => r.session_id);
|
|
9217
|
+
} else if (this.provider === "mongodb") {
|
|
9218
|
+
await this.getMongoClient();
|
|
9219
|
+
const db = this.getMongoDb();
|
|
9220
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
9221
|
+
} else {
|
|
9222
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9223
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
9224
|
+
return Array.from(sessions);
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9227
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
9228
|
+
async saveFeedback(feedback) {
|
|
9229
|
+
this.checkFeedbackEnabled();
|
|
9230
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9231
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9232
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9233
|
+
const pool = await this.getPGPool();
|
|
9234
|
+
await pool.query(
|
|
9235
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
9236
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
9237
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
9238
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
9239
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
9240
|
+
);
|
|
9241
|
+
} else if (this.provider === "mongodb") {
|
|
9242
|
+
await this.getMongoClient();
|
|
9243
|
+
const db = this.getMongoDb();
|
|
9244
|
+
const col = db.collection(this.feedbackTableName);
|
|
9245
|
+
await col.updateOne(
|
|
9246
|
+
{ message_id: feedback.messageId },
|
|
9247
|
+
{
|
|
9248
|
+
$set: {
|
|
9249
|
+
id,
|
|
9250
|
+
message_id: feedback.messageId,
|
|
9251
|
+
session_id: feedback.sessionId,
|
|
9252
|
+
rating: feedback.rating,
|
|
9253
|
+
comment: feedback.comment || null,
|
|
9254
|
+
created_at: createdAt
|
|
9255
|
+
}
|
|
9256
|
+
},
|
|
9257
|
+
{ upsert: true }
|
|
9258
|
+
);
|
|
9259
|
+
} else {
|
|
9260
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9261
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
9262
|
+
const item = {
|
|
9263
|
+
id,
|
|
9264
|
+
message_id: feedback.messageId,
|
|
9265
|
+
session_id: feedback.sessionId,
|
|
9266
|
+
rating: feedback.rating,
|
|
9267
|
+
comment: feedback.comment || null,
|
|
9268
|
+
created_at: createdAt
|
|
9269
|
+
};
|
|
9270
|
+
if (index !== -1) {
|
|
9271
|
+
list[index] = item;
|
|
9272
|
+
} else {
|
|
9273
|
+
list.push(item);
|
|
9274
|
+
}
|
|
9275
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
9276
|
+
}
|
|
9277
|
+
}
|
|
9278
|
+
async getFeedback(messageId) {
|
|
9279
|
+
this.checkFeedbackEnabled();
|
|
9280
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9281
|
+
const pool = await this.getPGPool();
|
|
9282
|
+
const res = await pool.query(
|
|
9283
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9284
|
+
FROM ${this.feedbackTableName}
|
|
9285
|
+
WHERE message_id = $1`,
|
|
9286
|
+
[messageId]
|
|
9287
|
+
);
|
|
9288
|
+
return res.rows[0] || null;
|
|
9289
|
+
} else if (this.provider === "mongodb") {
|
|
9290
|
+
await this.getMongoClient();
|
|
9291
|
+
const db = this.getMongoDb();
|
|
9292
|
+
const col = db.collection(this.feedbackTableName);
|
|
9293
|
+
const item = await col.findOne({ message_id: messageId });
|
|
9294
|
+
if (!item) return null;
|
|
9295
|
+
return {
|
|
9296
|
+
id: item.id,
|
|
9297
|
+
messageId: item.message_id,
|
|
9298
|
+
sessionId: item.session_id,
|
|
9299
|
+
rating: item.rating,
|
|
9300
|
+
comment: item.comment,
|
|
9301
|
+
createdAt: item.created_at
|
|
9302
|
+
};
|
|
9303
|
+
} else {
|
|
9304
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9305
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9308
|
+
async listFeedback() {
|
|
9309
|
+
this.checkFeedbackEnabled();
|
|
9310
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9311
|
+
const pool = await this.getPGPool();
|
|
9312
|
+
const res = await pool.query(
|
|
9313
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9314
|
+
FROM ${this.feedbackTableName}
|
|
9315
|
+
ORDER BY created_at DESC`
|
|
9316
|
+
);
|
|
9317
|
+
return res.rows;
|
|
9318
|
+
} else if (this.provider === "mongodb") {
|
|
9319
|
+
await this.getMongoClient();
|
|
9320
|
+
const db = this.getMongoDb();
|
|
9321
|
+
const col = db.collection(this.feedbackTableName);
|
|
9322
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
9323
|
+
return items.map((item) => ({
|
|
9324
|
+
id: item.id,
|
|
9325
|
+
messageId: item.message_id,
|
|
9326
|
+
sessionId: item.session_id,
|
|
9327
|
+
rating: item.rating,
|
|
9328
|
+
comment: item.comment,
|
|
9329
|
+
createdAt: item.created_at
|
|
9330
|
+
}));
|
|
9331
|
+
} else {
|
|
9332
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9333
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
9334
|
+
}
|
|
9335
|
+
}
|
|
9336
|
+
async disconnect() {
|
|
9337
|
+
if (this.pgPool) {
|
|
9338
|
+
await this.pgPool.end();
|
|
9339
|
+
this.pgPool = null;
|
|
9340
|
+
}
|
|
9341
|
+
if (this.mongoClient) {
|
|
9342
|
+
await this.mongoClient.close();
|
|
9343
|
+
this.mongoClient = null;
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
};
|
|
9347
|
+
|
|
9348
|
+
// src/handlers/index.ts
|
|
9349
|
+
async function checkAuth(req, onAuthorize) {
|
|
9350
|
+
if (!onAuthorize) return null;
|
|
9351
|
+
try {
|
|
9352
|
+
const res = await onAuthorize(req);
|
|
9353
|
+
if (res === false) {
|
|
9354
|
+
return import_server.NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
9355
|
+
}
|
|
9356
|
+
if (res instanceof Response) {
|
|
9357
|
+
return res;
|
|
9358
|
+
}
|
|
9359
|
+
return null;
|
|
9360
|
+
} catch (err) {
|
|
9361
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
9362
|
+
return import_server.NextResponse.json({ error: msg }, { status: 401 });
|
|
9363
|
+
}
|
|
9364
|
+
}
|
|
9365
|
+
var RateLimiter = class {
|
|
9366
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
9367
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
9368
|
+
this.windowMs = windowMs;
|
|
9369
|
+
this.max = max;
|
|
9370
|
+
}
|
|
9371
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
9372
|
+
allow(key) {
|
|
9373
|
+
const now = Date.now();
|
|
9374
|
+
const cutoff = now - this.windowMs;
|
|
9375
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9376
|
+
existing.push(now);
|
|
9377
|
+
this.hits.set(key, existing);
|
|
9378
|
+
if (this.hits.size > 5e3) {
|
|
9379
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
9380
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
9381
|
+
}
|
|
9382
|
+
}
|
|
9383
|
+
return existing.length <= this.max;
|
|
9384
|
+
}
|
|
9385
|
+
retryAfterSec(key) {
|
|
9386
|
+
const now = Date.now();
|
|
9387
|
+
const cutoff = now - this.windowMs;
|
|
9388
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9389
|
+
if (existing.length === 0) return 0;
|
|
9390
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
9391
|
+
}
|
|
9392
|
+
};
|
|
9393
|
+
var _g = global;
|
|
9394
|
+
var _a;
|
|
9395
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
9396
|
+
function getRateLimitKey(req) {
|
|
9397
|
+
var _a2, _b;
|
|
9398
|
+
const ip = ((_b = (_a2 = req.headers.get("x-forwarded-for")) == null ? void 0 : _a2.split(",")[0]) == null ? void 0 : _b.trim()) || req.headers.get("x-real-ip") || "127.0.0.1";
|
|
9399
|
+
return `ip:${ip}`;
|
|
9400
|
+
}
|
|
9401
|
+
function checkRateLimit(req) {
|
|
9402
|
+
const key = getRateLimitKey(req);
|
|
9403
|
+
if (!rateLimiter.allow(key)) {
|
|
9404
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
9405
|
+
return new Response(
|
|
9406
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
9407
|
+
{
|
|
9408
|
+
status: 429,
|
|
9409
|
+
headers: {
|
|
9410
|
+
"Content-Type": "application/json",
|
|
9411
|
+
"Retry-After": String(retryAfter),
|
|
9412
|
+
"X-RateLimit-Limit": "30",
|
|
9413
|
+
"X-RateLimit-Window": "60"
|
|
9414
|
+
}
|
|
9415
|
+
}
|
|
9416
|
+
);
|
|
9417
|
+
}
|
|
9418
|
+
return null;
|
|
9419
|
+
}
|
|
9420
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
9421
|
+
function sanitizeInput(raw) {
|
|
9422
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
9423
|
+
const trimmed = stripped.trim();
|
|
9424
|
+
if (!trimmed) {
|
|
9425
|
+
return { ok: false, error: "message must not be empty" };
|
|
9426
|
+
}
|
|
9427
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
9428
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
9429
|
+
}
|
|
9430
|
+
return { ok: true, value: trimmed };
|
|
9431
|
+
}
|
|
9432
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
9433
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
9434
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
9435
|
+
if (!_g[cacheKey]) {
|
|
9436
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
9437
|
+
}
|
|
9438
|
+
return _g[cacheKey];
|
|
9439
|
+
}
|
|
7755
9440
|
function sseFrame(payload) {
|
|
7756
9441
|
return `data: ${JSON.stringify(payload)}
|
|
7757
9442
|
|
|
@@ -7789,47 +9474,88 @@ var SSE_HEADERS = {
|
|
|
7789
9474
|
"X-Accel-Buffering": "no"
|
|
7790
9475
|
// Disable Nginx buffering for streaming
|
|
7791
9476
|
};
|
|
7792
|
-
function createChatHandler(configOrPlugin) {
|
|
7793
|
-
const plugin =
|
|
9477
|
+
function createChatHandler(configOrPlugin, options) {
|
|
9478
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9479
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9480
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7794
9481
|
return async function POST(req) {
|
|
9482
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9483
|
+
if (authResult) return authResult;
|
|
9484
|
+
const rateLimited = checkRateLimit(req);
|
|
9485
|
+
if (rateLimited) return rateLimited;
|
|
7795
9486
|
try {
|
|
7796
9487
|
const body = await req.json();
|
|
7797
|
-
const { message, history = [], namespace } = body;
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
9488
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9489
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9490
|
+
if (!sanitized.ok) {
|
|
9491
|
+
return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
9492
|
+
}
|
|
9493
|
+
const message = sanitized.value;
|
|
9494
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9495
|
+
await storage.saveMessage(sessionId, {
|
|
9496
|
+
id: userMsgId,
|
|
9497
|
+
role: "user",
|
|
9498
|
+
content: message
|
|
9499
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7801
9500
|
const result = await plugin.chat(message, history, namespace);
|
|
7802
|
-
|
|
9501
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9502
|
+
await storage.saveMessage(sessionId, {
|
|
9503
|
+
id: assistantMsgId,
|
|
9504
|
+
role: "assistant",
|
|
9505
|
+
content: result.reply,
|
|
9506
|
+
sources: result.sources,
|
|
9507
|
+
uiTransformation: result.ui_transformation,
|
|
9508
|
+
trace: result.trace
|
|
9509
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9510
|
+
return import_server.NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9511
|
+
messageId: assistantMsgId,
|
|
9512
|
+
userMessageId: userMsgId
|
|
9513
|
+
}));
|
|
7803
9514
|
} catch (err) {
|
|
7804
9515
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7805
9516
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
7806
9517
|
}
|
|
7807
9518
|
};
|
|
7808
9519
|
}
|
|
7809
|
-
function createStreamHandler(configOrPlugin) {
|
|
7810
|
-
const plugin =
|
|
9520
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9521
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9522
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9523
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7811
9524
|
return async function POST(req) {
|
|
9525
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9526
|
+
if (authResult) return authResult;
|
|
9527
|
+
const rateLimited = checkRateLimit(req);
|
|
9528
|
+
if (rateLimited) return rateLimited;
|
|
7812
9529
|
let body;
|
|
7813
9530
|
try {
|
|
7814
9531
|
body = await req.json();
|
|
7815
9532
|
} catch (e) {
|
|
7816
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9533
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7817
9534
|
status: 400,
|
|
7818
9535
|
headers: { "Content-Type": "application/json" }
|
|
7819
9536
|
});
|
|
7820
9537
|
}
|
|
7821
|
-
const { message, history = [], namespace } = body;
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
9538
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9539
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9540
|
+
if (!sanitized.ok) {
|
|
9541
|
+
return new Response(
|
|
9542
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9543
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9544
|
+
);
|
|
7827
9545
|
}
|
|
9546
|
+
const message = sanitized.value;
|
|
9547
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9548
|
+
await storage.saveMessage(sessionId, {
|
|
9549
|
+
id: userMsgId,
|
|
9550
|
+
role: "user",
|
|
9551
|
+
content: message
|
|
9552
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9553
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7828
9554
|
const encoder = new TextEncoder();
|
|
7829
9555
|
let isActive = true;
|
|
7830
9556
|
const stream = new ReadableStream({
|
|
7831
9557
|
async start(controller) {
|
|
7832
|
-
var
|
|
9558
|
+
var _a2;
|
|
7833
9559
|
const enqueue = (text) => {
|
|
7834
9560
|
if (!isActive) return;
|
|
7835
9561
|
try {
|
|
@@ -7840,11 +9566,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7840
9566
|
};
|
|
7841
9567
|
try {
|
|
7842
9568
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9569
|
+
let fullReply = "";
|
|
7843
9570
|
try {
|
|
7844
9571
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7845
9572
|
const chunk = temp.value;
|
|
7846
9573
|
if (!isActive) break;
|
|
7847
9574
|
if (typeof chunk === "string") {
|
|
9575
|
+
fullReply += chunk;
|
|
7848
9576
|
enqueue(sseTextFrame(chunk));
|
|
7849
9577
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7850
9578
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7857,9 +9585,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7857
9585
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7858
9586
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7859
9587
|
}
|
|
9588
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7860
9589
|
if (sources.length > 0) {
|
|
7861
9590
|
try {
|
|
7862
|
-
|
|
9591
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7863
9592
|
if (uiTransformation) {
|
|
7864
9593
|
enqueue(sseUIFrame(uiTransformation));
|
|
7865
9594
|
}
|
|
@@ -7867,11 +9596,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7867
9596
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7868
9597
|
try {
|
|
7869
9598
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7870
|
-
if (fallback)
|
|
9599
|
+
if (fallback) {
|
|
9600
|
+
uiTransformation = fallback;
|
|
9601
|
+
enqueue(sseUIFrame(fallback));
|
|
9602
|
+
}
|
|
7871
9603
|
} catch (e) {
|
|
7872
9604
|
}
|
|
7873
9605
|
}
|
|
7874
9606
|
}
|
|
9607
|
+
await storage.saveMessage(sessionId, {
|
|
9608
|
+
id: assistantMsgId,
|
|
9609
|
+
role: "assistant",
|
|
9610
|
+
content: fullReply,
|
|
9611
|
+
sources,
|
|
9612
|
+
uiTransformation,
|
|
9613
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9614
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7875
9615
|
}
|
|
7876
9616
|
}
|
|
7877
9617
|
} catch (temp) {
|
|
@@ -7908,12 +9648,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7908
9648
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7909
9649
|
}
|
|
7910
9650
|
});
|
|
7911
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9651
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7912
9652
|
};
|
|
7913
9653
|
}
|
|
7914
|
-
function createIngestHandler(configOrPlugin) {
|
|
7915
|
-
const plugin =
|
|
9654
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9655
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9656
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7916
9657
|
return async function POST(req) {
|
|
9658
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9659
|
+
if (authResult) return authResult;
|
|
7917
9660
|
try {
|
|
7918
9661
|
const body = await req.json();
|
|
7919
9662
|
const { documents, namespace } = body;
|
|
@@ -7928,9 +9671,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7928
9671
|
}
|
|
7929
9672
|
};
|
|
7930
9673
|
}
|
|
7931
|
-
function createHealthHandler(configOrPlugin) {
|
|
7932
|
-
const plugin =
|
|
7933
|
-
|
|
9674
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9675
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9676
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9677
|
+
return async function GET(req) {
|
|
9678
|
+
if (req) {
|
|
9679
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9680
|
+
if (authResult) return authResult;
|
|
9681
|
+
}
|
|
7934
9682
|
try {
|
|
7935
9683
|
const health = await plugin.checkHealth();
|
|
7936
9684
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7945,9 +9693,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7945
9693
|
}
|
|
7946
9694
|
};
|
|
7947
9695
|
}
|
|
7948
|
-
function createUploadHandler(configOrPlugin) {
|
|
7949
|
-
const plugin =
|
|
9696
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9697
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9698
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7950
9699
|
return async function POST(req) {
|
|
9700
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9701
|
+
if (authResult) return authResult;
|
|
7951
9702
|
try {
|
|
7952
9703
|
const formData = await req.formData();
|
|
7953
9704
|
const files = formData.getAll("files");
|
|
@@ -8021,9 +9772,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
8021
9772
|
}
|
|
8022
9773
|
};
|
|
8023
9774
|
}
|
|
8024
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
8025
|
-
const plugin =
|
|
9775
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9776
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9777
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
8026
9778
|
return async function POST(req) {
|
|
9779
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9780
|
+
if (authResult) return authResult;
|
|
8027
9781
|
try {
|
|
8028
9782
|
const body = await req.json();
|
|
8029
9783
|
const { query, namespace } = body;
|
|
@@ -8038,13 +9792,108 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
8038
9792
|
}
|
|
8039
9793
|
};
|
|
8040
9794
|
}
|
|
8041
|
-
function
|
|
8042
|
-
const plugin =
|
|
8043
|
-
const
|
|
8044
|
-
const
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
9795
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9796
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9797
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9798
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9799
|
+
return async function handler(req) {
|
|
9800
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9801
|
+
if (authResult) return authResult;
|
|
9802
|
+
const url = new URL(req.url);
|
|
9803
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9804
|
+
if (req.method === "GET") {
|
|
9805
|
+
try {
|
|
9806
|
+
const history = await storage.getHistory(sessionId);
|
|
9807
|
+
return import_server.NextResponse.json({ history });
|
|
9808
|
+
} catch (err) {
|
|
9809
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9810
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9811
|
+
}
|
|
9812
|
+
} else if (req.method === "POST") {
|
|
9813
|
+
try {
|
|
9814
|
+
const body = await req.json().catch(() => ({}));
|
|
9815
|
+
const sid = body.sessionId || sessionId;
|
|
9816
|
+
await storage.clearHistory(sid);
|
|
9817
|
+
return import_server.NextResponse.json({ success: true });
|
|
9818
|
+
} catch (err) {
|
|
9819
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9820
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9824
|
+
};
|
|
9825
|
+
}
|
|
9826
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9827
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9828
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9829
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9830
|
+
return async function handler(req) {
|
|
9831
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9832
|
+
if (authResult) return authResult;
|
|
9833
|
+
if (req.method === "GET") {
|
|
9834
|
+
try {
|
|
9835
|
+
const url = new URL(req.url);
|
|
9836
|
+
const messageId = url.searchParams.get("messageId");
|
|
9837
|
+
if (!messageId) {
|
|
9838
|
+
const feedbackList = await storage.listFeedback();
|
|
9839
|
+
return import_server.NextResponse.json({ feedback: feedbackList });
|
|
9840
|
+
}
|
|
9841
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9842
|
+
return import_server.NextResponse.json({ feedback });
|
|
9843
|
+
} catch (err) {
|
|
9844
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9845
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9846
|
+
}
|
|
9847
|
+
} else if (req.method === "POST") {
|
|
9848
|
+
try {
|
|
9849
|
+
const body = await req.json();
|
|
9850
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9851
|
+
if (!messageId) {
|
|
9852
|
+
return import_server.NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9853
|
+
}
|
|
9854
|
+
if (!rating) {
|
|
9855
|
+
return import_server.NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9856
|
+
}
|
|
9857
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9858
|
+
return import_server.NextResponse.json({ success: true });
|
|
9859
|
+
} catch (err) {
|
|
9860
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9861
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9862
|
+
}
|
|
9863
|
+
}
|
|
9864
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9865
|
+
};
|
|
9866
|
+
}
|
|
9867
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9868
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9869
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9870
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9871
|
+
return async function GET(req) {
|
|
9872
|
+
if (req) {
|
|
9873
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9874
|
+
if (authResult) return authResult;
|
|
9875
|
+
}
|
|
9876
|
+
void req;
|
|
9877
|
+
try {
|
|
9878
|
+
const sessions = await storage.listSessions();
|
|
9879
|
+
return import_server.NextResponse.json({ sessions });
|
|
9880
|
+
} catch (err) {
|
|
9881
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9882
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9883
|
+
}
|
|
9884
|
+
};
|
|
9885
|
+
}
|
|
9886
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9887
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9888
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9889
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9890
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9891
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9892
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9893
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9894
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9895
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9896
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
8048
9897
|
async function routePostRequest(req, segment) {
|
|
8049
9898
|
switch (segment) {
|
|
8050
9899
|
case "chat":
|
|
@@ -8056,22 +9905,35 @@ function createRagHandler(configOrPlugin) {
|
|
|
8056
9905
|
case "suggestions":
|
|
8057
9906
|
return suggestionsHandler(req);
|
|
8058
9907
|
case "health":
|
|
8059
|
-
return healthHandler();
|
|
9908
|
+
return healthHandler(req);
|
|
9909
|
+
case "history":
|
|
9910
|
+
case "history/clear":
|
|
9911
|
+
return historyHandler(req);
|
|
9912
|
+
case "feedback":
|
|
9913
|
+
return feedbackHandler(req);
|
|
8060
9914
|
default:
|
|
8061
9915
|
return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
8062
9916
|
}
|
|
8063
9917
|
}
|
|
8064
9918
|
async function routeGetRequest(req, segment) {
|
|
8065
|
-
|
|
8066
|
-
|
|
9919
|
+
switch (segment) {
|
|
9920
|
+
case "health":
|
|
9921
|
+
return healthHandler(req);
|
|
9922
|
+
case "history":
|
|
9923
|
+
return historyHandler(req);
|
|
9924
|
+
case "feedback":
|
|
9925
|
+
return feedbackHandler(req);
|
|
9926
|
+
case "sessions":
|
|
9927
|
+
return sessionsHandler(req);
|
|
9928
|
+
default:
|
|
9929
|
+
return import_server.NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
8067
9930
|
}
|
|
8068
|
-
return import_server.NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
|
|
8069
9931
|
}
|
|
8070
9932
|
async function getSegment(context) {
|
|
8071
|
-
var
|
|
8072
|
-
const resolvedParams = typeof ((
|
|
9933
|
+
var _a2;
|
|
9934
|
+
const resolvedParams = typeof ((_a2 = context == null ? void 0 : context.params) == null ? void 0 : _a2.then) === "function" ? await context.params : context == null ? void 0 : context.params;
|
|
8073
9935
|
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
8074
|
-
return segments
|
|
9936
|
+
return segments.join("/") || "chat";
|
|
8075
9937
|
}
|
|
8076
9938
|
return {
|
|
8077
9939
|
GET: async (req, context) => {
|
|
@@ -8110,8 +9972,10 @@ function createRagHandler(configOrPlugin) {
|
|
|
8110
9972
|
EmbeddingFailedException,
|
|
8111
9973
|
EmbeddingStrategy,
|
|
8112
9974
|
EmbeddingStrategyResolver,
|
|
9975
|
+
GroqProvider,
|
|
8113
9976
|
LLMFactory,
|
|
8114
9977
|
LLM_PROFILES,
|
|
9978
|
+
LicenseVerifier,
|
|
8115
9979
|
MilvusProvider,
|
|
8116
9980
|
MongoDBProvider,
|
|
8117
9981
|
MultiTablePostgresProvider,
|
|
@@ -8125,6 +9989,7 @@ function createRagHandler(configOrPlugin) {
|
|
|
8125
9989
|
ProviderNotFoundException,
|
|
8126
9990
|
ProviderRegistry,
|
|
8127
9991
|
QdrantProvider,
|
|
9992
|
+
QwenProvider,
|
|
8128
9993
|
RateLimitException,
|
|
8129
9994
|
RedisProvider,
|
|
8130
9995
|
RetrievalException,
|
|
@@ -8136,10 +10001,13 @@ function createRagHandler(configOrPlugin) {
|
|
|
8136
10001
|
VectorPlugin,
|
|
8137
10002
|
WeaviateProvider,
|
|
8138
10003
|
createChatHandler,
|
|
10004
|
+
createFeedbackHandler,
|
|
8139
10005
|
createFromPreset,
|
|
8140
10006
|
createHealthHandler,
|
|
10007
|
+
createHistoryHandler,
|
|
8141
10008
|
createIngestHandler,
|
|
8142
10009
|
createRagHandler,
|
|
10010
|
+
createSessionsHandler,
|
|
8143
10011
|
createStreamHandler,
|
|
8144
10012
|
createUploadHandler,
|
|
8145
10013
|
getRagConfig,
|