@retrivora-ai/rag-engine 1.9.7 → 1.9.8
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 +127 -135
- package/dist/{ILLMProvider-Bhk6zJOK.d.mts → ILLMProvider-B8ROITYK.d.mts} +57 -2
- package/dist/{ILLMProvider-Bhk6zJOK.d.ts → ILLMProvider-B8ROITYK.d.ts} +57 -2
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +2198 -457
- package/dist/handlers/index.mjs +2195 -457
- package/dist/{index-BJ4cd-t5.d.mts → index-B8PbEFSY.d.mts} +12 -2
- package/dist/{index-Bu7T6xgr.d.ts → index-BCPKUAVL.d.ts} +27 -52
- package/dist/{index-C3SVtPYg.d.mts → index-CrxCy36A.d.mts} +27 -52
- package/dist/{index-B9J_XEh0.d.ts → index-DNvoi-sV.d.ts} +12 -2
- package/dist/index.css +578 -273
- package/dist/index.d.mts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +1160 -282
- package/dist/index.mjs +1185 -292
- package/dist/server.d.mts +62 -6
- package/dist/server.d.ts +62 -6
- package/dist/server.js +2061 -306
- package/dist/server.mjs +2055 -306
- package/package.json +11 -7
- package/src/app/constants.tsx +37 -7
- package/src/components/AmbientBackground.tsx +10 -10
- package/src/components/ArchitectureCard.tsx +43 -7
- package/src/components/ArchitectureCardsSection.tsx +37 -4
- package/src/components/ChatWidget.tsx +2 -1
- package/src/components/ChatWindow.tsx +4 -1
- package/src/components/CodeViewer.tsx +19 -14
- package/src/components/DocViewer.tsx +43 -49
- package/src/components/Documentation.tsx +71 -51
- package/src/components/Hero.tsx +103 -20
- package/src/components/Lifecycle.tsx +65 -25
- package/src/components/MarkdownComponents.tsx +44 -1
- package/src/components/MessageBubble.tsx +162 -50
- package/src/components/constants.tsx +4 -0
- package/src/config/RagConfig.ts +46 -0
- package/src/config/constants.ts +4 -0
- package/src/config/serverConfig.ts +15 -0
- package/src/core/ConfigResolver.ts +6 -0
- package/src/core/DatabaseStorage.ts +469 -0
- package/src/core/LicenseVerifier.ts +154 -0
- package/src/core/MultiAgentCoordinator.ts +239 -0
- package/src/core/Pipeline.ts +146 -15
- package/src/core/Retrivora.ts +6 -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 +5 -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/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,11 +2429,11 @@ var ConfigResolver = class {
|
|
|
2401
2429
|
}
|
|
2402
2430
|
}
|
|
2403
2431
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2404
|
-
var
|
|
2432
|
+
var _a2, _b, _c, _d, _e;
|
|
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";
|
|
@@ -2487,8 +2515,8 @@ var OpenAIProvider = class {
|
|
|
2487
2515
|
const apiKey = config.apiKey;
|
|
2488
2516
|
const modelName = config.model;
|
|
2489
2517
|
try {
|
|
2490
|
-
const
|
|
2491
|
-
const client = new
|
|
2518
|
+
const OpenAI4 = await import("openai");
|
|
2519
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2492
2520
|
const models = await client.models.list();
|
|
2493
2521
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2494
2522
|
return {
|
|
@@ -2509,8 +2537,8 @@ var OpenAIProvider = class {
|
|
|
2509
2537
|
};
|
|
2510
2538
|
}
|
|
2511
2539
|
async chat(messages, context, options) {
|
|
2512
|
-
var
|
|
2513
|
-
const basePrompt = (_b = (
|
|
2540
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2541
|
+
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
2542
|
const systemMessage = {
|
|
2515
2543
|
role: "system",
|
|
2516
2544
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2529,12 +2557,12 @@ var OpenAIProvider = class {
|
|
|
2529
2557
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2530
2558
|
stop: options == null ? void 0 : options.stop
|
|
2531
2559
|
});
|
|
2532
|
-
return (_i = (_h = (
|
|
2560
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2533
2561
|
}
|
|
2534
2562
|
chatStream(messages, context, options) {
|
|
2535
2563
|
return __asyncGenerator(this, null, function* () {
|
|
2536
|
-
var
|
|
2537
|
-
const basePrompt = (_b = (
|
|
2564
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
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.";
|
|
2538
2566
|
const systemMessage = {
|
|
2539
2567
|
role: "system",
|
|
2540
2568
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2560,7 +2588,7 @@ var OpenAIProvider = class {
|
|
|
2560
2588
|
try {
|
|
2561
2589
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2562
2590
|
const chunk = temp.value;
|
|
2563
|
-
const content = ((_h = (
|
|
2591
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2564
2592
|
if (content) yield content;
|
|
2565
2593
|
}
|
|
2566
2594
|
} catch (temp) {
|
|
@@ -2580,8 +2608,8 @@ var OpenAIProvider = class {
|
|
|
2580
2608
|
return results[0];
|
|
2581
2609
|
}
|
|
2582
2610
|
async batchEmbed(texts, options) {
|
|
2583
|
-
var
|
|
2584
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2611
|
+
var _a2, _b, _c, _d, _e;
|
|
2612
|
+
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
2613
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2586
2614
|
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
2587
2615
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2658,8 +2686,8 @@ var AnthropicProvider = class {
|
|
|
2658
2686
|
};
|
|
2659
2687
|
}
|
|
2660
2688
|
async chat(messages, context, options) {
|
|
2661
|
-
var
|
|
2662
|
-
const basePrompt = (_b = (
|
|
2689
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2690
|
+
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
2691
|
const system = buildSystemContent(basePrompt, context);
|
|
2664
2692
|
const anthropicMessages = messages.map((m) => ({
|
|
2665
2693
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2670,7 +2698,7 @@ var AnthropicProvider = class {
|
|
|
2670
2698
|
const extraParams = {};
|
|
2671
2699
|
if (isThinkingEnabled && isClaude37) {
|
|
2672
2700
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2673
|
-
const maxTokens = (
|
|
2701
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2674
2702
|
const budget = Math.min(
|
|
2675
2703
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2676
2704
|
maxTokens - 1
|
|
@@ -2697,8 +2725,8 @@ var AnthropicProvider = class {
|
|
|
2697
2725
|
}
|
|
2698
2726
|
chatStream(messages, context, options) {
|
|
2699
2727
|
return __asyncGenerator(this, null, function* () {
|
|
2700
|
-
var
|
|
2701
|
-
const basePrompt = (_b = (
|
|
2728
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2729
|
+
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
2730
|
const system = buildSystemContent(basePrompt, context);
|
|
2703
2731
|
const anthropicMessages = messages.map((m) => ({
|
|
2704
2732
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2709,7 +2737,7 @@ var AnthropicProvider = class {
|
|
|
2709
2737
|
const extraParams = {};
|
|
2710
2738
|
if (isThinkingEnabled && isClaude37) {
|
|
2711
2739
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2712
|
-
const maxTokens = (
|
|
2740
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2713
2741
|
const budget = Math.min(
|
|
2714
2742
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2715
2743
|
maxTokens - 1
|
|
@@ -2782,8 +2810,8 @@ var AnthropicProvider = class {
|
|
|
2782
2810
|
var import_axios = __toESM(require("axios"));
|
|
2783
2811
|
var OllamaProvider = class {
|
|
2784
2812
|
constructor(llmConfig, embeddingConfig) {
|
|
2785
|
-
var
|
|
2786
|
-
const baseURL = (
|
|
2813
|
+
var _a2, _b;
|
|
2814
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2787
2815
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2788
2816
|
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2789
2817
|
this.llmConfig = llmConfig;
|
|
@@ -2841,8 +2869,8 @@ var OllamaProvider = class {
|
|
|
2841
2869
|
};
|
|
2842
2870
|
}
|
|
2843
2871
|
async chat(messages, context, options) {
|
|
2844
|
-
var
|
|
2845
|
-
const basePrompt = (_b = (
|
|
2872
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2873
|
+
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
2874
|
const system = buildSystemContent(basePrompt, context);
|
|
2847
2875
|
const { data } = await this.http.post("/api/chat", {
|
|
2848
2876
|
model: this.llmConfig.model,
|
|
@@ -2860,8 +2888,8 @@ var OllamaProvider = class {
|
|
|
2860
2888
|
}
|
|
2861
2889
|
chatStream(messages, context, options) {
|
|
2862
2890
|
return __asyncGenerator(this, null, function* () {
|
|
2863
|
-
var
|
|
2864
|
-
const basePrompt = (_b = (
|
|
2891
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2892
|
+
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
2893
|
const system = buildSystemContent(basePrompt, context);
|
|
2866
2894
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2867
2895
|
model: this.llmConfig.model,
|
|
@@ -2890,7 +2918,7 @@ var OllamaProvider = class {
|
|
|
2890
2918
|
if (!line.trim()) continue;
|
|
2891
2919
|
try {
|
|
2892
2920
|
const json = JSON.parse(line);
|
|
2893
|
-
if ((
|
|
2921
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2894
2922
|
yield json.message.content;
|
|
2895
2923
|
}
|
|
2896
2924
|
if (json.done) return;
|
|
@@ -2919,10 +2947,10 @@ var OllamaProvider = class {
|
|
|
2919
2947
|
});
|
|
2920
2948
|
}
|
|
2921
2949
|
async embed(text, options) {
|
|
2922
|
-
var
|
|
2923
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2950
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2951
|
+
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
2952
|
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 !== ((
|
|
2953
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2926
2954
|
let prompt = text;
|
|
2927
2955
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2928
2956
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -3021,9 +3049,9 @@ var GeminiProvider = class {
|
|
|
3021
3049
|
static getHealthChecker() {
|
|
3022
3050
|
return {
|
|
3023
3051
|
async check(config) {
|
|
3024
|
-
var
|
|
3052
|
+
var _a2, _b;
|
|
3025
3053
|
const timestamp = Date.now();
|
|
3026
|
-
const apiKey = (_b = (
|
|
3054
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
3027
3055
|
const modelName = sanitizeModel(config.model);
|
|
3028
3056
|
try {
|
|
3029
3057
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -3053,16 +3081,16 @@ var GeminiProvider = class {
|
|
|
3053
3081
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
3054
3082
|
* API key differs from the LLM API key. */
|
|
3055
3083
|
get embeddingClient() {
|
|
3056
|
-
var
|
|
3057
|
-
if (((
|
|
3084
|
+
var _a2;
|
|
3085
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
3058
3086
|
return buildClient(this.embeddingConfig.apiKey);
|
|
3059
3087
|
}
|
|
3060
3088
|
return this.client;
|
|
3061
3089
|
}
|
|
3062
3090
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
3063
3091
|
resolveEmbeddingModel(optionsModel) {
|
|
3064
|
-
var
|
|
3065
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3092
|
+
var _a2, _b;
|
|
3093
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
3066
3094
|
}
|
|
3067
3095
|
/**
|
|
3068
3096
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3082,8 +3110,8 @@ var GeminiProvider = class {
|
|
|
3082
3110
|
// ILLMProvider — chat
|
|
3083
3111
|
// -------------------------------------------------------------------------
|
|
3084
3112
|
async chat(messages, context, options) {
|
|
3085
|
-
var
|
|
3086
|
-
const basePrompt = (_b = (
|
|
3113
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3114
|
+
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
3115
|
const model = this.client.getGenerativeModel({
|
|
3088
3116
|
model: this.llmConfig.model,
|
|
3089
3117
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3100,8 +3128,8 @@ var GeminiProvider = class {
|
|
|
3100
3128
|
}
|
|
3101
3129
|
chatStream(messages, context, options) {
|
|
3102
3130
|
return __asyncGenerator(this, null, function* () {
|
|
3103
|
-
var
|
|
3104
|
-
const basePrompt = (_b = (
|
|
3131
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3132
|
+
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
3133
|
const model = this.client.getGenerativeModel({
|
|
3106
3134
|
model: this.llmConfig.model,
|
|
3107
3135
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3136,11 +3164,11 @@ var GeminiProvider = class {
|
|
|
3136
3164
|
// ILLMProvider — embeddings
|
|
3137
3165
|
// -------------------------------------------------------------------------
|
|
3138
3166
|
async embed(text, options) {
|
|
3139
|
-
var
|
|
3167
|
+
var _a2, _b;
|
|
3140
3168
|
const content = applyPrefix(
|
|
3141
3169
|
text,
|
|
3142
3170
|
options == null ? void 0 : options.taskType,
|
|
3143
|
-
(
|
|
3171
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3144
3172
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3145
3173
|
);
|
|
3146
3174
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3157,7 +3185,7 @@ var GeminiProvider = class {
|
|
|
3157
3185
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3158
3186
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3159
3187
|
const requests = texts.map((text) => {
|
|
3160
|
-
var
|
|
3188
|
+
var _a2, _b;
|
|
3161
3189
|
return {
|
|
3162
3190
|
content: {
|
|
3163
3191
|
role: "user",
|
|
@@ -3165,7 +3193,7 @@ var GeminiProvider = class {
|
|
|
3165
3193
|
text: applyPrefix(
|
|
3166
3194
|
text,
|
|
3167
3195
|
options == null ? void 0 : options.taskType,
|
|
3168
|
-
(
|
|
3196
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3169
3197
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3170
3198
|
)
|
|
3171
3199
|
}]
|
|
@@ -3182,8 +3210,8 @@ var GeminiProvider = class {
|
|
|
3182
3210
|
throw err;
|
|
3183
3211
|
});
|
|
3184
3212
|
return response.embeddings.map((e) => {
|
|
3185
|
-
var
|
|
3186
|
-
return (
|
|
3213
|
+
var _a2;
|
|
3214
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3187
3215
|
});
|
|
3188
3216
|
}
|
|
3189
3217
|
// -------------------------------------------------------------------------
|
|
@@ -3203,6 +3231,325 @@ var GeminiProvider = class {
|
|
|
3203
3231
|
}
|
|
3204
3232
|
};
|
|
3205
3233
|
|
|
3234
|
+
// src/llm/providers/GroqProvider.ts
|
|
3235
|
+
var import_openai2 = __toESM(require("openai"));
|
|
3236
|
+
var GroqProvider = class {
|
|
3237
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3238
|
+
void embeddingConfig;
|
|
3239
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3240
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3241
|
+
this.client = new import_openai2.default({
|
|
3242
|
+
apiKey,
|
|
3243
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3244
|
+
});
|
|
3245
|
+
this.llmConfig = llmConfig;
|
|
3246
|
+
}
|
|
3247
|
+
static getValidator() {
|
|
3248
|
+
return {
|
|
3249
|
+
validate(config) {
|
|
3250
|
+
const errors = [];
|
|
3251
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3252
|
+
errors.push({
|
|
3253
|
+
field: "llm.apiKey",
|
|
3254
|
+
message: "Groq API key is required",
|
|
3255
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3256
|
+
severity: "error"
|
|
3257
|
+
});
|
|
3258
|
+
}
|
|
3259
|
+
if (!config.model) {
|
|
3260
|
+
errors.push({
|
|
3261
|
+
field: "llm.model",
|
|
3262
|
+
message: "Groq model name is required",
|
|
3263
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3264
|
+
severity: "error"
|
|
3265
|
+
});
|
|
3266
|
+
}
|
|
3267
|
+
return errors;
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
static getHealthChecker() {
|
|
3272
|
+
return {
|
|
3273
|
+
async check(config) {
|
|
3274
|
+
const timestamp = Date.now();
|
|
3275
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3276
|
+
const modelName = config.model;
|
|
3277
|
+
try {
|
|
3278
|
+
const OpenAI4 = await import("openai");
|
|
3279
|
+
const client = new OpenAI4.default({
|
|
3280
|
+
apiKey,
|
|
3281
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3282
|
+
});
|
|
3283
|
+
const models = await client.models.list();
|
|
3284
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3285
|
+
return {
|
|
3286
|
+
healthy: true,
|
|
3287
|
+
provider: "groq",
|
|
3288
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3289
|
+
timestamp
|
|
3290
|
+
};
|
|
3291
|
+
} catch (error) {
|
|
3292
|
+
return {
|
|
3293
|
+
healthy: false,
|
|
3294
|
+
provider: "groq",
|
|
3295
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3296
|
+
timestamp
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
};
|
|
3301
|
+
}
|
|
3302
|
+
async chat(messages, context, options) {
|
|
3303
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3304
|
+
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.";
|
|
3305
|
+
const systemMessage = {
|
|
3306
|
+
role: "system",
|
|
3307
|
+
content: buildSystemContent(basePrompt, context)
|
|
3308
|
+
};
|
|
3309
|
+
const formattedMessages = [
|
|
3310
|
+
systemMessage,
|
|
3311
|
+
...messages.map((m) => ({
|
|
3312
|
+
role: m.role,
|
|
3313
|
+
content: m.content
|
|
3314
|
+
}))
|
|
3315
|
+
];
|
|
3316
|
+
const completion = await this.client.chat.completions.create({
|
|
3317
|
+
model: this.llmConfig.model,
|
|
3318
|
+
messages: formattedMessages,
|
|
3319
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3320
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3321
|
+
stop: options == null ? void 0 : options.stop
|
|
3322
|
+
});
|
|
3323
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3324
|
+
}
|
|
3325
|
+
chatStream(messages, context, options) {
|
|
3326
|
+
return __asyncGenerator(this, null, function* () {
|
|
3327
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
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 stream = yield new __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
|
+
stream: true
|
|
3347
|
+
}));
|
|
3348
|
+
if (!stream) {
|
|
3349
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3350
|
+
}
|
|
3351
|
+
try {
|
|
3352
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3353
|
+
const chunk = temp.value;
|
|
3354
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3355
|
+
if (content) yield content;
|
|
3356
|
+
}
|
|
3357
|
+
} catch (temp) {
|
|
3358
|
+
error = [temp];
|
|
3359
|
+
} finally {
|
|
3360
|
+
try {
|
|
3361
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3362
|
+
} finally {
|
|
3363
|
+
if (error)
|
|
3364
|
+
throw error[0];
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
async embed(text, options) {
|
|
3370
|
+
void text;
|
|
3371
|
+
void options;
|
|
3372
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3373
|
+
}
|
|
3374
|
+
async batchEmbed(texts, options) {
|
|
3375
|
+
void texts;
|
|
3376
|
+
void options;
|
|
3377
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3378
|
+
}
|
|
3379
|
+
async ping() {
|
|
3380
|
+
try {
|
|
3381
|
+
await this.client.models.list();
|
|
3382
|
+
return true;
|
|
3383
|
+
} catch (err) {
|
|
3384
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3385
|
+
return false;
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
};
|
|
3389
|
+
|
|
3390
|
+
// src/llm/providers/QwenProvider.ts
|
|
3391
|
+
var import_openai3 = __toESM(require("openai"));
|
|
3392
|
+
var QwenProvider = class {
|
|
3393
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3394
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3395
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3396
|
+
this.client = new import_openai3.default({
|
|
3397
|
+
apiKey,
|
|
3398
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3399
|
+
});
|
|
3400
|
+
this.llmConfig = llmConfig;
|
|
3401
|
+
this.embeddingConfig = embeddingConfig;
|
|
3402
|
+
}
|
|
3403
|
+
static getValidator() {
|
|
3404
|
+
return {
|
|
3405
|
+
validate(config) {
|
|
3406
|
+
const errors = [];
|
|
3407
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3408
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3409
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3410
|
+
errors.push({
|
|
3411
|
+
field: `${prefix}.apiKey`,
|
|
3412
|
+
message: "Qwen API key is required",
|
|
3413
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3414
|
+
severity: "error"
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
if (!config.model) {
|
|
3418
|
+
errors.push({
|
|
3419
|
+
field: `${prefix}.model`,
|
|
3420
|
+
message: "Qwen model name is required",
|
|
3421
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3422
|
+
severity: "error"
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
3425
|
+
return errors;
|
|
3426
|
+
}
|
|
3427
|
+
};
|
|
3428
|
+
}
|
|
3429
|
+
static getHealthChecker() {
|
|
3430
|
+
return {
|
|
3431
|
+
async check(config) {
|
|
3432
|
+
const timestamp = Date.now();
|
|
3433
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3434
|
+
const modelName = config.model;
|
|
3435
|
+
try {
|
|
3436
|
+
const OpenAI4 = await import("openai");
|
|
3437
|
+
const client = new OpenAI4.default({
|
|
3438
|
+
apiKey,
|
|
3439
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3440
|
+
});
|
|
3441
|
+
const models = await client.models.list();
|
|
3442
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3443
|
+
return {
|
|
3444
|
+
healthy: true,
|
|
3445
|
+
provider: "qwen",
|
|
3446
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3447
|
+
timestamp
|
|
3448
|
+
};
|
|
3449
|
+
} catch (error) {
|
|
3450
|
+
return {
|
|
3451
|
+
healthy: false,
|
|
3452
|
+
provider: "qwen",
|
|
3453
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3454
|
+
timestamp
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
async chat(messages, context, options) {
|
|
3461
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3462
|
+
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.";
|
|
3463
|
+
const systemMessage = {
|
|
3464
|
+
role: "system",
|
|
3465
|
+
content: buildSystemContent(basePrompt, context)
|
|
3466
|
+
};
|
|
3467
|
+
const formattedMessages = [
|
|
3468
|
+
systemMessage,
|
|
3469
|
+
...messages.map((m) => ({
|
|
3470
|
+
role: m.role,
|
|
3471
|
+
content: m.content
|
|
3472
|
+
}))
|
|
3473
|
+
];
|
|
3474
|
+
const completion = await this.client.chat.completions.create({
|
|
3475
|
+
model: this.llmConfig.model,
|
|
3476
|
+
messages: formattedMessages,
|
|
3477
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3478
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3479
|
+
stop: options == null ? void 0 : options.stop
|
|
3480
|
+
});
|
|
3481
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3482
|
+
}
|
|
3483
|
+
chatStream(messages, context, options) {
|
|
3484
|
+
return __asyncGenerator(this, null, function* () {
|
|
3485
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
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 stream = yield new __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
|
+
stream: true
|
|
3505
|
+
}));
|
|
3506
|
+
if (!stream) {
|
|
3507
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3508
|
+
}
|
|
3509
|
+
try {
|
|
3510
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3511
|
+
const chunk = temp.value;
|
|
3512
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3513
|
+
if (content) yield content;
|
|
3514
|
+
}
|
|
3515
|
+
} catch (temp) {
|
|
3516
|
+
error = [temp];
|
|
3517
|
+
} finally {
|
|
3518
|
+
try {
|
|
3519
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3520
|
+
} finally {
|
|
3521
|
+
if (error)
|
|
3522
|
+
throw error[0];
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
async embed(text, options) {
|
|
3528
|
+
const results = await this.batchEmbed([text], options);
|
|
3529
|
+
return results[0];
|
|
3530
|
+
}
|
|
3531
|
+
async batchEmbed(texts, options) {
|
|
3532
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3533
|
+
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";
|
|
3534
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3535
|
+
const client = apiKey !== this.llmConfig.apiKey ? new import_openai3.default({
|
|
3536
|
+
apiKey,
|
|
3537
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3538
|
+
}) : this.client;
|
|
3539
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3540
|
+
return response.data.map((d) => d.embedding);
|
|
3541
|
+
}
|
|
3542
|
+
async ping() {
|
|
3543
|
+
try {
|
|
3544
|
+
await this.client.models.list();
|
|
3545
|
+
return true;
|
|
3546
|
+
} catch (err) {
|
|
3547
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3548
|
+
return false;
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
};
|
|
3552
|
+
|
|
3206
3553
|
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3207
3554
|
var import_axios2 = __toESM(require("axios"));
|
|
3208
3555
|
init_templateUtils();
|
|
@@ -3286,10 +3633,10 @@ var VECTOR_PROFILES = {
|
|
|
3286
3633
|
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3287
3634
|
var UniversalLLMAdapter = class {
|
|
3288
3635
|
constructor(config) {
|
|
3289
|
-
var
|
|
3636
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3290
3637
|
this.model = config.model;
|
|
3291
3638
|
const llmConfig = config;
|
|
3292
|
-
const options = (
|
|
3639
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3293
3640
|
let profile = {};
|
|
3294
3641
|
if (typeof options.profile === "string") {
|
|
3295
3642
|
profile = LLM_PROFILES[options.profile] || {};
|
|
@@ -3301,7 +3648,7 @@ var UniversalLLMAdapter = class {
|
|
|
3301
3648
|
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3302
3649
|
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3303
3650
|
this.apiKey = config.apiKey;
|
|
3304
|
-
this.baseUrl = (
|
|
3651
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3305
3652
|
if (!this.baseUrl) {
|
|
3306
3653
|
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3307
3654
|
}
|
|
@@ -3315,8 +3662,8 @@ var UniversalLLMAdapter = class {
|
|
|
3315
3662
|
});
|
|
3316
3663
|
}
|
|
3317
3664
|
async chat(messages, context) {
|
|
3318
|
-
var
|
|
3319
|
-
const
|
|
3665
|
+
var _a2, _b;
|
|
3666
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3320
3667
|
const formattedMessages = [
|
|
3321
3668
|
{ role: "system", content: `${this.systemPrompt}
|
|
3322
3669
|
|
|
@@ -3340,7 +3687,7 @@ ${context != null ? context : "None"}` },
|
|
|
3340
3687
|
temperature: this.temperature
|
|
3341
3688
|
};
|
|
3342
3689
|
}
|
|
3343
|
-
const { data } = await this.http.post(
|
|
3690
|
+
const { data } = await this.http.post(path2, payload);
|
|
3344
3691
|
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3345
3692
|
const result = resolvePath(data, extractPath);
|
|
3346
3693
|
if (result === void 0) {
|
|
@@ -3355,9 +3702,9 @@ ${context != null ? context : "None"}` },
|
|
|
3355
3702
|
*/
|
|
3356
3703
|
chatStream(messages, context) {
|
|
3357
3704
|
return __asyncGenerator(this, null, function* () {
|
|
3358
|
-
var
|
|
3359
|
-
const
|
|
3360
|
-
const url = `${this.baseUrl.replace(/\/$/, "")}${
|
|
3705
|
+
var _a2, _b, _c;
|
|
3706
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3707
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3361
3708
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3362
3709
|
const formattedMessages = [
|
|
3363
3710
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3435,8 +3782,8 @@ ${context != null ? context : "None"}` },
|
|
|
3435
3782
|
});
|
|
3436
3783
|
}
|
|
3437
3784
|
async embed(text) {
|
|
3438
|
-
var
|
|
3439
|
-
const
|
|
3785
|
+
var _a2, _b;
|
|
3786
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3440
3787
|
let payload;
|
|
3441
3788
|
if (this.opts.embedPayloadTemplate) {
|
|
3442
3789
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3449,7 +3796,7 @@ ${context != null ? context : "None"}` },
|
|
|
3449
3796
|
input: text
|
|
3450
3797
|
};
|
|
3451
3798
|
}
|
|
3452
|
-
const { data } = await this.http.post(
|
|
3799
|
+
const { data } = await this.http.post(path2, payload);
|
|
3453
3800
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3454
3801
|
const vector = resolvePath(data, extractPath);
|
|
3455
3802
|
if (!Array.isArray(vector)) {
|
|
@@ -3517,13 +3864,13 @@ var AuthenticationException = class extends RetrivoraError {
|
|
|
3517
3864
|
}
|
|
3518
3865
|
};
|
|
3519
3866
|
function wrapError(err, defaultCode, defaultMessage) {
|
|
3520
|
-
var
|
|
3867
|
+
var _a2;
|
|
3521
3868
|
if (err instanceof RetrivoraError) {
|
|
3522
3869
|
return err;
|
|
3523
3870
|
}
|
|
3524
3871
|
const error = err;
|
|
3525
3872
|
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) || ((
|
|
3873
|
+
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
3874
|
const code = error == null ? void 0 : error.code;
|
|
3528
3875
|
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3529
3876
|
return new RateLimitException(message, err);
|
|
@@ -3587,6 +3934,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3587
3934
|
"anthropic",
|
|
3588
3935
|
"ollama",
|
|
3589
3936
|
"gemini",
|
|
3937
|
+
"groq",
|
|
3938
|
+
"qwen",
|
|
3590
3939
|
"rest",
|
|
3591
3940
|
"universal_rest",
|
|
3592
3941
|
"custom",
|
|
@@ -3594,7 +3943,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3594
3943
|
];
|
|
3595
3944
|
}
|
|
3596
3945
|
static create(llmConfig, embeddingConfig) {
|
|
3597
|
-
var
|
|
3946
|
+
var _a2, _b, _c;
|
|
3598
3947
|
switch (llmConfig.provider) {
|
|
3599
3948
|
case "openai":
|
|
3600
3949
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3604,12 +3953,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3604
3953
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3605
3954
|
case "gemini":
|
|
3606
3955
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3956
|
+
case "groq":
|
|
3957
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3958
|
+
case "qwen":
|
|
3959
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3607
3960
|
case "rest":
|
|
3608
3961
|
case "universal_rest":
|
|
3609
3962
|
case "custom":
|
|
3610
3963
|
return new UniversalLLMAdapter(llmConfig);
|
|
3611
3964
|
default: {
|
|
3612
|
-
const providerName = String((
|
|
3965
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3613
3966
|
const customFactory = customProviders.get(providerName);
|
|
3614
3967
|
if (customFactory) {
|
|
3615
3968
|
return customFactory(llmConfig);
|
|
@@ -3646,6 +3999,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3646
3999
|
return OllamaProvider;
|
|
3647
4000
|
case "gemini":
|
|
3648
4001
|
return GeminiProvider;
|
|
4002
|
+
case "groq":
|
|
4003
|
+
return GroqProvider;
|
|
4004
|
+
case "qwen":
|
|
4005
|
+
return QwenProvider;
|
|
3649
4006
|
case "rest":
|
|
3650
4007
|
case "universal_rest":
|
|
3651
4008
|
case "custom":
|
|
@@ -3707,7 +4064,7 @@ var ProviderRegistry = class {
|
|
|
3707
4064
|
return null;
|
|
3708
4065
|
}
|
|
3709
4066
|
static async loadVectorProviderClass(provider) {
|
|
3710
|
-
var
|
|
4067
|
+
var _a2;
|
|
3711
4068
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3712
4069
|
switch (provider) {
|
|
3713
4070
|
case "pinecone": {
|
|
@@ -3716,7 +4073,7 @@ var ProviderRegistry = class {
|
|
|
3716
4073
|
}
|
|
3717
4074
|
case "pgvector":
|
|
3718
4075
|
case "postgresql": {
|
|
3719
|
-
const postgresMode = ((
|
|
4076
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3720
4077
|
if (postgresMode === "single") {
|
|
3721
4078
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3722
4079
|
return PostgreSQLProvider2;
|
|
@@ -3936,6 +4293,125 @@ var ConfigValidator = class {
|
|
|
3936
4293
|
}
|
|
3937
4294
|
};
|
|
3938
4295
|
|
|
4296
|
+
// src/core/LicenseVerifier.ts
|
|
4297
|
+
var crypto2 = __toESM(require("crypto"));
|
|
4298
|
+
var LicenseVerifier = class {
|
|
4299
|
+
/**
|
|
4300
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
4301
|
+
*
|
|
4302
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
4303
|
+
* @param currentProjectId - Project namespace ID.
|
|
4304
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
4305
|
+
*/
|
|
4306
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
4307
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4308
|
+
if (!licenseKey) {
|
|
4309
|
+
if (isProduction) {
|
|
4310
|
+
throw new ConfigurationException(
|
|
4311
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
4312
|
+
);
|
|
4313
|
+
}
|
|
4314
|
+
console.warn(
|
|
4315
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
4316
|
+
);
|
|
4317
|
+
return {
|
|
4318
|
+
projectId: currentProjectId,
|
|
4319
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
4320
|
+
// Valid for 24h
|
|
4321
|
+
tier: "hobby"
|
|
4322
|
+
};
|
|
4323
|
+
}
|
|
4324
|
+
try {
|
|
4325
|
+
const parts = licenseKey.split(".");
|
|
4326
|
+
if (parts.length !== 3) {
|
|
4327
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
4328
|
+
}
|
|
4329
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
4330
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
4331
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
4332
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
4333
|
+
const data = Buffer.from(dataToVerify);
|
|
4334
|
+
const isValid = crypto2.verify(
|
|
4335
|
+
"sha256",
|
|
4336
|
+
data,
|
|
4337
|
+
publicKey,
|
|
4338
|
+
signature
|
|
4339
|
+
);
|
|
4340
|
+
if (!isValid) {
|
|
4341
|
+
throw new Error("Signature verification failed.");
|
|
4342
|
+
}
|
|
4343
|
+
const payload = JSON.parse(
|
|
4344
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4345
|
+
);
|
|
4346
|
+
if (!payload.projectId) {
|
|
4347
|
+
throw new Error('License payload is missing "projectId".');
|
|
4348
|
+
}
|
|
4349
|
+
if (payload.projectId !== currentProjectId) {
|
|
4350
|
+
throw new Error(
|
|
4351
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
4352
|
+
);
|
|
4353
|
+
}
|
|
4354
|
+
if (!payload.expiresAt) {
|
|
4355
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
4356
|
+
}
|
|
4357
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
4358
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
4359
|
+
throw new Error(
|
|
4360
|
+
`License key has expired. Expiration: ${new Date(
|
|
4361
|
+
payload.expiresAt * 1e3
|
|
4362
|
+
).toDateString()}`
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
if (isProduction && provider) {
|
|
4366
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
4367
|
+
const normalizedProvider = provider.toLowerCase();
|
|
4368
|
+
if (tier === "hobby") {
|
|
4369
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
4370
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
4371
|
+
throw new Error(
|
|
4372
|
+
`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.`
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4375
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
4376
|
+
const allowedPro = [
|
|
4377
|
+
"postgresql",
|
|
4378
|
+
"pgvector",
|
|
4379
|
+
"supabase",
|
|
4380
|
+
"pinecone",
|
|
4381
|
+
"qdrant",
|
|
4382
|
+
"mongodb",
|
|
4383
|
+
"milvus",
|
|
4384
|
+
"chroma",
|
|
4385
|
+
"chromadb"
|
|
4386
|
+
];
|
|
4387
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
4388
|
+
throw new Error(
|
|
4389
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
4390
|
+
);
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
return payload;
|
|
4395
|
+
} catch (err) {
|
|
4396
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4397
|
+
throw new ConfigurationException(
|
|
4398
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
4399
|
+
);
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4402
|
+
};
|
|
4403
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
4404
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
4405
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
4406
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
4407
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
4408
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
4409
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
4410
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
4411
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
4412
|
+
MwIDAQAB
|
|
4413
|
+
-----END PUBLIC KEY-----`;
|
|
4414
|
+
|
|
3939
4415
|
// src/rag/DocumentChunker.ts
|
|
3940
4416
|
var DocumentChunker = class {
|
|
3941
4417
|
constructor(chunkSize = 1e3, chunkOverlap = 200, separators = ["\n# ", "\n## ", "\n### ", "\n#### ", "\n\n", "\n", " ", ""]) {
|
|
@@ -4165,11 +4641,11 @@ var LlamaIndexIngestor = class {
|
|
|
4165
4641
|
* than standard character-count splitting.
|
|
4166
4642
|
*/
|
|
4167
4643
|
async chunk(text, options = {}) {
|
|
4168
|
-
var
|
|
4644
|
+
var _a2, _b;
|
|
4169
4645
|
try {
|
|
4170
4646
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4171
4647
|
const splitter = new SentenceSplitter({
|
|
4172
|
-
chunkSize: (
|
|
4648
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4173
4649
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4174
4650
|
});
|
|
4175
4651
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4278,7 +4754,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4278
4754
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4279
4755
|
*/
|
|
4280
4756
|
async run(input, chatHistory = []) {
|
|
4281
|
-
var
|
|
4757
|
+
var _a2, _b, _c;
|
|
4282
4758
|
if (!this.agent) {
|
|
4283
4759
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4284
4760
|
}
|
|
@@ -4289,14 +4765,445 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4289
4765
|
const response = await this.agent.invoke({
|
|
4290
4766
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4291
4767
|
});
|
|
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 : "");
|
|
4768
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4769
|
+
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4770
|
+
return lastMessage.content;
|
|
4771
|
+
}
|
|
4772
|
+
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
4773
|
+
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4774
|
+
}
|
|
4775
|
+
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
4776
|
+
}
|
|
4777
|
+
};
|
|
4778
|
+
|
|
4779
|
+
// src/core/mcp.ts
|
|
4780
|
+
var import_child_process = require("child_process");
|
|
4781
|
+
var MCPClient = class {
|
|
4782
|
+
constructor(config) {
|
|
4783
|
+
this.config = config;
|
|
4784
|
+
this.messageIdCounter = 0;
|
|
4785
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4786
|
+
this.stdioBuffer = "";
|
|
4787
|
+
this.initialized = false;
|
|
4788
|
+
}
|
|
4789
|
+
getNextMessageId() {
|
|
4790
|
+
return ++this.messageIdCounter;
|
|
4791
|
+
}
|
|
4792
|
+
/**
|
|
4793
|
+
* Connect and initialize the MCP server connection.
|
|
4794
|
+
*/
|
|
4795
|
+
async connect() {
|
|
4796
|
+
if (this.initialized) return;
|
|
4797
|
+
if (this.config.transport === "stdio") {
|
|
4798
|
+
await this.connectStdio();
|
|
4799
|
+
} else {
|
|
4800
|
+
await this.connectSSE();
|
|
4801
|
+
}
|
|
4802
|
+
try {
|
|
4803
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4804
|
+
protocolVersion: "2024-11-05",
|
|
4805
|
+
capabilities: {},
|
|
4806
|
+
clientInfo: {
|
|
4807
|
+
name: "retrivora-sdk",
|
|
4808
|
+
version: "1.0.0"
|
|
4809
|
+
}
|
|
4810
|
+
});
|
|
4811
|
+
await this.sendNotification("notifications/initialized");
|
|
4812
|
+
this.initialized = true;
|
|
4813
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4814
|
+
} catch (err) {
|
|
4815
|
+
this.disconnect();
|
|
4816
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
async connectStdio() {
|
|
4820
|
+
var _a2;
|
|
4821
|
+
const cmd = this.config.command;
|
|
4822
|
+
if (!cmd) {
|
|
4823
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4824
|
+
}
|
|
4825
|
+
const args = this.config.args || [];
|
|
4826
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4827
|
+
this.childProcess = (0, import_child_process.spawn)(cmd, args, { env, shell: true });
|
|
4828
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4829
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4830
|
+
}
|
|
4831
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4832
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4833
|
+
this.processStdioLines();
|
|
4834
|
+
});
|
|
4835
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4836
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4837
|
+
});
|
|
4838
|
+
this.childProcess.on("close", (code) => {
|
|
4839
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4840
|
+
this.disconnect();
|
|
4841
|
+
});
|
|
4842
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4843
|
+
}
|
|
4844
|
+
processStdioLines() {
|
|
4845
|
+
let newlineIndex;
|
|
4846
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4847
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4848
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4849
|
+
if (!line) continue;
|
|
4850
|
+
try {
|
|
4851
|
+
const payload = JSON.parse(line);
|
|
4852
|
+
if (payload.id !== void 0) {
|
|
4853
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4854
|
+
if (req) {
|
|
4855
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4856
|
+
if (payload.error) {
|
|
4857
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4858
|
+
} else {
|
|
4859
|
+
req.resolve(payload.result);
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
} catch (e) {
|
|
4864
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
async connectSSE() {
|
|
4869
|
+
if (!this.config.url) {
|
|
4870
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4871
|
+
}
|
|
4872
|
+
this.sseUrl = this.config.url;
|
|
4873
|
+
}
|
|
4874
|
+
async sendJsonRpc(method, params) {
|
|
4875
|
+
const id = this.getNextMessageId();
|
|
4876
|
+
const request = {
|
|
4877
|
+
jsonrpc: "2.0",
|
|
4878
|
+
id,
|
|
4879
|
+
method,
|
|
4880
|
+
params
|
|
4881
|
+
};
|
|
4882
|
+
if (this.config.transport === "stdio") {
|
|
4883
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4884
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4885
|
+
}
|
|
4886
|
+
return new Promise((resolve, reject) => {
|
|
4887
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4888
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4889
|
+
});
|
|
4890
|
+
} else {
|
|
4891
|
+
if (!this.sseUrl) {
|
|
4892
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4893
|
+
}
|
|
4894
|
+
const response = await fetch(this.sseUrl, {
|
|
4895
|
+
method: "POST",
|
|
4896
|
+
headers: { "Content-Type": "application/json" },
|
|
4897
|
+
body: JSON.stringify(request)
|
|
4898
|
+
});
|
|
4899
|
+
if (!response.ok) {
|
|
4900
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4901
|
+
}
|
|
4902
|
+
const payload = await response.json();
|
|
4903
|
+
if (payload.error) {
|
|
4904
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4905
|
+
}
|
|
4906
|
+
return payload.result;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
async sendNotification(method, params) {
|
|
4910
|
+
var _a2;
|
|
4911
|
+
const notification = {
|
|
4912
|
+
jsonrpc: "2.0",
|
|
4913
|
+
method,
|
|
4914
|
+
params
|
|
4915
|
+
};
|
|
4916
|
+
if (this.config.transport === "stdio") {
|
|
4917
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4918
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4919
|
+
}
|
|
4920
|
+
} else if (this.sseUrl) {
|
|
4921
|
+
await fetch(this.sseUrl, {
|
|
4922
|
+
method: "POST",
|
|
4923
|
+
headers: { "Content-Type": "application/json" },
|
|
4924
|
+
body: JSON.stringify(notification)
|
|
4925
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
/**
|
|
4929
|
+
* List all tools offered by the MCP server.
|
|
4930
|
+
*/
|
|
4931
|
+
async listTools() {
|
|
4932
|
+
await this.connect();
|
|
4933
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4934
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4935
|
+
}
|
|
4936
|
+
/**
|
|
4937
|
+
* Execute a tool on the MCP server.
|
|
4938
|
+
*/
|
|
4939
|
+
async callTool(name, args = {}) {
|
|
4940
|
+
await this.connect();
|
|
4941
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4942
|
+
}
|
|
4943
|
+
disconnect() {
|
|
4944
|
+
this.initialized = false;
|
|
4945
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4946
|
+
this.pendingRequests.clear();
|
|
4947
|
+
if (this.childProcess) {
|
|
4948
|
+
try {
|
|
4949
|
+
this.childProcess.kill();
|
|
4950
|
+
} catch (e) {
|
|
4951
|
+
}
|
|
4952
|
+
this.childProcess = void 0;
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
};
|
|
4956
|
+
var MCPRegistry = class {
|
|
4957
|
+
constructor(servers = []) {
|
|
4958
|
+
this.clients = [];
|
|
4959
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4960
|
+
}
|
|
4961
|
+
async getAllTools() {
|
|
4962
|
+
const list = [];
|
|
4963
|
+
await Promise.all(
|
|
4964
|
+
this.clients.map(async (client) => {
|
|
4965
|
+
try {
|
|
4966
|
+
const tools = await client.listTools();
|
|
4967
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4968
|
+
} catch (e) {
|
|
4969
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4970
|
+
}
|
|
4971
|
+
})
|
|
4972
|
+
);
|
|
4973
|
+
return list;
|
|
4974
|
+
}
|
|
4975
|
+
async callTool(toolName, args = {}) {
|
|
4976
|
+
for (const client of this.clients) {
|
|
4977
|
+
try {
|
|
4978
|
+
const tools = await client.listTools();
|
|
4979
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4980
|
+
return await client.callTool(toolName, args);
|
|
4981
|
+
}
|
|
4982
|
+
} catch (e) {
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4986
|
+
}
|
|
4987
|
+
disconnectAll() {
|
|
4988
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4989
|
+
}
|
|
4990
|
+
};
|
|
4991
|
+
|
|
4992
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4993
|
+
var MultiAgentCoordinator = class {
|
|
4994
|
+
constructor(options) {
|
|
4995
|
+
var _a2;
|
|
4996
|
+
this.llmProvider = options.llmProvider;
|
|
4997
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4998
|
+
this.documentSearch = options.documentSearch;
|
|
4999
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
5000
|
+
}
|
|
5001
|
+
/**
|
|
5002
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
5003
|
+
*/
|
|
5004
|
+
async run(question, history = []) {
|
|
5005
|
+
const generator = this.runStream(question, history);
|
|
5006
|
+
let finalReply = "";
|
|
5007
|
+
const sources = [];
|
|
5008
|
+
try {
|
|
5009
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
5010
|
+
const chunk = temp.value;
|
|
5011
|
+
if (typeof chunk === "string") {
|
|
5012
|
+
finalReply += chunk;
|
|
5013
|
+
} else if (chunk && typeof chunk === "object") {
|
|
5014
|
+
if ("reply" in chunk && chunk.reply) {
|
|
5015
|
+
finalReply += chunk.reply;
|
|
5016
|
+
}
|
|
5017
|
+
if ("sources" in chunk && chunk.sources) {
|
|
5018
|
+
sources.push(...chunk.sources);
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
} catch (temp) {
|
|
5023
|
+
error = [temp];
|
|
5024
|
+
} finally {
|
|
5025
|
+
try {
|
|
5026
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
5027
|
+
} finally {
|
|
5028
|
+
if (error)
|
|
5029
|
+
throw error[0];
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
return {
|
|
5033
|
+
reply: finalReply,
|
|
5034
|
+
sources
|
|
5035
|
+
};
|
|
5036
|
+
}
|
|
5037
|
+
/**
|
|
5038
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
5039
|
+
*/
|
|
5040
|
+
runStream(_0) {
|
|
5041
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
5042
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
5043
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
5044
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
5045
|
+
|
|
5046
|
+
Available Tools:
|
|
5047
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
5048
|
+
|
|
5049
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
5050
|
+
${mcpTools.map((mt) => {
|
|
5051
|
+
var _a2;
|
|
5052
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
5053
|
+
}).join("\n")}
|
|
5054
|
+
|
|
5055
|
+
Tool Calling Protocol:
|
|
5056
|
+
If you need to call a tool, write:
|
|
5057
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
5058
|
+
And then STOP generating immediately.
|
|
5059
|
+
|
|
5060
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
5061
|
+
`;
|
|
5062
|
+
const supervisorHistory = [
|
|
5063
|
+
{ role: "system", content: systemPrompt },
|
|
5064
|
+
...history,
|
|
5065
|
+
{ role: "user", content: question }
|
|
5066
|
+
];
|
|
5067
|
+
let iteration = 0;
|
|
5068
|
+
const allSources = [];
|
|
5069
|
+
while (iteration < this.maxIterations) {
|
|
5070
|
+
iteration++;
|
|
5071
|
+
const context = "";
|
|
5072
|
+
let fullModelResponse = "";
|
|
5073
|
+
let textBuffer = "";
|
|
5074
|
+
let inThinking = false;
|
|
5075
|
+
let toolCallDetected = null;
|
|
5076
|
+
if (!this.llmProvider.chatStream) {
|
|
5077
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
5078
|
+
fullModelResponse = reply;
|
|
5079
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
5080
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
5081
|
+
let thinkingText = "";
|
|
5082
|
+
let answerText = reply;
|
|
5083
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
5084
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
5085
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
5086
|
+
yield { type: "thinking", text: thinkingText };
|
|
5087
|
+
}
|
|
5088
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5089
|
+
if (toolMatch) {
|
|
5090
|
+
const toolName = toolMatch[1];
|
|
5091
|
+
const toolArgsStr = toolMatch[2];
|
|
5092
|
+
try {
|
|
5093
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5094
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5095
|
+
} catch (e) {
|
|
5096
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5097
|
+
}
|
|
5098
|
+
} else {
|
|
5099
|
+
yield answerText;
|
|
5100
|
+
}
|
|
5101
|
+
} else {
|
|
5102
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
5103
|
+
try {
|
|
5104
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
5105
|
+
const chunk = temp.value;
|
|
5106
|
+
fullModelResponse += chunk;
|
|
5107
|
+
textBuffer += chunk;
|
|
5108
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
5109
|
+
inThinking = true;
|
|
5110
|
+
const idx = textBuffer.indexOf("<think>");
|
|
5111
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
5112
|
+
}
|
|
5113
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
5114
|
+
inThinking = false;
|
|
5115
|
+
const idx = textBuffer.indexOf("</think>");
|
|
5116
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
5117
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
5118
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
5119
|
+
}
|
|
5120
|
+
if (inThinking && textBuffer.length > 0) {
|
|
5121
|
+
yield { type: "thinking", text: textBuffer };
|
|
5122
|
+
textBuffer = "";
|
|
5123
|
+
}
|
|
5124
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
5125
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
5126
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
5127
|
+
if (precedingText.trim()) {
|
|
5128
|
+
yield precedingText;
|
|
5129
|
+
}
|
|
5130
|
+
textBuffer = textBuffer.slice(idx);
|
|
5131
|
+
}
|
|
5132
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
5133
|
+
yield textBuffer;
|
|
5134
|
+
textBuffer = "";
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
} catch (temp) {
|
|
5138
|
+
error = [temp];
|
|
5139
|
+
} finally {
|
|
5140
|
+
try {
|
|
5141
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
5142
|
+
} finally {
|
|
5143
|
+
if (error)
|
|
5144
|
+
throw error[0];
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
if (textBuffer.trim()) {
|
|
5148
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5149
|
+
if (toolMatch) {
|
|
5150
|
+
const toolName = toolMatch[1];
|
|
5151
|
+
const toolArgsStr = toolMatch[2];
|
|
5152
|
+
try {
|
|
5153
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5154
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5155
|
+
} catch (e) {
|
|
5156
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5157
|
+
}
|
|
5158
|
+
} else {
|
|
5159
|
+
yield textBuffer;
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5163
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
5164
|
+
if (toolCallDetected) {
|
|
5165
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
5166
|
+
yield {
|
|
5167
|
+
type: "thinking",
|
|
5168
|
+
text: `
|
|
5169
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
5170
|
+
`
|
|
5171
|
+
};
|
|
5172
|
+
let toolResultText = "";
|
|
5173
|
+
try {
|
|
5174
|
+
if (toolName === "document_search") {
|
|
5175
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
5176
|
+
toolResultText = `document_search returned:
|
|
5177
|
+
${searchRes.reply}
|
|
5178
|
+
|
|
5179
|
+
Sources count: ${searchRes.sources.length}`;
|
|
5180
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
5181
|
+
allSources.push(...searchRes.sources);
|
|
5182
|
+
yield { reply: "", sources: searchRes.sources };
|
|
5183
|
+
}
|
|
5184
|
+
} else {
|
|
5185
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
5186
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
5187
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
5188
|
+
}
|
|
5189
|
+
} catch (err) {
|
|
5190
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
5191
|
+
}
|
|
5192
|
+
supervisorHistory.push({
|
|
5193
|
+
role: "user",
|
|
5194
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
5195
|
+
${toolResultText}`
|
|
5196
|
+
});
|
|
5197
|
+
yield {
|
|
5198
|
+
type: "thinking",
|
|
5199
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
5200
|
+
`
|
|
5201
|
+
};
|
|
5202
|
+
} else {
|
|
5203
|
+
break;
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
});
|
|
4300
5207
|
}
|
|
4301
5208
|
};
|
|
4302
5209
|
|
|
@@ -4626,7 +5533,7 @@ var QueryProcessor = class {
|
|
|
4626
5533
|
* @param validFields Optional list of known filterable fields to look for
|
|
4627
5534
|
*/
|
|
4628
5535
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4629
|
-
var
|
|
5536
|
+
var _a2, _b, _c, _d;
|
|
4630
5537
|
if (!question.trim()) return [];
|
|
4631
5538
|
const hints = /* @__PURE__ */ new Map();
|
|
4632
5539
|
const addHint = (value, field) => {
|
|
@@ -4706,7 +5613,7 @@ var QueryProcessor = class {
|
|
|
4706
5613
|
];
|
|
4707
5614
|
for (const p of universalPatterns) {
|
|
4708
5615
|
for (const match of question.matchAll(p.regex)) {
|
|
4709
|
-
const val = p.group ? (
|
|
5616
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4710
5617
|
if (!val) continue;
|
|
4711
5618
|
if (p.field) addHint(val, p.field);
|
|
4712
5619
|
else addHint(val);
|
|
@@ -4930,11 +5837,11 @@ var LLMRouter = class {
|
|
|
4930
5837
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4931
5838
|
*/
|
|
4932
5839
|
async initialize(prebuiltDefault) {
|
|
4933
|
-
var
|
|
5840
|
+
var _a2;
|
|
4934
5841
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4935
5842
|
this.models.set("default", defaultModel);
|
|
4936
5843
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4937
|
-
const providerFastDefault = (
|
|
5844
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4938
5845
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4939
5846
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4940
5847
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4953,8 +5860,8 @@ var LLMRouter = class {
|
|
|
4953
5860
|
* Falls back to 'default' if the requested role is not registered.
|
|
4954
5861
|
*/
|
|
4955
5862
|
get(role) {
|
|
4956
|
-
var
|
|
4957
|
-
const provider = (
|
|
5863
|
+
var _a2;
|
|
5864
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4958
5865
|
if (!provider) {
|
|
4959
5866
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4960
5867
|
}
|
|
@@ -4972,7 +5879,7 @@ var UITransformer = class _UITransformer {
|
|
|
4972
5879
|
* Prefer `analyzeAndDecide()` in production.
|
|
4973
5880
|
*/
|
|
4974
5881
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4975
|
-
var
|
|
5882
|
+
var _a2, _b, _c;
|
|
4976
5883
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4977
5884
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4978
5885
|
}
|
|
@@ -4992,7 +5899,7 @@ var UITransformer = class _UITransformer {
|
|
|
4992
5899
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4993
5900
|
}
|
|
4994
5901
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4995
|
-
return (
|
|
5902
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4996
5903
|
}
|
|
4997
5904
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4998
5905
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5317,11 +6224,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5317
6224
|
};
|
|
5318
6225
|
}
|
|
5319
6226
|
static transformToPieChart(data, profile, query = "") {
|
|
5320
|
-
var
|
|
6227
|
+
var _a2;
|
|
5321
6228
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5322
6229
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5323
|
-
var
|
|
5324
|
-
return String((
|
|
6230
|
+
var _a3;
|
|
6231
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5325
6232
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5326
6233
|
if (categories.length === 0) return null;
|
|
5327
6234
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5331,7 +6238,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5331
6238
|
});
|
|
5332
6239
|
return {
|
|
5333
6240
|
type: "pie_chart",
|
|
5334
|
-
title: `Distribution by ${(
|
|
6241
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5335
6242
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5336
6243
|
data: pieData
|
|
5337
6244
|
};
|
|
@@ -5341,8 +6248,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5341
6248
|
const valueField = profile.numericFields[0];
|
|
5342
6249
|
const buckets = /* @__PURE__ */ new Map();
|
|
5343
6250
|
profile.records.forEach((record) => {
|
|
5344
|
-
var
|
|
5345
|
-
const timestamp = String((
|
|
6251
|
+
var _a2, _b, _c;
|
|
6252
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5346
6253
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5347
6254
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5348
6255
|
});
|
|
@@ -5355,23 +6262,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5355
6262
|
};
|
|
5356
6263
|
}
|
|
5357
6264
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5358
|
-
var
|
|
6265
|
+
var _a2;
|
|
5359
6266
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5360
6267
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5361
6268
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5362
6269
|
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
6270
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5364
|
-
var
|
|
6271
|
+
var _a3, _b, _c, _d, _e;
|
|
5365
6272
|
const meta = item.metadata || {};
|
|
5366
6273
|
const label = String(
|
|
5367
|
-
(_c = (_b = (
|
|
6274
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5368
6275
|
);
|
|
5369
6276
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5370
6277
|
return { category: label, value: Number(value) };
|
|
5371
6278
|
});
|
|
5372
6279
|
return {
|
|
5373
6280
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5374
|
-
title: dimension ? `${(
|
|
6281
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5375
6282
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5376
6283
|
data: fallbackData
|
|
5377
6284
|
};
|
|
@@ -5406,11 +6313,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5406
6313
|
if (fields.length < 2) return null;
|
|
5407
6314
|
const [xField, yField] = fields;
|
|
5408
6315
|
const points = profile.records.map((record) => {
|
|
5409
|
-
var
|
|
6316
|
+
var _a2;
|
|
5410
6317
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5411
6318
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5412
6319
|
if (x === null || y === null) return null;
|
|
5413
|
-
return { x, y, label: String((
|
|
6320
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5414
6321
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5415
6322
|
if (points.length === 0) return null;
|
|
5416
6323
|
return {
|
|
@@ -5440,9 +6347,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5440
6347
|
static transformToRadarChart(data) {
|
|
5441
6348
|
const attributeMap = {};
|
|
5442
6349
|
data.forEach((item) => {
|
|
5443
|
-
var
|
|
6350
|
+
var _a2, _b, _c;
|
|
5444
6351
|
const meta = item.metadata || {};
|
|
5445
|
-
const seriesName = String((_c = (_b = (
|
|
6352
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5446
6353
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5447
6354
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5448
6355
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5524,22 +6431,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5524
6431
|
return null;
|
|
5525
6432
|
}
|
|
5526
6433
|
static normalizeTransformation(payload) {
|
|
5527
|
-
var
|
|
6434
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5528
6435
|
if (!payload || typeof payload !== "object") return null;
|
|
5529
6436
|
const p = payload;
|
|
5530
6437
|
const type = this.normalizeVisualizationType(
|
|
5531
|
-
String((_c = (_b = (
|
|
6438
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5532
6439
|
);
|
|
5533
6440
|
if (!type) return null;
|
|
5534
6441
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5535
6442
|
const description = p.description ? String(p.description) : void 0;
|
|
5536
|
-
const rawData = (_j = (_i = (_h = (
|
|
6443
|
+
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
6444
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5538
6445
|
const transformation = { type, title, description, data };
|
|
5539
6446
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5540
6447
|
}
|
|
5541
6448
|
static normalizeVisualizationType(type) {
|
|
5542
|
-
var
|
|
6449
|
+
var _a2;
|
|
5543
6450
|
const mapping = {
|
|
5544
6451
|
pie: "pie_chart",
|
|
5545
6452
|
pie_chart: "pie_chart",
|
|
@@ -5567,7 +6474,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5567
6474
|
product_carousel: "product_carousel",
|
|
5568
6475
|
carousel: "carousel"
|
|
5569
6476
|
};
|
|
5570
|
-
return (
|
|
6477
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5571
6478
|
}
|
|
5572
6479
|
static validateTransformation(t) {
|
|
5573
6480
|
const { type, data } = t;
|
|
@@ -5769,16 +6676,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5769
6676
|
return null;
|
|
5770
6677
|
}
|
|
5771
6678
|
static selectDimensionField(profile, query) {
|
|
5772
|
-
var
|
|
6679
|
+
var _a2, _b;
|
|
5773
6680
|
const productCategory = profile.categoricalFields.find(
|
|
5774
6681
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5775
6682
|
);
|
|
5776
6683
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5777
|
-
return (_b = (
|
|
6684
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5778
6685
|
}
|
|
5779
6686
|
static selectNumericField(profile, query) {
|
|
5780
|
-
var
|
|
5781
|
-
return (
|
|
6687
|
+
var _a2;
|
|
6688
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5782
6689
|
}
|
|
5783
6690
|
static rankFieldsByQuery(fields, query) {
|
|
5784
6691
|
const q = query.toLowerCase();
|
|
@@ -5807,8 +6714,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5807
6714
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5808
6715
|
const result = {};
|
|
5809
6716
|
profile.records.forEach((record) => {
|
|
5810
|
-
var
|
|
5811
|
-
const category = String((
|
|
6717
|
+
var _a2, _b, _c;
|
|
6718
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5812
6719
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5813
6720
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5814
6721
|
});
|
|
@@ -5887,8 +6794,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5887
6794
|
static aggregateByCategory(data, categories) {
|
|
5888
6795
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5889
6796
|
data.forEach((item) => {
|
|
5890
|
-
var
|
|
5891
|
-
const cat = (
|
|
6797
|
+
var _a2;
|
|
6798
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5892
6799
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5893
6800
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5894
6801
|
});
|
|
@@ -5896,17 +6803,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5896
6803
|
}
|
|
5897
6804
|
static extractTimeSeriesData(data) {
|
|
5898
6805
|
return data.map((item) => {
|
|
5899
|
-
var
|
|
6806
|
+
var _a2, _b, _c, _d, _e;
|
|
5900
6807
|
const meta = item.metadata || {};
|
|
5901
6808
|
return {
|
|
5902
|
-
timestamp: (_b = (
|
|
6809
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5903
6810
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5904
6811
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5905
6812
|
};
|
|
5906
6813
|
});
|
|
5907
6814
|
}
|
|
5908
6815
|
static extractNumericValue(meta) {
|
|
5909
|
-
var
|
|
6816
|
+
var _a2;
|
|
5910
6817
|
const preferredKeys = [
|
|
5911
6818
|
"value",
|
|
5912
6819
|
"count",
|
|
@@ -5921,7 +6828,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5921
6828
|
"price"
|
|
5922
6829
|
];
|
|
5923
6830
|
for (const key of preferredKeys) {
|
|
5924
|
-
const raw = (
|
|
6831
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5925
6832
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5926
6833
|
if (Number.isFinite(value)) return value;
|
|
5927
6834
|
}
|
|
@@ -6067,8 +6974,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
6067
6974
|
let inStock = 0;
|
|
6068
6975
|
let outOfStock = 0;
|
|
6069
6976
|
data.forEach((d) => {
|
|
6070
|
-
var
|
|
6071
|
-
const cat = (
|
|
6977
|
+
var _a2, _b;
|
|
6978
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
6072
6979
|
if (cat === category) {
|
|
6073
6980
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
6074
6981
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -6112,9 +7019,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
6112
7019
|
}
|
|
6113
7020
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
6114
7021
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
6115
|
-
var
|
|
7022
|
+
var _a2;
|
|
6116
7023
|
if (!meta) return void 0;
|
|
6117
|
-
const mapping = (
|
|
7024
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
6118
7025
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
6119
7026
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
6120
7027
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -6123,13 +7030,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6123
7030
|
return resolveMetadataValue(meta, uiKey);
|
|
6124
7031
|
}
|
|
6125
7032
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6126
|
-
var
|
|
7033
|
+
var _a2;
|
|
6127
7034
|
const meta = item.metadata || {};
|
|
6128
7035
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6129
7036
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6130
7037
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6131
7038
|
const description = this.cleanProductDescription(
|
|
6132
|
-
(
|
|
7039
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6133
7040
|
);
|
|
6134
7041
|
if (name || this.isProductData(item)) {
|
|
6135
7042
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6237,10 +7144,10 @@ RULES:
|
|
|
6237
7144
|
}
|
|
6238
7145
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6239
7146
|
const items = sources.map((s, i) => {
|
|
6240
|
-
var
|
|
7147
|
+
var _a2, _b, _c, _d;
|
|
6241
7148
|
return {
|
|
6242
7149
|
index: i + 1,
|
|
6243
|
-
content: (_b = (
|
|
7150
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6244
7151
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6245
7152
|
score: (_d = s.score) != null ? _d : 0
|
|
6246
7153
|
};
|
|
@@ -6433,9 +7340,11 @@ var Pipeline = class {
|
|
|
6433
7340
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6434
7341
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6435
7342
|
this.initialised = false;
|
|
6436
|
-
|
|
7343
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7344
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7345
|
+
var _a2, _b, _c, _d, _e;
|
|
6437
7346
|
this.chunker = new DocumentChunker(
|
|
6438
|
-
(_b = (
|
|
7347
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6439
7348
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6440
7349
|
);
|
|
6441
7350
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6451,7 +7360,7 @@ var Pipeline = class {
|
|
|
6451
7360
|
return this.initialised ? this.llmProvider : void 0;
|
|
6452
7361
|
}
|
|
6453
7362
|
async initialize() {
|
|
6454
|
-
var
|
|
7363
|
+
var _a2, _b, _c;
|
|
6455
7364
|
if (this.initialised) return;
|
|
6456
7365
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6457
7366
|
|
|
@@ -6494,12 +7403,47 @@ var Pipeline = class {
|
|
|
6494
7403
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6495
7404
|
}
|
|
6496
7405
|
await this.vectorDB.initialize();
|
|
6497
|
-
if (((
|
|
7406
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7407
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7408
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7409
|
+
llmProvider: this.llmProvider,
|
|
7410
|
+
mcpRegistry: this.mcpRegistry,
|
|
7411
|
+
documentSearch: async (query) => {
|
|
7412
|
+
return this.runNormalQuery(query);
|
|
7413
|
+
}
|
|
7414
|
+
});
|
|
6498
7415
|
this.agent = new LangChainAgent(this, this.config);
|
|
6499
7416
|
await this.agent.initialize(this.llmProvider);
|
|
6500
7417
|
}
|
|
7418
|
+
if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
|
|
7419
|
+
await this.loadColdContext(this.config.projectId);
|
|
7420
|
+
}
|
|
6501
7421
|
this.initialised = true;
|
|
6502
7422
|
}
|
|
7423
|
+
async loadColdContext(ns) {
|
|
7424
|
+
var _a2, _b;
|
|
7425
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7426
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7427
|
+
try {
|
|
7428
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7429
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7430
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7431
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7432
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7433
|
+
if (coldMatches.length > 0) {
|
|
7434
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7435
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7436
|
+
this.coldContexts.set(ns, formatted);
|
|
7437
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7438
|
+
} else {
|
|
7439
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7440
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7441
|
+
}
|
|
7442
|
+
} catch (err) {
|
|
7443
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7444
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7445
|
+
}
|
|
7446
|
+
}
|
|
6503
7447
|
/**
|
|
6504
7448
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6505
7449
|
*/
|
|
@@ -6531,12 +7475,12 @@ var Pipeline = class {
|
|
|
6531
7475
|
}
|
|
6532
7476
|
/** Step 1: Chunk the document content. */
|
|
6533
7477
|
async prepareChunks(doc) {
|
|
6534
|
-
var
|
|
7478
|
+
var _a2, _b;
|
|
6535
7479
|
if (this.llamaIngestor) {
|
|
6536
7480
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6537
7481
|
docId: doc.docId,
|
|
6538
7482
|
metadata: doc.metadata,
|
|
6539
|
-
chunkSize: (
|
|
7483
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6540
7484
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6541
7485
|
});
|
|
6542
7486
|
}
|
|
@@ -6607,12 +7551,37 @@ var Pipeline = class {
|
|
|
6607
7551
|
extractionOptions
|
|
6608
7552
|
);
|
|
6609
7553
|
}
|
|
7554
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7555
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7556
|
+
let reply = "";
|
|
7557
|
+
let sources = [];
|
|
7558
|
+
try {
|
|
7559
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7560
|
+
const chunk = temp.value;
|
|
7561
|
+
if (typeof chunk === "string") {
|
|
7562
|
+
reply += chunk;
|
|
7563
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7564
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7565
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7566
|
+
}
|
|
7567
|
+
}
|
|
7568
|
+
} catch (temp) {
|
|
7569
|
+
error = [temp];
|
|
7570
|
+
} finally {
|
|
7571
|
+
try {
|
|
7572
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7573
|
+
} finally {
|
|
7574
|
+
if (error)
|
|
7575
|
+
throw error[0];
|
|
7576
|
+
}
|
|
7577
|
+
}
|
|
7578
|
+
return { reply, sources };
|
|
7579
|
+
}
|
|
6610
7580
|
async ask(question, history = [], namespace) {
|
|
6611
|
-
var
|
|
7581
|
+
var _a2;
|
|
6612
7582
|
await this.initialize();
|
|
6613
|
-
if (((
|
|
6614
|
-
|
|
6615
|
-
return { reply: agentReply, sources: [] };
|
|
7583
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7584
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6616
7585
|
}
|
|
6617
7586
|
const stream = this.askStream(question, history, namespace);
|
|
6618
7587
|
let reply = "";
|
|
@@ -6644,6 +7613,47 @@ var Pipeline = class {
|
|
|
6644
7613
|
}
|
|
6645
7614
|
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
6646
7615
|
}
|
|
7616
|
+
askStream(_0) {
|
|
7617
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7618
|
+
var _a2;
|
|
7619
|
+
yield new __await(this.initialize());
|
|
7620
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7621
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7622
|
+
try {
|
|
7623
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7624
|
+
const chunk = temp.value;
|
|
7625
|
+
yield chunk;
|
|
7626
|
+
}
|
|
7627
|
+
} catch (temp) {
|
|
7628
|
+
error = [temp];
|
|
7629
|
+
} finally {
|
|
7630
|
+
try {
|
|
7631
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7632
|
+
} finally {
|
|
7633
|
+
if (error)
|
|
7634
|
+
throw error[0];
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
return;
|
|
7638
|
+
}
|
|
7639
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7640
|
+
try {
|
|
7641
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7642
|
+
const chunk = temp2.value;
|
|
7643
|
+
yield chunk;
|
|
7644
|
+
}
|
|
7645
|
+
} catch (temp2) {
|
|
7646
|
+
error2 = [temp2];
|
|
7647
|
+
} finally {
|
|
7648
|
+
try {
|
|
7649
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7650
|
+
} finally {
|
|
7651
|
+
if (error2)
|
|
7652
|
+
throw error2[0];
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
});
|
|
7656
|
+
}
|
|
6647
7657
|
/**
|
|
6648
7658
|
* High-performance streaming RAG flow.
|
|
6649
7659
|
* Yields text chunks first, then the retrieval metadata + observability trace at the end.
|
|
@@ -6654,12 +7664,12 @@ var Pipeline = class {
|
|
|
6654
7664
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6655
7665
|
* - SchemaMapper.train runs while answer generation streams
|
|
6656
7666
|
*/
|
|
6657
|
-
|
|
7667
|
+
askStreamInternal(_0) {
|
|
6658
7668
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6659
|
-
var
|
|
7669
|
+
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;
|
|
6660
7670
|
yield new __await(this.initialize());
|
|
6661
7671
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6662
|
-
const topK = (_b = (
|
|
7672
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6663
7673
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6664
7674
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6665
7675
|
const requestStart = performance.now();
|
|
@@ -6672,7 +7682,7 @@ var Pipeline = class {
|
|
|
6672
7682
|
}
|
|
6673
7683
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6674
7684
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6675
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7685
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6676
7686
|
if (numericPredicates.length > 0) {
|
|
6677
7687
|
filter.__numericPredicates = numericPredicates;
|
|
6678
7688
|
}
|
|
@@ -6738,6 +7748,32 @@ ${graphContext}
|
|
|
6738
7748
|
VECTOR CONTEXT:
|
|
6739
7749
|
${context}`;
|
|
6740
7750
|
}
|
|
7751
|
+
if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
|
|
7752
|
+
if (!this.coldContexts.has(ns)) {
|
|
7753
|
+
yield new __await(this.loadColdContext(ns));
|
|
7754
|
+
}
|
|
7755
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7756
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7757
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7758
|
+
${coldContext}
|
|
7759
|
+
|
|
7760
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7761
|
+
${context}`;
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7764
|
+
yield {
|
|
7765
|
+
reply: "",
|
|
7766
|
+
sources: sources.map((s) => {
|
|
7767
|
+
var _a3;
|
|
7768
|
+
return {
|
|
7769
|
+
id: s.id,
|
|
7770
|
+
score: s.score,
|
|
7771
|
+
content: s.content,
|
|
7772
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7773
|
+
namespace: ns
|
|
7774
|
+
};
|
|
7775
|
+
})
|
|
7776
|
+
};
|
|
6741
7777
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6742
7778
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6743
7779
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6765,10 +7801,10 @@ ${context}`;
|
|
|
6765
7801
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6766
7802
|
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
7803
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6768
|
-
const isNativeThinking = isClaude37 && (((
|
|
7804
|
+
const isNativeThinking = isClaude37 && (((_o = this.config.llm.options) == null ? void 0 : _o.thinking) === true || ((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === "enabled" || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) !== false);
|
|
6769
7805
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6770
7806
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6771
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7807
|
+
const isSimulatedThinking = !isNativeThinking && (((_r = this.config.llm.options) == null ? void 0 : _r.thinking) === true || ((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === "enabled" || isReasoningModel && ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) !== false);
|
|
6772
7808
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6773
7809
|
if (isSimulatedThinking) {
|
|
6774
7810
|
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 +7812,7 @@ ${context}`;
|
|
|
6776
7812
|
const hardenedHistory = [...history];
|
|
6777
7813
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6778
7814
|
const messages = [...hardenedHistory, userQuestion];
|
|
6779
|
-
const systemPrompt = (
|
|
7815
|
+
const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
|
|
6780
7816
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6781
7817
|
let fullReply = "";
|
|
6782
7818
|
let thinkingText = "";
|
|
@@ -6887,7 +7923,7 @@ ${context}`;
|
|
|
6887
7923
|
}
|
|
6888
7924
|
yield fullReply;
|
|
6889
7925
|
}
|
|
6890
|
-
const runHallucination = ((
|
|
7926
|
+
const runHallucination = ((_v = this.config.llm.options) == null ? void 0 : _v.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) !== false;
|
|
6891
7927
|
if (runHallucination) {
|
|
6892
7928
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6893
7929
|
}
|
|
@@ -6896,7 +7932,7 @@ ${context}`;
|
|
|
6896
7932
|
const latency = {
|
|
6897
7933
|
embedMs: Math.round(embedMs),
|
|
6898
7934
|
retrieveMs: Math.round(retrieveMs),
|
|
6899
|
-
rerankMs: ((
|
|
7935
|
+
rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6900
7936
|
generateMs: Math.round(generateMs),
|
|
6901
7937
|
totalMs: Math.round(totalMs)
|
|
6902
7938
|
};
|
|
@@ -6909,33 +7945,63 @@ ${context}`;
|
|
|
6909
7945
|
totalTokens: promptTokens + completionTokens,
|
|
6910
7946
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6911
7947
|
};
|
|
7948
|
+
const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
|
|
6912
7949
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6913
7950
|
uiTransformationPromise,
|
|
6914
|
-
hallucinationScoringPromise
|
|
7951
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6915
7952
|
]));
|
|
6916
|
-
const
|
|
7953
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6917
7954
|
requestId,
|
|
6918
7955
|
query: question,
|
|
6919
7956
|
rewrittenQuery,
|
|
6920
7957
|
systemPrompt,
|
|
6921
7958
|
userPrompt: question + finalRestrictionSuffix,
|
|
6922
7959
|
chunks: sources.map((s) => {
|
|
6923
|
-
var
|
|
7960
|
+
var _a3;
|
|
6924
7961
|
return {
|
|
6925
7962
|
id: s.id,
|
|
6926
7963
|
score: s.score,
|
|
6927
7964
|
content: s.content,
|
|
6928
|
-
metadata: (
|
|
7965
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6929
7966
|
namespace: ns
|
|
6930
7967
|
};
|
|
6931
7968
|
}),
|
|
6932
7969
|
latency,
|
|
6933
7970
|
tokens,
|
|
6934
7971
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6935
|
-
},
|
|
6936
|
-
hallucinationScore:
|
|
6937
|
-
hallucinationReason:
|
|
7972
|
+
}, hScore ? {
|
|
7973
|
+
hallucinationScore: hScore.score,
|
|
7974
|
+
hallucinationReason: hScore.reason
|
|
6938
7975
|
} : {});
|
|
7976
|
+
const trace = buildTrace(hallucinationResult);
|
|
7977
|
+
if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
|
|
7978
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7979
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7980
|
+
(async () => {
|
|
7981
|
+
try {
|
|
7982
|
+
let finalTrace = trace;
|
|
7983
|
+
if (!awaitHallucination && runHallucination) {
|
|
7984
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7985
|
+
if (backgroundScoreResult) {
|
|
7986
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7989
|
+
await fetch(absoluteUrl, {
|
|
7990
|
+
method: "POST",
|
|
7991
|
+
headers: {
|
|
7992
|
+
"Content-Type": "application/json"
|
|
7993
|
+
},
|
|
7994
|
+
body: JSON.stringify({
|
|
7995
|
+
trace: finalTrace,
|
|
7996
|
+
licenseKey: this.config.licenseKey,
|
|
7997
|
+
projectId: ns
|
|
7998
|
+
})
|
|
7999
|
+
});
|
|
8000
|
+
} catch (err) {
|
|
8001
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
8002
|
+
}
|
|
8003
|
+
})();
|
|
8004
|
+
}
|
|
6939
8005
|
yield {
|
|
6940
8006
|
reply: "",
|
|
6941
8007
|
sources,
|
|
@@ -6955,7 +8021,7 @@ ${context}`;
|
|
|
6955
8021
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6956
8022
|
*/
|
|
6957
8023
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6958
|
-
var
|
|
8024
|
+
var _a2;
|
|
6959
8025
|
if (!sources || sources.length === 0) {
|
|
6960
8026
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6961
8027
|
}
|
|
@@ -6969,7 +8035,7 @@ ${context}`;
|
|
|
6969
8035
|
);
|
|
6970
8036
|
}
|
|
6971
8037
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6972
|
-
const disableLlmUiTransform = ((
|
|
8038
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6973
8039
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6974
8040
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6975
8041
|
}
|
|
@@ -6987,9 +8053,9 @@ ${context}`;
|
|
|
6987
8053
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6988
8054
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6989
8055
|
})).sort((a, b) => {
|
|
6990
|
-
var
|
|
8056
|
+
var _a2, _b;
|
|
6991
8057
|
const primary = predicates[0];
|
|
6992
|
-
const aValue = (
|
|
8058
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6993
8059
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6994
8060
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6995
8061
|
});
|
|
@@ -7061,8 +8127,8 @@ ${context}`;
|
|
|
7061
8127
|
return Number.isFinite(numeric) ? numeric : null;
|
|
7062
8128
|
}
|
|
7063
8129
|
async retrieve(query, options) {
|
|
7064
|
-
var
|
|
7065
|
-
const ns = (
|
|
8130
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
8131
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
7066
8132
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
7067
8133
|
const cacheKey = `${ns}::${query}`;
|
|
7068
8134
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -7094,7 +8160,7 @@ ${context}`;
|
|
|
7094
8160
|
) : [];
|
|
7095
8161
|
const resolvedSources = [];
|
|
7096
8162
|
for (const source of sources) {
|
|
7097
|
-
const parentId = (
|
|
8163
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
7098
8164
|
if (parentId) {
|
|
7099
8165
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
7100
8166
|
resolvedSources.push(source);
|
|
@@ -7176,8 +8242,14 @@ var Retrivora = class {
|
|
|
7176
8242
|
this.pipeline = new Pipeline(this.config);
|
|
7177
8243
|
}
|
|
7178
8244
|
async initialize() {
|
|
8245
|
+
var _a2;
|
|
7179
8246
|
try {
|
|
7180
8247
|
await ConfigValidator.validateAndThrow(this.config);
|
|
8248
|
+
LicenseVerifier.verify(
|
|
8249
|
+
this.config.licenseKey,
|
|
8250
|
+
this.config.projectId,
|
|
8251
|
+
(_a2 = this.config.vectorDb) == null ? void 0 : _a2.provider
|
|
8252
|
+
);
|
|
7181
8253
|
} catch (err) {
|
|
7182
8254
|
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
7183
8255
|
}
|
|
@@ -7351,11 +8423,20 @@ var ProviderHealthCheck = class {
|
|
|
7351
8423
|
// src/core/VectorPlugin.ts
|
|
7352
8424
|
var VectorPlugin = class {
|
|
7353
8425
|
constructor(hostConfig) {
|
|
7354
|
-
|
|
7355
|
-
this.
|
|
8426
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8427
|
+
this.config = resolvedConfig;
|
|
8428
|
+
this.validationPromise = (async () => {
|
|
8429
|
+
var _a2;
|
|
8430
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8431
|
+
LicenseVerifier.verify(
|
|
8432
|
+
resolvedConfig.licenseKey,
|
|
8433
|
+
resolvedConfig.projectId,
|
|
8434
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8435
|
+
);
|
|
8436
|
+
})();
|
|
7356
8437
|
this.validationPromise.catch(() => {
|
|
7357
8438
|
});
|
|
7358
|
-
this.pipeline = new Pipeline(
|
|
8439
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7359
8440
|
}
|
|
7360
8441
|
/**
|
|
7361
8442
|
* Get the current resolved configuration.
|
|
@@ -7491,13 +8572,13 @@ var ConfigBuilder = class {
|
|
|
7491
8572
|
* Configure the vector database provider
|
|
7492
8573
|
*/
|
|
7493
8574
|
vectorDb(provider, options) {
|
|
7494
|
-
var
|
|
8575
|
+
var _a2;
|
|
7495
8576
|
if (provider === "auto") {
|
|
7496
8577
|
this._vectorDb = this._autoDetectVectorDb();
|
|
7497
8578
|
} else {
|
|
7498
8579
|
this._vectorDb = {
|
|
7499
8580
|
provider,
|
|
7500
|
-
indexName: (
|
|
8581
|
+
indexName: (_a2 = options == null ? void 0 : options.indexName) != null ? _a2 : "default",
|
|
7501
8582
|
options: __spreadValues({}, options)
|
|
7502
8583
|
};
|
|
7503
8584
|
}
|
|
@@ -7507,7 +8588,7 @@ var ConfigBuilder = class {
|
|
|
7507
8588
|
* Configure the LLM provider for chat
|
|
7508
8589
|
*/
|
|
7509
8590
|
llm(provider, model, apiKey, options) {
|
|
7510
|
-
var
|
|
8591
|
+
var _a2, _b;
|
|
7511
8592
|
if (provider === "auto") {
|
|
7512
8593
|
this._llm = this._autoDetectLLM();
|
|
7513
8594
|
} else {
|
|
@@ -7516,7 +8597,7 @@ var ConfigBuilder = class {
|
|
|
7516
8597
|
model: model != null ? model : "default-model",
|
|
7517
8598
|
apiKey,
|
|
7518
8599
|
systemPrompt: options == null ? void 0 : options.systemPrompt,
|
|
7519
|
-
maxTokens: (
|
|
8600
|
+
maxTokens: (_a2 = options == null ? void 0 : options.maxTokens) != null ? _a2 : 1024,
|
|
7520
8601
|
temperature: (_b = options == null ? void 0 : options.temperature) != null ? _b : 0.7,
|
|
7521
8602
|
baseUrl: options == null ? void 0 : options.baseUrl,
|
|
7522
8603
|
options
|
|
@@ -7559,8 +8640,8 @@ var ConfigBuilder = class {
|
|
|
7559
8640
|
* Set RAG-specific pipeline parameters
|
|
7560
8641
|
*/
|
|
7561
8642
|
rag(options) {
|
|
7562
|
-
var
|
|
7563
|
-
this._rag = __spreadValues(__spreadValues({}, (
|
|
8643
|
+
var _a2;
|
|
8644
|
+
this._rag = __spreadValues(__spreadValues({}, (_a2 = this._rag) != null ? _a2 : {}), options);
|
|
7564
8645
|
return this;
|
|
7565
8646
|
}
|
|
7566
8647
|
/**
|
|
@@ -7576,7 +8657,7 @@ var ConfigBuilder = class {
|
|
|
7576
8657
|
* Throws if required fields (projectId, vectorDb, llm, embedding) are not set.
|
|
7577
8658
|
*/
|
|
7578
8659
|
build() {
|
|
7579
|
-
var
|
|
8660
|
+
var _a2;
|
|
7580
8661
|
const missing = [];
|
|
7581
8662
|
if (!this._projectId) missing.push('projectId (call .projectId("my-app"))');
|
|
7582
8663
|
if (!this._vectorDb) missing.push('vectorDb (call .vectorDb("pinecone", { ... }))');
|
|
@@ -7588,7 +8669,7 @@ var ConfigBuilder = class {
|
|
|
7588
8669
|
${missing.join("\n ")}`
|
|
7589
8670
|
);
|
|
7590
8671
|
}
|
|
7591
|
-
const ragConfig = (
|
|
8672
|
+
const ragConfig = (_a2 = this._rag) != null ? _a2 : { chunkSize: 1e3, chunkOverlap: 200, topK: 5 };
|
|
7592
8673
|
if (process.env.RAG_USE_GRAPH_RETRIEVAL === "true") {
|
|
7593
8674
|
ragConfig.useGraphRetrieval = true;
|
|
7594
8675
|
}
|
|
@@ -7684,8 +8765,8 @@ var DocumentParser = class {
|
|
|
7684
8765
|
* Extract text from a File or Buffer based on its type.
|
|
7685
8766
|
*/
|
|
7686
8767
|
static async parse(file, fileName, mimeType) {
|
|
7687
|
-
var
|
|
7688
|
-
const extension = (
|
|
8768
|
+
var _a2;
|
|
8769
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7689
8770
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7690
8771
|
return this.readAsText(file);
|
|
7691
8772
|
}
|
|
@@ -7752,6 +8833,497 @@ init_UniversalVectorProvider();
|
|
|
7752
8833
|
|
|
7753
8834
|
// src/handlers/index.ts
|
|
7754
8835
|
var import_server = require("next/server");
|
|
8836
|
+
|
|
8837
|
+
// src/core/DatabaseStorage.ts
|
|
8838
|
+
var fs = __toESM(require("fs"));
|
|
8839
|
+
var path = __toESM(require("path"));
|
|
8840
|
+
var DatabaseStorage = class {
|
|
8841
|
+
constructor(config) {
|
|
8842
|
+
// Dynamic PG Pool
|
|
8843
|
+
this.pgPool = null;
|
|
8844
|
+
// Dynamic MongoDB Client
|
|
8845
|
+
this.mongoClient = null;
|
|
8846
|
+
this.mongoDbName = "";
|
|
8847
|
+
// Filesystem fallback configuration
|
|
8848
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8849
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8850
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8851
|
+
var _a2, _b, _c, _d, _e;
|
|
8852
|
+
this.config = config;
|
|
8853
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8854
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8855
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8856
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8857
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8858
|
+
}
|
|
8859
|
+
/**
|
|
8860
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8861
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8862
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8863
|
+
*/
|
|
8864
|
+
checkPremiumSubscription() {
|
|
8865
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8866
|
+
return;
|
|
8867
|
+
}
|
|
8868
|
+
if (!this.config.licenseKey) {
|
|
8869
|
+
throw new Error(
|
|
8870
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8871
|
+
);
|
|
8872
|
+
}
|
|
8873
|
+
try {
|
|
8874
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8875
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8876
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8877
|
+
throw new Error(
|
|
8878
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8879
|
+
);
|
|
8880
|
+
}
|
|
8881
|
+
} catch (err) {
|
|
8882
|
+
throw new Error(
|
|
8883
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8884
|
+
);
|
|
8885
|
+
}
|
|
8886
|
+
}
|
|
8887
|
+
checkHistoryEnabled() {
|
|
8888
|
+
var _a2, _b;
|
|
8889
|
+
this.checkPremiumSubscription();
|
|
8890
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8891
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8892
|
+
}
|
|
8893
|
+
}
|
|
8894
|
+
checkFeedbackEnabled() {
|
|
8895
|
+
var _a2, _b;
|
|
8896
|
+
this.checkPremiumSubscription();
|
|
8897
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8898
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8899
|
+
}
|
|
8900
|
+
}
|
|
8901
|
+
async getPGPool() {
|
|
8902
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8903
|
+
const _g2 = global;
|
|
8904
|
+
if (_g2[globalKey]) {
|
|
8905
|
+
this.pgPool = _g2[globalKey];
|
|
8906
|
+
return this.pgPool;
|
|
8907
|
+
}
|
|
8908
|
+
const opts = this.config.vectorDb.options;
|
|
8909
|
+
if (!opts.connectionString) {
|
|
8910
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8911
|
+
}
|
|
8912
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8913
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8914
|
+
_g2[globalKey] = this.pgPool;
|
|
8915
|
+
const client = await this.pgPool.connect();
|
|
8916
|
+
try {
|
|
8917
|
+
await client.query(`
|
|
8918
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8919
|
+
id TEXT PRIMARY KEY,
|
|
8920
|
+
session_id TEXT NOT NULL,
|
|
8921
|
+
role TEXT NOT NULL,
|
|
8922
|
+
content TEXT NOT NULL,
|
|
8923
|
+
sources JSONB,
|
|
8924
|
+
ui_transformation JSONB,
|
|
8925
|
+
trace JSONB,
|
|
8926
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8927
|
+
)
|
|
8928
|
+
`);
|
|
8929
|
+
await client.query(`
|
|
8930
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8931
|
+
id TEXT PRIMARY KEY,
|
|
8932
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8933
|
+
session_id TEXT NOT NULL,
|
|
8934
|
+
rating TEXT NOT NULL,
|
|
8935
|
+
comment TEXT,
|
|
8936
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8937
|
+
)
|
|
8938
|
+
`);
|
|
8939
|
+
} finally {
|
|
8940
|
+
client.release();
|
|
8941
|
+
}
|
|
8942
|
+
return this.pgPool;
|
|
8943
|
+
}
|
|
8944
|
+
async getMongoClient() {
|
|
8945
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8946
|
+
const _g2 = global;
|
|
8947
|
+
if (_g2[globalKey]) {
|
|
8948
|
+
this.mongoClient = _g2[globalKey];
|
|
8949
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8950
|
+
return this.mongoClient;
|
|
8951
|
+
}
|
|
8952
|
+
const opts = this.config.vectorDb.options;
|
|
8953
|
+
if (!opts.uri || !opts.database) {
|
|
8954
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8955
|
+
}
|
|
8956
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8957
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8958
|
+
await this.mongoClient.connect();
|
|
8959
|
+
_g2[globalKey] = this.mongoClient;
|
|
8960
|
+
this.mongoDbName = opts.database;
|
|
8961
|
+
return this.mongoClient;
|
|
8962
|
+
}
|
|
8963
|
+
getMongoDb() {
|
|
8964
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8965
|
+
}
|
|
8966
|
+
// Helper for FS fallback reads
|
|
8967
|
+
readLocalFile(filePath) {
|
|
8968
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8969
|
+
try {
|
|
8970
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8971
|
+
return JSON.parse(raw) || [];
|
|
8972
|
+
} catch (e) {
|
|
8973
|
+
return [];
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
8976
|
+
// Helper for FS fallback writes
|
|
8977
|
+
writeLocalFile(filePath, data) {
|
|
8978
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8979
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8980
|
+
}
|
|
8981
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8982
|
+
}
|
|
8983
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8984
|
+
async saveMessage(sessionId, message) {
|
|
8985
|
+
this.checkHistoryEnabled();
|
|
8986
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8987
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8988
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8989
|
+
const pool = await this.getPGPool();
|
|
8990
|
+
await pool.query(
|
|
8991
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8992
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8993
|
+
ON CONFLICT (id) DO UPDATE
|
|
8994
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8995
|
+
[
|
|
8996
|
+
msgId,
|
|
8997
|
+
sessionId,
|
|
8998
|
+
message.role,
|
|
8999
|
+
message.content,
|
|
9000
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
9001
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
9002
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
9003
|
+
createdAt
|
|
9004
|
+
]
|
|
9005
|
+
);
|
|
9006
|
+
} else if (this.provider === "mongodb") {
|
|
9007
|
+
await this.getMongoClient();
|
|
9008
|
+
const db = this.getMongoDb();
|
|
9009
|
+
const col = db.collection(this.historyTableName);
|
|
9010
|
+
await col.updateOne(
|
|
9011
|
+
{ id: msgId },
|
|
9012
|
+
{
|
|
9013
|
+
$set: {
|
|
9014
|
+
id: msgId,
|
|
9015
|
+
session_id: sessionId,
|
|
9016
|
+
role: message.role,
|
|
9017
|
+
content: message.content,
|
|
9018
|
+
sources: message.sources || null,
|
|
9019
|
+
ui_transformation: message.uiTransformation || null,
|
|
9020
|
+
trace: message.trace || null,
|
|
9021
|
+
created_at: createdAt
|
|
9022
|
+
}
|
|
9023
|
+
},
|
|
9024
|
+
{ upsert: true }
|
|
9025
|
+
);
|
|
9026
|
+
} else {
|
|
9027
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9028
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
9029
|
+
const item = {
|
|
9030
|
+
id: msgId,
|
|
9031
|
+
session_id: sessionId,
|
|
9032
|
+
role: message.role,
|
|
9033
|
+
content: message.content,
|
|
9034
|
+
sources: message.sources || null,
|
|
9035
|
+
ui_transformation: message.uiTransformation || null,
|
|
9036
|
+
trace: message.trace || null,
|
|
9037
|
+
created_at: createdAt
|
|
9038
|
+
};
|
|
9039
|
+
if (index !== -1) {
|
|
9040
|
+
history[index] = item;
|
|
9041
|
+
} else {
|
|
9042
|
+
history.push(item);
|
|
9043
|
+
}
|
|
9044
|
+
this.writeLocalFile(this.historyFile, history);
|
|
9045
|
+
}
|
|
9046
|
+
}
|
|
9047
|
+
async getHistory(sessionId) {
|
|
9048
|
+
this.checkHistoryEnabled();
|
|
9049
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9050
|
+
const pool = await this.getPGPool();
|
|
9051
|
+
const res = await pool.query(
|
|
9052
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
9053
|
+
FROM ${this.historyTableName}
|
|
9054
|
+
WHERE session_id = $1
|
|
9055
|
+
ORDER BY created_at ASC`,
|
|
9056
|
+
[sessionId]
|
|
9057
|
+
);
|
|
9058
|
+
return res.rows;
|
|
9059
|
+
} else if (this.provider === "mongodb") {
|
|
9060
|
+
await this.getMongoClient();
|
|
9061
|
+
const db = this.getMongoDb();
|
|
9062
|
+
const col = db.collection(this.historyTableName);
|
|
9063
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
9064
|
+
return items.map((item) => ({
|
|
9065
|
+
id: item.id,
|
|
9066
|
+
role: item.role,
|
|
9067
|
+
content: item.content,
|
|
9068
|
+
sources: item.sources,
|
|
9069
|
+
uiTransformation: item.ui_transformation,
|
|
9070
|
+
trace: item.trace,
|
|
9071
|
+
createdAt: item.created_at
|
|
9072
|
+
}));
|
|
9073
|
+
} else {
|
|
9074
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9075
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
9076
|
+
}
|
|
9077
|
+
}
|
|
9078
|
+
async clearHistory(sessionId) {
|
|
9079
|
+
this.checkHistoryEnabled();
|
|
9080
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9081
|
+
const pool = await this.getPGPool();
|
|
9082
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
9083
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
9084
|
+
} else if (this.provider === "mongodb") {
|
|
9085
|
+
await this.getMongoClient();
|
|
9086
|
+
const db = this.getMongoDb();
|
|
9087
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
9088
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
9089
|
+
} else {
|
|
9090
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9091
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
9092
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
9093
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
9094
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
9095
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
9096
|
+
}
|
|
9097
|
+
}
|
|
9098
|
+
async listSessions() {
|
|
9099
|
+
this.checkHistoryEnabled();
|
|
9100
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9101
|
+
const pool = await this.getPGPool();
|
|
9102
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
9103
|
+
return res.rows.map((r) => r.session_id);
|
|
9104
|
+
} else if (this.provider === "mongodb") {
|
|
9105
|
+
await this.getMongoClient();
|
|
9106
|
+
const db = this.getMongoDb();
|
|
9107
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
9108
|
+
} else {
|
|
9109
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9110
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
9111
|
+
return Array.from(sessions);
|
|
9112
|
+
}
|
|
9113
|
+
}
|
|
9114
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
9115
|
+
async saveFeedback(feedback) {
|
|
9116
|
+
this.checkFeedbackEnabled();
|
|
9117
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9118
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9119
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9120
|
+
const pool = await this.getPGPool();
|
|
9121
|
+
await pool.query(
|
|
9122
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
9123
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
9124
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
9125
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
9126
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
9127
|
+
);
|
|
9128
|
+
} else if (this.provider === "mongodb") {
|
|
9129
|
+
await this.getMongoClient();
|
|
9130
|
+
const db = this.getMongoDb();
|
|
9131
|
+
const col = db.collection(this.feedbackTableName);
|
|
9132
|
+
await col.updateOne(
|
|
9133
|
+
{ message_id: feedback.messageId },
|
|
9134
|
+
{
|
|
9135
|
+
$set: {
|
|
9136
|
+
id,
|
|
9137
|
+
message_id: feedback.messageId,
|
|
9138
|
+
session_id: feedback.sessionId,
|
|
9139
|
+
rating: feedback.rating,
|
|
9140
|
+
comment: feedback.comment || null,
|
|
9141
|
+
created_at: createdAt
|
|
9142
|
+
}
|
|
9143
|
+
},
|
|
9144
|
+
{ upsert: true }
|
|
9145
|
+
);
|
|
9146
|
+
} else {
|
|
9147
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9148
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
9149
|
+
const item = {
|
|
9150
|
+
id,
|
|
9151
|
+
message_id: feedback.messageId,
|
|
9152
|
+
session_id: feedback.sessionId,
|
|
9153
|
+
rating: feedback.rating,
|
|
9154
|
+
comment: feedback.comment || null,
|
|
9155
|
+
created_at: createdAt
|
|
9156
|
+
};
|
|
9157
|
+
if (index !== -1) {
|
|
9158
|
+
list[index] = item;
|
|
9159
|
+
} else {
|
|
9160
|
+
list.push(item);
|
|
9161
|
+
}
|
|
9162
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
9163
|
+
}
|
|
9164
|
+
}
|
|
9165
|
+
async getFeedback(messageId) {
|
|
9166
|
+
this.checkFeedbackEnabled();
|
|
9167
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9168
|
+
const pool = await this.getPGPool();
|
|
9169
|
+
const res = await pool.query(
|
|
9170
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9171
|
+
FROM ${this.feedbackTableName}
|
|
9172
|
+
WHERE message_id = $1`,
|
|
9173
|
+
[messageId]
|
|
9174
|
+
);
|
|
9175
|
+
return res.rows[0] || null;
|
|
9176
|
+
} else if (this.provider === "mongodb") {
|
|
9177
|
+
await this.getMongoClient();
|
|
9178
|
+
const db = this.getMongoDb();
|
|
9179
|
+
const col = db.collection(this.feedbackTableName);
|
|
9180
|
+
const item = await col.findOne({ message_id: messageId });
|
|
9181
|
+
if (!item) return null;
|
|
9182
|
+
return {
|
|
9183
|
+
id: item.id,
|
|
9184
|
+
messageId: item.message_id,
|
|
9185
|
+
sessionId: item.session_id,
|
|
9186
|
+
rating: item.rating,
|
|
9187
|
+
comment: item.comment,
|
|
9188
|
+
createdAt: item.created_at
|
|
9189
|
+
};
|
|
9190
|
+
} else {
|
|
9191
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9192
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
9195
|
+
async listFeedback() {
|
|
9196
|
+
this.checkFeedbackEnabled();
|
|
9197
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9198
|
+
const pool = await this.getPGPool();
|
|
9199
|
+
const res = await pool.query(
|
|
9200
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9201
|
+
FROM ${this.feedbackTableName}
|
|
9202
|
+
ORDER BY created_at DESC`
|
|
9203
|
+
);
|
|
9204
|
+
return res.rows;
|
|
9205
|
+
} else if (this.provider === "mongodb") {
|
|
9206
|
+
await this.getMongoClient();
|
|
9207
|
+
const db = this.getMongoDb();
|
|
9208
|
+
const col = db.collection(this.feedbackTableName);
|
|
9209
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
9210
|
+
return items.map((item) => ({
|
|
9211
|
+
id: item.id,
|
|
9212
|
+
messageId: item.message_id,
|
|
9213
|
+
sessionId: item.session_id,
|
|
9214
|
+
rating: item.rating,
|
|
9215
|
+
comment: item.comment,
|
|
9216
|
+
createdAt: item.created_at
|
|
9217
|
+
}));
|
|
9218
|
+
} else {
|
|
9219
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9220
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
9221
|
+
}
|
|
9222
|
+
}
|
|
9223
|
+
async disconnect() {
|
|
9224
|
+
if (this.pgPool) {
|
|
9225
|
+
await this.pgPool.end();
|
|
9226
|
+
this.pgPool = null;
|
|
9227
|
+
}
|
|
9228
|
+
if (this.mongoClient) {
|
|
9229
|
+
await this.mongoClient.close();
|
|
9230
|
+
this.mongoClient = null;
|
|
9231
|
+
}
|
|
9232
|
+
}
|
|
9233
|
+
};
|
|
9234
|
+
|
|
9235
|
+
// src/handlers/index.ts
|
|
9236
|
+
async function checkAuth(req, onAuthorize) {
|
|
9237
|
+
if (!onAuthorize) return null;
|
|
9238
|
+
try {
|
|
9239
|
+
const res = await onAuthorize(req);
|
|
9240
|
+
if (res === false) {
|
|
9241
|
+
return import_server.NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
9242
|
+
}
|
|
9243
|
+
if (res instanceof Response) {
|
|
9244
|
+
return res;
|
|
9245
|
+
}
|
|
9246
|
+
return null;
|
|
9247
|
+
} catch (err) {
|
|
9248
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
9249
|
+
return import_server.NextResponse.json({ error: msg }, { status: 401 });
|
|
9250
|
+
}
|
|
9251
|
+
}
|
|
9252
|
+
var RateLimiter = class {
|
|
9253
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
9254
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
9255
|
+
this.windowMs = windowMs;
|
|
9256
|
+
this.max = max;
|
|
9257
|
+
}
|
|
9258
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
9259
|
+
allow(key) {
|
|
9260
|
+
const now = Date.now();
|
|
9261
|
+
const cutoff = now - this.windowMs;
|
|
9262
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9263
|
+
existing.push(now);
|
|
9264
|
+
this.hits.set(key, existing);
|
|
9265
|
+
if (this.hits.size > 5e3) {
|
|
9266
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
9267
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
9268
|
+
}
|
|
9269
|
+
}
|
|
9270
|
+
return existing.length <= this.max;
|
|
9271
|
+
}
|
|
9272
|
+
retryAfterSec(key) {
|
|
9273
|
+
const now = Date.now();
|
|
9274
|
+
const cutoff = now - this.windowMs;
|
|
9275
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9276
|
+
if (existing.length === 0) return 0;
|
|
9277
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
9278
|
+
}
|
|
9279
|
+
};
|
|
9280
|
+
var _g = global;
|
|
9281
|
+
var _a;
|
|
9282
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
9283
|
+
function getRateLimitKey(req) {
|
|
9284
|
+
var _a2, _b;
|
|
9285
|
+
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";
|
|
9286
|
+
return `ip:${ip}`;
|
|
9287
|
+
}
|
|
9288
|
+
function checkRateLimit(req) {
|
|
9289
|
+
const key = getRateLimitKey(req);
|
|
9290
|
+
if (!rateLimiter.allow(key)) {
|
|
9291
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
9292
|
+
return new Response(
|
|
9293
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
9294
|
+
{
|
|
9295
|
+
status: 429,
|
|
9296
|
+
headers: {
|
|
9297
|
+
"Content-Type": "application/json",
|
|
9298
|
+
"Retry-After": String(retryAfter),
|
|
9299
|
+
"X-RateLimit-Limit": "30",
|
|
9300
|
+
"X-RateLimit-Window": "60"
|
|
9301
|
+
}
|
|
9302
|
+
}
|
|
9303
|
+
);
|
|
9304
|
+
}
|
|
9305
|
+
return null;
|
|
9306
|
+
}
|
|
9307
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
9308
|
+
function sanitizeInput(raw) {
|
|
9309
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
9310
|
+
const trimmed = stripped.trim();
|
|
9311
|
+
if (!trimmed) {
|
|
9312
|
+
return { ok: false, error: "message must not be empty" };
|
|
9313
|
+
}
|
|
9314
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
9315
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
9316
|
+
}
|
|
9317
|
+
return { ok: true, value: trimmed };
|
|
9318
|
+
}
|
|
9319
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
9320
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
9321
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
9322
|
+
if (!_g[cacheKey]) {
|
|
9323
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
9324
|
+
}
|
|
9325
|
+
return _g[cacheKey];
|
|
9326
|
+
}
|
|
7755
9327
|
function sseFrame(payload) {
|
|
7756
9328
|
return `data: ${JSON.stringify(payload)}
|
|
7757
9329
|
|
|
@@ -7789,47 +9361,88 @@ var SSE_HEADERS = {
|
|
|
7789
9361
|
"X-Accel-Buffering": "no"
|
|
7790
9362
|
// Disable Nginx buffering for streaming
|
|
7791
9363
|
};
|
|
7792
|
-
function createChatHandler(configOrPlugin) {
|
|
7793
|
-
const plugin =
|
|
9364
|
+
function createChatHandler(configOrPlugin, options) {
|
|
9365
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9366
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9367
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7794
9368
|
return async function POST(req) {
|
|
9369
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9370
|
+
if (authResult) return authResult;
|
|
9371
|
+
const rateLimited = checkRateLimit(req);
|
|
9372
|
+
if (rateLimited) return rateLimited;
|
|
7795
9373
|
try {
|
|
7796
9374
|
const body = await req.json();
|
|
7797
|
-
const { message, history = [], namespace } = body;
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
9375
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9376
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9377
|
+
if (!sanitized.ok) {
|
|
9378
|
+
return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
9379
|
+
}
|
|
9380
|
+
const message = sanitized.value;
|
|
9381
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9382
|
+
await storage.saveMessage(sessionId, {
|
|
9383
|
+
id: userMsgId,
|
|
9384
|
+
role: "user",
|
|
9385
|
+
content: message
|
|
9386
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7801
9387
|
const result = await plugin.chat(message, history, namespace);
|
|
7802
|
-
|
|
9388
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9389
|
+
await storage.saveMessage(sessionId, {
|
|
9390
|
+
id: assistantMsgId,
|
|
9391
|
+
role: "assistant",
|
|
9392
|
+
content: result.reply,
|
|
9393
|
+
sources: result.sources,
|
|
9394
|
+
uiTransformation: result.ui_transformation,
|
|
9395
|
+
trace: result.trace
|
|
9396
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9397
|
+
return import_server.NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9398
|
+
messageId: assistantMsgId,
|
|
9399
|
+
userMessageId: userMsgId
|
|
9400
|
+
}));
|
|
7803
9401
|
} catch (err) {
|
|
7804
9402
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7805
9403
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
7806
9404
|
}
|
|
7807
9405
|
};
|
|
7808
9406
|
}
|
|
7809
|
-
function createStreamHandler(configOrPlugin) {
|
|
7810
|
-
const plugin =
|
|
9407
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9408
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9409
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9410
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7811
9411
|
return async function POST(req) {
|
|
9412
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9413
|
+
if (authResult) return authResult;
|
|
9414
|
+
const rateLimited = checkRateLimit(req);
|
|
9415
|
+
if (rateLimited) return rateLimited;
|
|
7812
9416
|
let body;
|
|
7813
9417
|
try {
|
|
7814
9418
|
body = await req.json();
|
|
7815
9419
|
} catch (e) {
|
|
7816
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9420
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7817
9421
|
status: 400,
|
|
7818
9422
|
headers: { "Content-Type": "application/json" }
|
|
7819
9423
|
});
|
|
7820
9424
|
}
|
|
7821
|
-
const { message, history = [], namespace } = body;
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
9425
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9426
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9427
|
+
if (!sanitized.ok) {
|
|
9428
|
+
return new Response(
|
|
9429
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9430
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9431
|
+
);
|
|
7827
9432
|
}
|
|
9433
|
+
const message = sanitized.value;
|
|
9434
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9435
|
+
await storage.saveMessage(sessionId, {
|
|
9436
|
+
id: userMsgId,
|
|
9437
|
+
role: "user",
|
|
9438
|
+
content: message
|
|
9439
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9440
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7828
9441
|
const encoder = new TextEncoder();
|
|
7829
9442
|
let isActive = true;
|
|
7830
9443
|
const stream = new ReadableStream({
|
|
7831
9444
|
async start(controller) {
|
|
7832
|
-
var
|
|
9445
|
+
var _a2;
|
|
7833
9446
|
const enqueue = (text) => {
|
|
7834
9447
|
if (!isActive) return;
|
|
7835
9448
|
try {
|
|
@@ -7840,11 +9453,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7840
9453
|
};
|
|
7841
9454
|
try {
|
|
7842
9455
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9456
|
+
let fullReply = "";
|
|
7843
9457
|
try {
|
|
7844
9458
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7845
9459
|
const chunk = temp.value;
|
|
7846
9460
|
if (!isActive) break;
|
|
7847
9461
|
if (typeof chunk === "string") {
|
|
9462
|
+
fullReply += chunk;
|
|
7848
9463
|
enqueue(sseTextFrame(chunk));
|
|
7849
9464
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7850
9465
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7857,9 +9472,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7857
9472
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7858
9473
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7859
9474
|
}
|
|
9475
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7860
9476
|
if (sources.length > 0) {
|
|
7861
9477
|
try {
|
|
7862
|
-
|
|
9478
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7863
9479
|
if (uiTransformation) {
|
|
7864
9480
|
enqueue(sseUIFrame(uiTransformation));
|
|
7865
9481
|
}
|
|
@@ -7867,11 +9483,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7867
9483
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7868
9484
|
try {
|
|
7869
9485
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7870
|
-
if (fallback)
|
|
9486
|
+
if (fallback) {
|
|
9487
|
+
uiTransformation = fallback;
|
|
9488
|
+
enqueue(sseUIFrame(fallback));
|
|
9489
|
+
}
|
|
7871
9490
|
} catch (e) {
|
|
7872
9491
|
}
|
|
7873
9492
|
}
|
|
7874
9493
|
}
|
|
9494
|
+
await storage.saveMessage(sessionId, {
|
|
9495
|
+
id: assistantMsgId,
|
|
9496
|
+
role: "assistant",
|
|
9497
|
+
content: fullReply,
|
|
9498
|
+
sources,
|
|
9499
|
+
uiTransformation,
|
|
9500
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9501
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7875
9502
|
}
|
|
7876
9503
|
}
|
|
7877
9504
|
} catch (temp) {
|
|
@@ -7908,12 +9535,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7908
9535
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7909
9536
|
}
|
|
7910
9537
|
});
|
|
7911
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9538
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7912
9539
|
};
|
|
7913
9540
|
}
|
|
7914
|
-
function createIngestHandler(configOrPlugin) {
|
|
7915
|
-
const plugin =
|
|
9541
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9542
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9543
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7916
9544
|
return async function POST(req) {
|
|
9545
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9546
|
+
if (authResult) return authResult;
|
|
7917
9547
|
try {
|
|
7918
9548
|
const body = await req.json();
|
|
7919
9549
|
const { documents, namespace } = body;
|
|
@@ -7928,9 +9558,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7928
9558
|
}
|
|
7929
9559
|
};
|
|
7930
9560
|
}
|
|
7931
|
-
function createHealthHandler(configOrPlugin) {
|
|
7932
|
-
const plugin =
|
|
7933
|
-
|
|
9561
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9562
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9563
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9564
|
+
return async function GET(req) {
|
|
9565
|
+
if (req) {
|
|
9566
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9567
|
+
if (authResult) return authResult;
|
|
9568
|
+
}
|
|
7934
9569
|
try {
|
|
7935
9570
|
const health = await plugin.checkHealth();
|
|
7936
9571
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7945,9 +9580,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7945
9580
|
}
|
|
7946
9581
|
};
|
|
7947
9582
|
}
|
|
7948
|
-
function createUploadHandler(configOrPlugin) {
|
|
7949
|
-
const plugin =
|
|
9583
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9584
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9585
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7950
9586
|
return async function POST(req) {
|
|
9587
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9588
|
+
if (authResult) return authResult;
|
|
7951
9589
|
try {
|
|
7952
9590
|
const formData = await req.formData();
|
|
7953
9591
|
const files = formData.getAll("files");
|
|
@@ -8021,9 +9659,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
8021
9659
|
}
|
|
8022
9660
|
};
|
|
8023
9661
|
}
|
|
8024
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
8025
|
-
const plugin =
|
|
9662
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9663
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9664
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
8026
9665
|
return async function POST(req) {
|
|
9666
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9667
|
+
if (authResult) return authResult;
|
|
8027
9668
|
try {
|
|
8028
9669
|
const body = await req.json();
|
|
8029
9670
|
const { query, namespace } = body;
|
|
@@ -8038,13 +9679,108 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
8038
9679
|
}
|
|
8039
9680
|
};
|
|
8040
9681
|
}
|
|
8041
|
-
function
|
|
8042
|
-
const plugin =
|
|
8043
|
-
const
|
|
8044
|
-
const
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
9682
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9683
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9684
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9685
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9686
|
+
return async function handler(req) {
|
|
9687
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9688
|
+
if (authResult) return authResult;
|
|
9689
|
+
const url = new URL(req.url);
|
|
9690
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9691
|
+
if (req.method === "GET") {
|
|
9692
|
+
try {
|
|
9693
|
+
const history = await storage.getHistory(sessionId);
|
|
9694
|
+
return import_server.NextResponse.json({ history });
|
|
9695
|
+
} catch (err) {
|
|
9696
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9697
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9698
|
+
}
|
|
9699
|
+
} else if (req.method === "POST") {
|
|
9700
|
+
try {
|
|
9701
|
+
const body = await req.json().catch(() => ({}));
|
|
9702
|
+
const sid = body.sessionId || sessionId;
|
|
9703
|
+
await storage.clearHistory(sid);
|
|
9704
|
+
return import_server.NextResponse.json({ success: true });
|
|
9705
|
+
} catch (err) {
|
|
9706
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9707
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9710
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9711
|
+
};
|
|
9712
|
+
}
|
|
9713
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9714
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9715
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9716
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9717
|
+
return async function handler(req) {
|
|
9718
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9719
|
+
if (authResult) return authResult;
|
|
9720
|
+
if (req.method === "GET") {
|
|
9721
|
+
try {
|
|
9722
|
+
const url = new URL(req.url);
|
|
9723
|
+
const messageId = url.searchParams.get("messageId");
|
|
9724
|
+
if (!messageId) {
|
|
9725
|
+
const feedbackList = await storage.listFeedback();
|
|
9726
|
+
return import_server.NextResponse.json({ feedback: feedbackList });
|
|
9727
|
+
}
|
|
9728
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9729
|
+
return import_server.NextResponse.json({ feedback });
|
|
9730
|
+
} catch (err) {
|
|
9731
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9732
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9733
|
+
}
|
|
9734
|
+
} else if (req.method === "POST") {
|
|
9735
|
+
try {
|
|
9736
|
+
const body = await req.json();
|
|
9737
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9738
|
+
if (!messageId) {
|
|
9739
|
+
return import_server.NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9740
|
+
}
|
|
9741
|
+
if (!rating) {
|
|
9742
|
+
return import_server.NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9743
|
+
}
|
|
9744
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9745
|
+
return import_server.NextResponse.json({ success: true });
|
|
9746
|
+
} catch (err) {
|
|
9747
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9748
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9749
|
+
}
|
|
9750
|
+
}
|
|
9751
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9752
|
+
};
|
|
9753
|
+
}
|
|
9754
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9755
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9756
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9757
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9758
|
+
return async function GET(req) {
|
|
9759
|
+
if (req) {
|
|
9760
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9761
|
+
if (authResult) return authResult;
|
|
9762
|
+
}
|
|
9763
|
+
void req;
|
|
9764
|
+
try {
|
|
9765
|
+
const sessions = await storage.listSessions();
|
|
9766
|
+
return import_server.NextResponse.json({ sessions });
|
|
9767
|
+
} catch (err) {
|
|
9768
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9769
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9770
|
+
}
|
|
9771
|
+
};
|
|
9772
|
+
}
|
|
9773
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9774
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9775
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9776
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9777
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9778
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9779
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9780
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9781
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9782
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9783
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
8048
9784
|
async function routePostRequest(req, segment) {
|
|
8049
9785
|
switch (segment) {
|
|
8050
9786
|
case "chat":
|
|
@@ -8056,22 +9792,35 @@ function createRagHandler(configOrPlugin) {
|
|
|
8056
9792
|
case "suggestions":
|
|
8057
9793
|
return suggestionsHandler(req);
|
|
8058
9794
|
case "health":
|
|
8059
|
-
return healthHandler();
|
|
9795
|
+
return healthHandler(req);
|
|
9796
|
+
case "history":
|
|
9797
|
+
case "history/clear":
|
|
9798
|
+
return historyHandler(req);
|
|
9799
|
+
case "feedback":
|
|
9800
|
+
return feedbackHandler(req);
|
|
8060
9801
|
default:
|
|
8061
9802
|
return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
8062
9803
|
}
|
|
8063
9804
|
}
|
|
8064
9805
|
async function routeGetRequest(req, segment) {
|
|
8065
|
-
|
|
8066
|
-
|
|
9806
|
+
switch (segment) {
|
|
9807
|
+
case "health":
|
|
9808
|
+
return healthHandler(req);
|
|
9809
|
+
case "history":
|
|
9810
|
+
return historyHandler(req);
|
|
9811
|
+
case "feedback":
|
|
9812
|
+
return feedbackHandler(req);
|
|
9813
|
+
case "sessions":
|
|
9814
|
+
return sessionsHandler(req);
|
|
9815
|
+
default:
|
|
9816
|
+
return import_server.NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
8067
9817
|
}
|
|
8068
|
-
return import_server.NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
|
|
8069
9818
|
}
|
|
8070
9819
|
async function getSegment(context) {
|
|
8071
|
-
var
|
|
8072
|
-
const resolvedParams = typeof ((
|
|
9820
|
+
var _a2;
|
|
9821
|
+
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
9822
|
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
8074
|
-
return segments
|
|
9823
|
+
return segments.join("/") || "chat";
|
|
8075
9824
|
}
|
|
8076
9825
|
return {
|
|
8077
9826
|
GET: async (req, context) => {
|
|
@@ -8110,8 +9859,10 @@ function createRagHandler(configOrPlugin) {
|
|
|
8110
9859
|
EmbeddingFailedException,
|
|
8111
9860
|
EmbeddingStrategy,
|
|
8112
9861
|
EmbeddingStrategyResolver,
|
|
9862
|
+
GroqProvider,
|
|
8113
9863
|
LLMFactory,
|
|
8114
9864
|
LLM_PROFILES,
|
|
9865
|
+
LicenseVerifier,
|
|
8115
9866
|
MilvusProvider,
|
|
8116
9867
|
MongoDBProvider,
|
|
8117
9868
|
MultiTablePostgresProvider,
|
|
@@ -8125,6 +9876,7 @@ function createRagHandler(configOrPlugin) {
|
|
|
8125
9876
|
ProviderNotFoundException,
|
|
8126
9877
|
ProviderRegistry,
|
|
8127
9878
|
QdrantProvider,
|
|
9879
|
+
QwenProvider,
|
|
8128
9880
|
RateLimitException,
|
|
8129
9881
|
RedisProvider,
|
|
8130
9882
|
RetrievalException,
|
|
@@ -8136,10 +9888,13 @@ function createRagHandler(configOrPlugin) {
|
|
|
8136
9888
|
VectorPlugin,
|
|
8137
9889
|
WeaviateProvider,
|
|
8138
9890
|
createChatHandler,
|
|
9891
|
+
createFeedbackHandler,
|
|
8139
9892
|
createFromPreset,
|
|
8140
9893
|
createHealthHandler,
|
|
9894
|
+
createHistoryHandler,
|
|
8141
9895
|
createIngestHandler,
|
|
8142
9896
|
createRagHandler,
|
|
9897
|
+
createSessionsHandler,
|
|
8143
9898
|
createStreamHandler,
|
|
8144
9899
|
createUploadHandler,
|
|
8145
9900
|
getRagConfig,
|