@retrivora-ai/rag-engine 1.9.7 → 1.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -136
- package/dist/{ILLMProvider-Bhk6zJOK.d.mts → ILLMProvider-DMxLyTdq.d.mts} +59 -4
- package/dist/{ILLMProvider-Bhk6zJOK.d.ts → ILLMProvider-DMxLyTdq.d.ts} +59 -4
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +2327 -474
- package/dist/handlers/index.mjs +2329 -473
- package/dist/{index-B9J_XEh0.d.ts → index-CfkqZd2Y.d.ts} +12 -2
- package/dist/{index-C3SVtPYg.d.mts → index-DXd29KMq.d.mts} +27 -52
- package/dist/{index-Bu7T6xgr.d.ts → index-D_bOdJML.d.ts} +27 -52
- package/dist/{index-BJ4cd-t5.d.mts → index-xygonxpW.d.mts} +12 -2
- package/dist/index.css +783 -550
- package/dist/index.d.mts +35 -7
- package/dist/index.d.ts +35 -7
- package/dist/index.js +419 -282
- package/dist/index.mjs +426 -292
- package/dist/server.d.mts +65 -6
- package/dist/server.d.ts +65 -6
- package/dist/server.js +2185 -317
- package/dist/server.mjs +2185 -317
- package/package.json +13 -8
- package/src/app/constants.tsx +37 -7
- package/src/app/page.tsx +2 -0
- package/src/components/ChatWidget.tsx +2 -1
- package/src/components/ChatWindow.tsx +4 -1
- package/src/components/CodeViewer.tsx +19 -14
- package/src/components/MarkdownComponents.tsx +44 -1
- package/src/components/MessageBubble.tsx +162 -50
- package/src/components/constants.tsx +228 -0
- package/src/config/RagConfig.ts +48 -2
- package/src/config/constants.ts +4 -0
- package/src/config/serverConfig.ts +15 -0
- package/src/core/ConfigResolver.ts +38 -6
- package/src/core/DatabaseStorage.ts +469 -0
- package/src/core/LicenseVerifier.ts +260 -0
- package/src/core/MultiAgentCoordinator.ts +239 -0
- package/src/core/Pipeline.ts +151 -18
- package/src/core/Retrivora.ts +7 -0
- package/src/core/VectorPlugin.ts +12 -3
- package/src/core/mcp.ts +261 -0
- package/src/handlers/index.ts +449 -63
- package/src/hooks/useRagChat.ts +96 -42
- package/src/hooks/useStoredMessages.ts +15 -4
- package/src/index.ts +3 -0
- package/src/llm/LLMFactory.ts +9 -1
- package/src/llm/providers/GroqProvider.ts +176 -0
- package/src/llm/providers/QwenProvider.ts +191 -0
- package/src/server.ts +7 -0
- package/src/types/chat.ts +14 -0
- package/src/types/props.ts +12 -0
- package/.env.example +0 -80
- package/LICENSE.txt +0 -21
- package/src/components/AmbientBackground.tsx +0 -29
- package/src/components/ArchitectureCard.tsx +0 -17
- package/src/components/ArchitectureCardsSection.tsx +0 -15
- package/src/components/DocViewer.tsx +0 -103
- package/src/components/Documentation.tsx +0 -121
- package/src/components/Hero.tsx +0 -59
- package/src/components/Lifecycle.tsx +0 -37
- package/src/components/Navbar.tsx +0 -55
package/dist/handlers/index.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) {
|
|
@@ -2071,9 +2071,12 @@ var init_SimpleGraphProvider = __esm({
|
|
|
2071
2071
|
var handlers_exports = {};
|
|
2072
2072
|
__export(handlers_exports, {
|
|
2073
2073
|
createChatHandler: () => createChatHandler,
|
|
2074
|
+
createFeedbackHandler: () => createFeedbackHandler,
|
|
2074
2075
|
createHealthHandler: () => createHealthHandler,
|
|
2076
|
+
createHistoryHandler: () => createHistoryHandler,
|
|
2075
2077
|
createIngestHandler: () => createIngestHandler,
|
|
2076
2078
|
createRagHandler: () => createRagHandler,
|
|
2079
|
+
createSessionsHandler: () => createSessionsHandler,
|
|
2077
2080
|
createStreamHandler: () => createStreamHandler,
|
|
2078
2081
|
createSuggestionsHandler: () => createSuggestionsHandler,
|
|
2079
2082
|
createUploadHandler: () => createUploadHandler,
|
|
@@ -2110,6 +2113,8 @@ var LLM_PROVIDERS = [
|
|
|
2110
2113
|
"anthropic",
|
|
2111
2114
|
"ollama",
|
|
2112
2115
|
"gemini",
|
|
2116
|
+
"groq",
|
|
2117
|
+
"qwen",
|
|
2113
2118
|
"rest",
|
|
2114
2119
|
"universal_rest",
|
|
2115
2120
|
"custom"
|
|
@@ -2118,6 +2123,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2118
2123
|
"openai",
|
|
2119
2124
|
"ollama",
|
|
2120
2125
|
"gemini",
|
|
2126
|
+
"qwen",
|
|
2121
2127
|
"rest",
|
|
2122
2128
|
"universal_rest",
|
|
2123
2129
|
"custom"
|
|
@@ -2126,6 +2132,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2126
2132
|
"openai",
|
|
2127
2133
|
"ollama",
|
|
2128
2134
|
"gemini",
|
|
2135
|
+
"qwen",
|
|
2129
2136
|
"rest",
|
|
2130
2137
|
"universal_rest"
|
|
2131
2138
|
];
|
|
@@ -2133,8 +2140,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2133
2140
|
|
|
2134
2141
|
// src/config/serverConfig.ts
|
|
2135
2142
|
function readString(env, name) {
|
|
2136
|
-
var
|
|
2137
|
-
const value = (
|
|
2143
|
+
var _a2;
|
|
2144
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2138
2145
|
return value ? value : void 0;
|
|
2139
2146
|
}
|
|
2140
2147
|
function readNumber(env, name, fallback) {
|
|
@@ -2147,23 +2154,23 @@ function readNumber(env, name, fallback) {
|
|
|
2147
2154
|
return parsed;
|
|
2148
2155
|
}
|
|
2149
2156
|
function readEnum(env, name, fallback, allowed) {
|
|
2150
|
-
var
|
|
2151
|
-
const value = (
|
|
2157
|
+
var _a2;
|
|
2158
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2152
2159
|
if (allowed.includes(value)) {
|
|
2153
2160
|
return value;
|
|
2154
2161
|
}
|
|
2155
2162
|
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
2156
2163
|
}
|
|
2157
2164
|
function getEnvConfig(env = process.env, base) {
|
|
2158
|
-
var
|
|
2159
|
-
const projectId = (_c = (_b = (
|
|
2165
|
+
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;
|
|
2166
|
+
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__";
|
|
2160
2167
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2161
2168
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2162
2169
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2163
2170
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2164
2171
|
const vectorDbOptions = {};
|
|
2165
2172
|
if (vectorProvider === "pinecone") {
|
|
2166
|
-
vectorDbOptions.apiKey = (
|
|
2173
|
+
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 : "";
|
|
2167
2174
|
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;
|
|
2168
2175
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2169
2176
|
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 : "";
|
|
@@ -2225,17 +2232,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2225
2232
|
rest: "default",
|
|
2226
2233
|
custom: "default"
|
|
2227
2234
|
};
|
|
2228
|
-
return __spreadValues({
|
|
2235
|
+
return __spreadProps(__spreadValues({
|
|
2229
2236
|
projectId,
|
|
2237
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2230
2238
|
vectorDb: {
|
|
2231
2239
|
provider: vectorProvider,
|
|
2232
|
-
indexName: (
|
|
2240
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2233
2241
|
options: vectorDbOptions
|
|
2234
2242
|
},
|
|
2235
2243
|
llm: {
|
|
2236
2244
|
provider: llmProvider,
|
|
2237
|
-
model: (
|
|
2238
|
-
apiKey: (
|
|
2245
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2246
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2239
2247
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2240
2248
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2241
2249
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2248,7 +2256,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2248
2256
|
},
|
|
2249
2257
|
embedding: {
|
|
2250
2258
|
provider: embeddingProvider,
|
|
2251
|
-
model: (
|
|
2259
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2252
2260
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2253
2261
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2254
2262
|
dimensions: embeddingDimensions,
|
|
@@ -2259,30 +2267,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2259
2267
|
}
|
|
2260
2268
|
},
|
|
2261
2269
|
ui: {
|
|
2262
|
-
title: (
|
|
2263
|
-
subtitle: (
|
|
2264
|
-
primaryColor: (
|
|
2265
|
-
accentColor: (
|
|
2266
|
-
logoUrl: (
|
|
2267
|
-
placeholder: (
|
|
2268
|
-
showSources: ((
|
|
2269
|
-
welcomeMessage: (
|
|
2270
|
-
visualStyle: (
|
|
2271
|
-
borderRadius: (
|
|
2272
|
-
allowUpload: ((
|
|
2270
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2271
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2272
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2273
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2274
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2275
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2276
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2277
|
+
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.",
|
|
2278
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2279
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2280
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2273
2281
|
},
|
|
2274
2282
|
rag: {
|
|
2275
2283
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2276
2284
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2277
2285
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2278
2286
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2279
|
-
filterableFields: (
|
|
2287
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2280
2288
|
// Query pipeline toggles — read from .env.local
|
|
2281
2289
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2282
2290
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2283
2291
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2284
|
-
architecture: (
|
|
2285
|
-
chunkingStrategy: (
|
|
2292
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2293
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2286
2294
|
uiMapping: (() => {
|
|
2287
2295
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2288
2296
|
if (!raw) return void 0;
|
|
@@ -2292,6 +2300,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2292
2300
|
return void 0;
|
|
2293
2301
|
}
|
|
2294
2302
|
})()
|
|
2303
|
+
},
|
|
2304
|
+
telemetry: {
|
|
2305
|
+
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,
|
|
2306
|
+
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"
|
|
2295
2307
|
}
|
|
2296
2308
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2297
2309
|
graphDb: {
|
|
@@ -2302,7 +2314,19 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2302
2314
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2303
2315
|
}
|
|
2304
2316
|
}
|
|
2305
|
-
} : {})
|
|
2317
|
+
} : {}), {
|
|
2318
|
+
mcpServers: (() => {
|
|
2319
|
+
var _a3;
|
|
2320
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2321
|
+
if (!raw) return void 0;
|
|
2322
|
+
try {
|
|
2323
|
+
return JSON.parse(raw);
|
|
2324
|
+
} catch (e) {
|
|
2325
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2326
|
+
return void 0;
|
|
2327
|
+
}
|
|
2328
|
+
})()
|
|
2329
|
+
});
|
|
2306
2330
|
}
|
|
2307
2331
|
|
|
2308
2332
|
// src/core/ConfigResolver.ts
|
|
@@ -2328,7 +2352,8 @@ var ConfigResolver = class {
|
|
|
2328
2352
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2329
2353
|
}) : envConfig.embedding,
|
|
2330
2354
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2331
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2355
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2356
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2332
2357
|
});
|
|
2333
2358
|
}
|
|
2334
2359
|
/**
|
|
@@ -2337,10 +2362,10 @@ var ConfigResolver = class {
|
|
|
2337
2362
|
* fallback behavior.
|
|
2338
2363
|
*/
|
|
2339
2364
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2340
|
-
var
|
|
2365
|
+
var _a2;
|
|
2341
2366
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2342
2367
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2343
|
-
vectorDb: (
|
|
2368
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2344
2369
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2345
2370
|
});
|
|
2346
2371
|
return this.resolve(normalized, env);
|
|
@@ -2360,28 +2385,52 @@ var ConfigResolver = class {
|
|
|
2360
2385
|
}
|
|
2361
2386
|
}
|
|
2362
2387
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2363
|
-
var
|
|
2388
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2364
2389
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2365
2390
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2366
2391
|
if (retrieval) {
|
|
2367
|
-
normalized.topK = (
|
|
2392
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2368
2393
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2369
2394
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2370
2395
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
2371
|
-
if (retrieval.strategy === "agentic") normalized.architecture = "
|
|
2372
|
-
if (retrieval.strategy === "contextual-compression")
|
|
2396
|
+
if (retrieval.strategy === "agentic") normalized.architecture = "multi-agent";
|
|
2397
|
+
if (retrieval.strategy === "contextual-compression") {
|
|
2398
|
+
normalized.useReranking = true;
|
|
2399
|
+
normalized.architecture = (_e = normalized.architecture) != null ? _e : "retrieve-and-rerank";
|
|
2400
|
+
}
|
|
2373
2401
|
}
|
|
2374
2402
|
if (workflow == null ? void 0 : workflow.type) {
|
|
2375
2403
|
const type = workflow.type;
|
|
2376
|
-
if (type === "
|
|
2377
|
-
|
|
2378
|
-
|
|
2404
|
+
if (type === "naive-rag") {
|
|
2405
|
+
normalized.architecture = "naive";
|
|
2406
|
+
normalized.useReranking = false;
|
|
2407
|
+
normalized.useGraphRetrieval = false;
|
|
2408
|
+
} else if (type === "retrieve-and-rerank") {
|
|
2409
|
+
normalized.architecture = "retrieve-and-rerank";
|
|
2410
|
+
normalized.useReranking = true;
|
|
2411
|
+
} else if (type === "multimodal-rag") {
|
|
2412
|
+
normalized.architecture = "multimodal";
|
|
2413
|
+
} else if (type === "graph-rag") {
|
|
2379
2414
|
normalized.architecture = "graph";
|
|
2380
2415
|
normalized.useGraphRetrieval = true;
|
|
2416
|
+
} else if (type === "hybrid-rag") {
|
|
2417
|
+
normalized.architecture = "hybrid";
|
|
2418
|
+
} else if (type === "agentic-router") {
|
|
2419
|
+
normalized.architecture = "agentic-router";
|
|
2420
|
+
} else if (type === "multi-agent-rag" || type === "multi-agent" || type === "agentic" || type === "agentic-rag") {
|
|
2421
|
+
normalized.architecture = "multi-agent";
|
|
2381
2422
|
} else if (type === "simple-rag" || type === "rag") {
|
|
2382
|
-
normalized.architecture = (
|
|
2423
|
+
normalized.architecture = (_f = normalized.architecture) != null ? _f : "naive";
|
|
2383
2424
|
}
|
|
2384
2425
|
}
|
|
2426
|
+
if (normalized.architecture === "retrieve-and-rerank") {
|
|
2427
|
+
normalized.useReranking = true;
|
|
2428
|
+
} else if (normalized.architecture === "graph") {
|
|
2429
|
+
normalized.useGraphRetrieval = true;
|
|
2430
|
+
} else if (normalized.architecture === "naive") {
|
|
2431
|
+
normalized.useReranking = false;
|
|
2432
|
+
normalized.useGraphRetrieval = false;
|
|
2433
|
+
}
|
|
2385
2434
|
return normalized;
|
|
2386
2435
|
}
|
|
2387
2436
|
};
|
|
@@ -2446,8 +2495,8 @@ var OpenAIProvider = class {
|
|
|
2446
2495
|
const apiKey = config.apiKey;
|
|
2447
2496
|
const modelName = config.model;
|
|
2448
2497
|
try {
|
|
2449
|
-
const
|
|
2450
|
-
const client = new
|
|
2498
|
+
const OpenAI4 = await import("openai");
|
|
2499
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2451
2500
|
const models = await client.models.list();
|
|
2452
2501
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2453
2502
|
return {
|
|
@@ -2468,8 +2517,8 @@ var OpenAIProvider = class {
|
|
|
2468
2517
|
};
|
|
2469
2518
|
}
|
|
2470
2519
|
async chat(messages, context, options) {
|
|
2471
|
-
var
|
|
2472
|
-
const basePrompt = (_b = (
|
|
2520
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2521
|
+
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.";
|
|
2473
2522
|
const systemMessage = {
|
|
2474
2523
|
role: "system",
|
|
2475
2524
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2488,12 +2537,12 @@ var OpenAIProvider = class {
|
|
|
2488
2537
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2489
2538
|
stop: options == null ? void 0 : options.stop
|
|
2490
2539
|
});
|
|
2491
|
-
return (_i = (_h = (
|
|
2540
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2492
2541
|
}
|
|
2493
2542
|
chatStream(messages, context, options) {
|
|
2494
2543
|
return __asyncGenerator(this, null, function* () {
|
|
2495
|
-
var
|
|
2496
|
-
const basePrompt = (_b = (
|
|
2544
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2545
|
+
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.";
|
|
2497
2546
|
const systemMessage = {
|
|
2498
2547
|
role: "system",
|
|
2499
2548
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2519,7 +2568,7 @@ var OpenAIProvider = class {
|
|
|
2519
2568
|
try {
|
|
2520
2569
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2521
2570
|
const chunk = temp.value;
|
|
2522
|
-
const content = ((_h = (
|
|
2571
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2523
2572
|
if (content) yield content;
|
|
2524
2573
|
}
|
|
2525
2574
|
} catch (temp) {
|
|
@@ -2539,8 +2588,8 @@ var OpenAIProvider = class {
|
|
|
2539
2588
|
return results[0];
|
|
2540
2589
|
}
|
|
2541
2590
|
async batchEmbed(texts, options) {
|
|
2542
|
-
var
|
|
2543
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2591
|
+
var _a2, _b, _c, _d, _e;
|
|
2592
|
+
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";
|
|
2544
2593
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2545
2594
|
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
2546
2595
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2617,8 +2666,8 @@ var AnthropicProvider = class {
|
|
|
2617
2666
|
};
|
|
2618
2667
|
}
|
|
2619
2668
|
async chat(messages, context, options) {
|
|
2620
|
-
var
|
|
2621
|
-
const basePrompt = (_b = (
|
|
2669
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2670
|
+
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.";
|
|
2622
2671
|
const system = buildSystemContent(basePrompt, context);
|
|
2623
2672
|
const anthropicMessages = messages.map((m) => ({
|
|
2624
2673
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2629,7 +2678,7 @@ var AnthropicProvider = class {
|
|
|
2629
2678
|
const extraParams = {};
|
|
2630
2679
|
if (isThinkingEnabled && isClaude37) {
|
|
2631
2680
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2632
|
-
const maxTokens = (
|
|
2681
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2633
2682
|
const budget = Math.min(
|
|
2634
2683
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2635
2684
|
maxTokens - 1
|
|
@@ -2656,8 +2705,8 @@ var AnthropicProvider = class {
|
|
|
2656
2705
|
}
|
|
2657
2706
|
chatStream(messages, context, options) {
|
|
2658
2707
|
return __asyncGenerator(this, null, function* () {
|
|
2659
|
-
var
|
|
2660
|
-
const basePrompt = (_b = (
|
|
2708
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2709
|
+
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.";
|
|
2661
2710
|
const system = buildSystemContent(basePrompt, context);
|
|
2662
2711
|
const anthropicMessages = messages.map((m) => ({
|
|
2663
2712
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2668,7 +2717,7 @@ var AnthropicProvider = class {
|
|
|
2668
2717
|
const extraParams = {};
|
|
2669
2718
|
if (isThinkingEnabled && isClaude37) {
|
|
2670
2719
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2671
|
-
const maxTokens = (
|
|
2720
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2672
2721
|
const budget = Math.min(
|
|
2673
2722
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2674
2723
|
maxTokens - 1
|
|
@@ -2741,8 +2790,8 @@ var AnthropicProvider = class {
|
|
|
2741
2790
|
var import_axios = __toESM(require("axios"));
|
|
2742
2791
|
var OllamaProvider = class {
|
|
2743
2792
|
constructor(llmConfig, embeddingConfig) {
|
|
2744
|
-
var
|
|
2745
|
-
const baseURL = (
|
|
2793
|
+
var _a2, _b;
|
|
2794
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2746
2795
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2747
2796
|
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2748
2797
|
this.llmConfig = llmConfig;
|
|
@@ -2800,8 +2849,8 @@ var OllamaProvider = class {
|
|
|
2800
2849
|
};
|
|
2801
2850
|
}
|
|
2802
2851
|
async chat(messages, context, options) {
|
|
2803
|
-
var
|
|
2804
|
-
const basePrompt = (_b = (
|
|
2852
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2853
|
+
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.";
|
|
2805
2854
|
const system = buildSystemContent(basePrompt, context);
|
|
2806
2855
|
const { data } = await this.http.post("/api/chat", {
|
|
2807
2856
|
model: this.llmConfig.model,
|
|
@@ -2819,8 +2868,8 @@ var OllamaProvider = class {
|
|
|
2819
2868
|
}
|
|
2820
2869
|
chatStream(messages, context, options) {
|
|
2821
2870
|
return __asyncGenerator(this, null, function* () {
|
|
2822
|
-
var
|
|
2823
|
-
const basePrompt = (_b = (
|
|
2871
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2872
|
+
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.";
|
|
2824
2873
|
const system = buildSystemContent(basePrompt, context);
|
|
2825
2874
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2826
2875
|
model: this.llmConfig.model,
|
|
@@ -2849,7 +2898,7 @@ var OllamaProvider = class {
|
|
|
2849
2898
|
if (!line.trim()) continue;
|
|
2850
2899
|
try {
|
|
2851
2900
|
const json = JSON.parse(line);
|
|
2852
|
-
if ((
|
|
2901
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2853
2902
|
yield json.message.content;
|
|
2854
2903
|
}
|
|
2855
2904
|
if (json.done) return;
|
|
@@ -2878,10 +2927,10 @@ var OllamaProvider = class {
|
|
|
2878
2927
|
});
|
|
2879
2928
|
}
|
|
2880
2929
|
async embed(text, options) {
|
|
2881
|
-
var
|
|
2882
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2930
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2931
|
+
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";
|
|
2883
2932
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2884
|
-
const client = baseURL !== ((
|
|
2933
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2885
2934
|
let prompt = text;
|
|
2886
2935
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2887
2936
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -2980,9 +3029,9 @@ var GeminiProvider = class {
|
|
|
2980
3029
|
static getHealthChecker() {
|
|
2981
3030
|
return {
|
|
2982
3031
|
async check(config) {
|
|
2983
|
-
var
|
|
3032
|
+
var _a2, _b;
|
|
2984
3033
|
const timestamp = Date.now();
|
|
2985
|
-
const apiKey = (_b = (
|
|
3034
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
2986
3035
|
const modelName = sanitizeModel(config.model);
|
|
2987
3036
|
try {
|
|
2988
3037
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -3012,16 +3061,16 @@ var GeminiProvider = class {
|
|
|
3012
3061
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
3013
3062
|
* API key differs from the LLM API key. */
|
|
3014
3063
|
get embeddingClient() {
|
|
3015
|
-
var
|
|
3016
|
-
if (((
|
|
3064
|
+
var _a2;
|
|
3065
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
3017
3066
|
return buildClient(this.embeddingConfig.apiKey);
|
|
3018
3067
|
}
|
|
3019
3068
|
return this.client;
|
|
3020
3069
|
}
|
|
3021
3070
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
3022
3071
|
resolveEmbeddingModel(optionsModel) {
|
|
3023
|
-
var
|
|
3024
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3072
|
+
var _a2, _b;
|
|
3073
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
3025
3074
|
}
|
|
3026
3075
|
/**
|
|
3027
3076
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3041,8 +3090,8 @@ var GeminiProvider = class {
|
|
|
3041
3090
|
// ILLMProvider — chat
|
|
3042
3091
|
// -------------------------------------------------------------------------
|
|
3043
3092
|
async chat(messages, context, options) {
|
|
3044
|
-
var
|
|
3045
|
-
const basePrompt = (_b = (
|
|
3093
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3094
|
+
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.";
|
|
3046
3095
|
const model = this.client.getGenerativeModel({
|
|
3047
3096
|
model: this.llmConfig.model,
|
|
3048
3097
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3059,8 +3108,8 @@ var GeminiProvider = class {
|
|
|
3059
3108
|
}
|
|
3060
3109
|
chatStream(messages, context, options) {
|
|
3061
3110
|
return __asyncGenerator(this, null, function* () {
|
|
3062
|
-
var
|
|
3063
|
-
const basePrompt = (_b = (
|
|
3111
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3112
|
+
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.";
|
|
3064
3113
|
const model = this.client.getGenerativeModel({
|
|
3065
3114
|
model: this.llmConfig.model,
|
|
3066
3115
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3095,11 +3144,11 @@ var GeminiProvider = class {
|
|
|
3095
3144
|
// ILLMProvider — embeddings
|
|
3096
3145
|
// -------------------------------------------------------------------------
|
|
3097
3146
|
async embed(text, options) {
|
|
3098
|
-
var
|
|
3147
|
+
var _a2, _b;
|
|
3099
3148
|
const content = applyPrefix(
|
|
3100
3149
|
text,
|
|
3101
3150
|
options == null ? void 0 : options.taskType,
|
|
3102
|
-
(
|
|
3151
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3103
3152
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3104
3153
|
);
|
|
3105
3154
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3116,7 +3165,7 @@ var GeminiProvider = class {
|
|
|
3116
3165
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3117
3166
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3118
3167
|
const requests = texts.map((text) => {
|
|
3119
|
-
var
|
|
3168
|
+
var _a2, _b;
|
|
3120
3169
|
return {
|
|
3121
3170
|
content: {
|
|
3122
3171
|
role: "user",
|
|
@@ -3124,7 +3173,7 @@ var GeminiProvider = class {
|
|
|
3124
3173
|
text: applyPrefix(
|
|
3125
3174
|
text,
|
|
3126
3175
|
options == null ? void 0 : options.taskType,
|
|
3127
|
-
(
|
|
3176
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3128
3177
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3129
3178
|
)
|
|
3130
3179
|
}]
|
|
@@ -3141,8 +3190,8 @@ var GeminiProvider = class {
|
|
|
3141
3190
|
throw err;
|
|
3142
3191
|
});
|
|
3143
3192
|
return response.embeddings.map((e) => {
|
|
3144
|
-
var
|
|
3145
|
-
return (
|
|
3193
|
+
var _a2;
|
|
3194
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3146
3195
|
});
|
|
3147
3196
|
}
|
|
3148
3197
|
// -------------------------------------------------------------------------
|
|
@@ -3162,191 +3211,510 @@ var GeminiProvider = class {
|
|
|
3162
3211
|
}
|
|
3163
3212
|
};
|
|
3164
3213
|
|
|
3165
|
-
// src/llm/providers/
|
|
3166
|
-
var
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3176
|
-
};
|
|
3177
|
-
var LLM_PROFILES = {
|
|
3178
|
-
"openai-compatible": OPENAI_BASE,
|
|
3179
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3180
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3181
|
-
}),
|
|
3182
|
-
"anthropic-claude": {
|
|
3183
|
-
chatPath: "/v1/messages",
|
|
3184
|
-
responseExtractPath: "content[0].text",
|
|
3185
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
3186
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3187
|
-
},
|
|
3188
|
-
"google-gemini": {
|
|
3189
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3190
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3191
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3192
|
-
},
|
|
3193
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3194
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3195
|
-
}),
|
|
3196
|
-
"ollama-standard": {
|
|
3197
|
-
chatPath: "/api/chat",
|
|
3198
|
-
embedPath: "/api/embeddings",
|
|
3199
|
-
responseExtractPath: "message.content",
|
|
3200
|
-
embedExtractPath: "embedding",
|
|
3201
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3202
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3203
|
-
}
|
|
3204
|
-
};
|
|
3205
|
-
|
|
3206
|
-
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3207
|
-
var UniversalLLMAdapter = class {
|
|
3208
|
-
constructor(config) {
|
|
3209
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3210
|
-
this.model = config.model;
|
|
3211
|
-
const llmConfig = config;
|
|
3212
|
-
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
3213
|
-
let profile = {};
|
|
3214
|
-
if (typeof options.profile === "string") {
|
|
3215
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
3216
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3217
|
-
profile = options.profile;
|
|
3218
|
-
}
|
|
3219
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3220
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3221
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3222
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3223
|
-
this.apiKey = config.apiKey;
|
|
3224
|
-
this.baseUrl = (_g = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g : "";
|
|
3225
|
-
if (!this.baseUrl) {
|
|
3226
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3227
|
-
}
|
|
3228
|
-
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3229
|
-
"Content-Type": "application/json"
|
|
3230
|
-
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3231
|
-
this.http = import_axios2.default.create({
|
|
3232
|
-
baseURL: this.baseUrl,
|
|
3233
|
-
headers: this.resolvedHeaders,
|
|
3234
|
-
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3214
|
+
// src/llm/providers/GroqProvider.ts
|
|
3215
|
+
var import_openai2 = __toESM(require("openai"));
|
|
3216
|
+
var GroqProvider = class {
|
|
3217
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3218
|
+
void embeddingConfig;
|
|
3219
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3220
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3221
|
+
this.client = new import_openai2.default({
|
|
3222
|
+
apiKey,
|
|
3223
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3235
3224
|
});
|
|
3225
|
+
this.llmConfig = llmConfig;
|
|
3236
3226
|
}
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3227
|
+
static getValidator() {
|
|
3228
|
+
return {
|
|
3229
|
+
validate(config) {
|
|
3230
|
+
const errors = [];
|
|
3231
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3232
|
+
errors.push({
|
|
3233
|
+
field: "llm.apiKey",
|
|
3234
|
+
message: "Groq API key is required",
|
|
3235
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3236
|
+
severity: "error"
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
if (!config.model) {
|
|
3240
|
+
errors.push({
|
|
3241
|
+
field: "llm.model",
|
|
3242
|
+
message: "Groq model name is required",
|
|
3243
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3244
|
+
severity: "error"
|
|
3245
|
+
});
|
|
3246
|
+
}
|
|
3247
|
+
return errors;
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
static getHealthChecker() {
|
|
3252
|
+
return {
|
|
3253
|
+
async check(config) {
|
|
3254
|
+
const timestamp = Date.now();
|
|
3255
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3256
|
+
const modelName = config.model;
|
|
3257
|
+
try {
|
|
3258
|
+
const OpenAI4 = await import("openai");
|
|
3259
|
+
const client = new OpenAI4.default({
|
|
3260
|
+
apiKey,
|
|
3261
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3262
|
+
});
|
|
3263
|
+
const models = await client.models.list();
|
|
3264
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3265
|
+
return {
|
|
3266
|
+
healthy: true,
|
|
3267
|
+
provider: "groq",
|
|
3268
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3269
|
+
timestamp
|
|
3270
|
+
};
|
|
3271
|
+
} catch (error) {
|
|
3272
|
+
return {
|
|
3273
|
+
healthy: false,
|
|
3274
|
+
provider: "groq",
|
|
3275
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3276
|
+
timestamp
|
|
3277
|
+
};
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
async chat(messages, context, options) {
|
|
3283
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3284
|
+
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.";
|
|
3285
|
+
const systemMessage = {
|
|
3286
|
+
role: "system",
|
|
3287
|
+
content: buildSystemContent(basePrompt, context)
|
|
3288
|
+
};
|
|
3240
3289
|
const formattedMessages = [
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3290
|
+
systemMessage,
|
|
3291
|
+
...messages.map((m) => ({
|
|
3292
|
+
role: m.role,
|
|
3293
|
+
content: m.content
|
|
3294
|
+
}))
|
|
3246
3295
|
];
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
} else {
|
|
3256
|
-
payload = {
|
|
3257
|
-
model: this.model,
|
|
3258
|
-
messages: formattedMessages,
|
|
3259
|
-
max_tokens: this.maxTokens,
|
|
3260
|
-
temperature: this.temperature
|
|
3261
|
-
};
|
|
3262
|
-
}
|
|
3263
|
-
const { data } = await this.http.post(path, payload);
|
|
3264
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3265
|
-
const result = resolvePath(data, extractPath);
|
|
3266
|
-
if (result === void 0) {
|
|
3267
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3268
|
-
}
|
|
3269
|
-
return String(result);
|
|
3296
|
+
const completion = await this.client.chat.completions.create({
|
|
3297
|
+
model: this.llmConfig.model,
|
|
3298
|
+
messages: formattedMessages,
|
|
3299
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3300
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3301
|
+
stop: options == null ? void 0 : options.stop
|
|
3302
|
+
});
|
|
3303
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3270
3304
|
}
|
|
3271
|
-
|
|
3272
|
-
* Streaming chat using native fetch + ReadableStream.
|
|
3273
|
-
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3274
|
-
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3275
|
-
*/
|
|
3276
|
-
chatStream(messages, context) {
|
|
3305
|
+
chatStream(messages, context, options) {
|
|
3277
3306
|
return __asyncGenerator(this, null, function* () {
|
|
3278
|
-
var
|
|
3279
|
-
const
|
|
3280
|
-
const
|
|
3281
|
-
|
|
3307
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3308
|
+
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.";
|
|
3309
|
+
const systemMessage = {
|
|
3310
|
+
role: "system",
|
|
3311
|
+
content: buildSystemContent(basePrompt, context)
|
|
3312
|
+
};
|
|
3282
3313
|
const formattedMessages = [
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3314
|
+
systemMessage,
|
|
3315
|
+
...messages.map((m) => ({
|
|
3316
|
+
role: m.role,
|
|
3317
|
+
content: m.content
|
|
3318
|
+
}))
|
|
3288
3319
|
];
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
});
|
|
3297
|
-
if (typeof payload === "object" && payload !== null) {
|
|
3298
|
-
payload.stream = true;
|
|
3299
|
-
}
|
|
3300
|
-
} else {
|
|
3301
|
-
payload = {
|
|
3302
|
-
model: this.model,
|
|
3303
|
-
messages: formattedMessages,
|
|
3304
|
-
max_tokens: this.maxTokens,
|
|
3305
|
-
temperature: this.temperature,
|
|
3306
|
-
stream: true
|
|
3307
|
-
};
|
|
3308
|
-
}
|
|
3309
|
-
const response = yield new __await(fetch(url, {
|
|
3310
|
-
method: "POST",
|
|
3311
|
-
headers: this.resolvedHeaders,
|
|
3312
|
-
body: JSON.stringify(payload)
|
|
3320
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3321
|
+
model: this.llmConfig.model,
|
|
3322
|
+
messages: formattedMessages,
|
|
3323
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3324
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3325
|
+
stop: options == null ? void 0 : options.stop,
|
|
3326
|
+
stream: true
|
|
3313
3327
|
}));
|
|
3314
|
-
if (!
|
|
3315
|
-
|
|
3316
|
-
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3317
|
-
}
|
|
3318
|
-
if (!response.body) {
|
|
3319
|
-
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3328
|
+
if (!stream) {
|
|
3329
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3320
3330
|
}
|
|
3321
|
-
const reader = response.body.getReader();
|
|
3322
|
-
const decoder = new TextDecoder("utf-8");
|
|
3323
|
-
let buffer = "";
|
|
3324
3331
|
try {
|
|
3325
|
-
|
|
3326
|
-
const
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
const lines = buffer.split("\n");
|
|
3330
|
-
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
3331
|
-
for (const line of lines) {
|
|
3332
|
-
const trimmed = line.trim();
|
|
3333
|
-
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
3334
|
-
if (!trimmed.startsWith("data:")) continue;
|
|
3335
|
-
try {
|
|
3336
|
-
const json = JSON.parse(trimmed.slice(5).trim());
|
|
3337
|
-
const text = resolvePath(json, extractPath);
|
|
3338
|
-
if (text && typeof text === "string") yield text;
|
|
3339
|
-
} catch (e) {
|
|
3340
|
-
}
|
|
3341
|
-
}
|
|
3332
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3333
|
+
const chunk = temp.value;
|
|
3334
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3335
|
+
if (content) yield content;
|
|
3342
3336
|
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3337
|
+
} catch (temp) {
|
|
3338
|
+
error = [temp];
|
|
3339
|
+
} finally {
|
|
3340
|
+
try {
|
|
3341
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3342
|
+
} finally {
|
|
3343
|
+
if (error)
|
|
3344
|
+
throw error[0];
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
});
|
|
3348
|
+
}
|
|
3349
|
+
async embed(text, options) {
|
|
3350
|
+
void text;
|
|
3351
|
+
void options;
|
|
3352
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3353
|
+
}
|
|
3354
|
+
async batchEmbed(texts, options) {
|
|
3355
|
+
void texts;
|
|
3356
|
+
void options;
|
|
3357
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3358
|
+
}
|
|
3359
|
+
async ping() {
|
|
3360
|
+
try {
|
|
3361
|
+
await this.client.models.list();
|
|
3362
|
+
return true;
|
|
3363
|
+
} catch (err) {
|
|
3364
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3365
|
+
return false;
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
};
|
|
3369
|
+
|
|
3370
|
+
// src/llm/providers/QwenProvider.ts
|
|
3371
|
+
var import_openai3 = __toESM(require("openai"));
|
|
3372
|
+
var QwenProvider = class {
|
|
3373
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3374
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3375
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3376
|
+
this.client = new import_openai3.default({
|
|
3377
|
+
apiKey,
|
|
3378
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3379
|
+
});
|
|
3380
|
+
this.llmConfig = llmConfig;
|
|
3381
|
+
this.embeddingConfig = embeddingConfig;
|
|
3382
|
+
}
|
|
3383
|
+
static getValidator() {
|
|
3384
|
+
return {
|
|
3385
|
+
validate(config) {
|
|
3386
|
+
const errors = [];
|
|
3387
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3388
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3389
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3390
|
+
errors.push({
|
|
3391
|
+
field: `${prefix}.apiKey`,
|
|
3392
|
+
message: "Qwen API key is required",
|
|
3393
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3394
|
+
severity: "error"
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3397
|
+
if (!config.model) {
|
|
3398
|
+
errors.push({
|
|
3399
|
+
field: `${prefix}.model`,
|
|
3400
|
+
message: "Qwen model name is required",
|
|
3401
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3402
|
+
severity: "error"
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
return errors;
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
static getHealthChecker() {
|
|
3410
|
+
return {
|
|
3411
|
+
async check(config) {
|
|
3412
|
+
const timestamp = Date.now();
|
|
3413
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3414
|
+
const modelName = config.model;
|
|
3415
|
+
try {
|
|
3416
|
+
const OpenAI4 = await import("openai");
|
|
3417
|
+
const client = new OpenAI4.default({
|
|
3418
|
+
apiKey,
|
|
3419
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3420
|
+
});
|
|
3421
|
+
const models = await client.models.list();
|
|
3422
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3423
|
+
return {
|
|
3424
|
+
healthy: true,
|
|
3425
|
+
provider: "qwen",
|
|
3426
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3427
|
+
timestamp
|
|
3428
|
+
};
|
|
3429
|
+
} catch (error) {
|
|
3430
|
+
return {
|
|
3431
|
+
healthy: false,
|
|
3432
|
+
provider: "qwen",
|
|
3433
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3434
|
+
timestamp
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
async chat(messages, context, options) {
|
|
3441
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3442
|
+
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.";
|
|
3443
|
+
const systemMessage = {
|
|
3444
|
+
role: "system",
|
|
3445
|
+
content: buildSystemContent(basePrompt, context)
|
|
3446
|
+
};
|
|
3447
|
+
const formattedMessages = [
|
|
3448
|
+
systemMessage,
|
|
3449
|
+
...messages.map((m) => ({
|
|
3450
|
+
role: m.role,
|
|
3451
|
+
content: m.content
|
|
3452
|
+
}))
|
|
3453
|
+
];
|
|
3454
|
+
const completion = await this.client.chat.completions.create({
|
|
3455
|
+
model: this.llmConfig.model,
|
|
3456
|
+
messages: formattedMessages,
|
|
3457
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3458
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3459
|
+
stop: options == null ? void 0 : options.stop
|
|
3460
|
+
});
|
|
3461
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3462
|
+
}
|
|
3463
|
+
chatStream(messages, context, options) {
|
|
3464
|
+
return __asyncGenerator(this, null, function* () {
|
|
3465
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3466
|
+
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.";
|
|
3467
|
+
const systemMessage = {
|
|
3468
|
+
role: "system",
|
|
3469
|
+
content: buildSystemContent(basePrompt, context)
|
|
3470
|
+
};
|
|
3471
|
+
const formattedMessages = [
|
|
3472
|
+
systemMessage,
|
|
3473
|
+
...messages.map((m) => ({
|
|
3474
|
+
role: m.role,
|
|
3475
|
+
content: m.content
|
|
3476
|
+
}))
|
|
3477
|
+
];
|
|
3478
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3479
|
+
model: this.llmConfig.model,
|
|
3480
|
+
messages: formattedMessages,
|
|
3481
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3482
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3483
|
+
stop: options == null ? void 0 : options.stop,
|
|
3484
|
+
stream: true
|
|
3485
|
+
}));
|
|
3486
|
+
if (!stream) {
|
|
3487
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3488
|
+
}
|
|
3489
|
+
try {
|
|
3490
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3491
|
+
const chunk = temp.value;
|
|
3492
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3493
|
+
if (content) yield content;
|
|
3494
|
+
}
|
|
3495
|
+
} catch (temp) {
|
|
3496
|
+
error = [temp];
|
|
3497
|
+
} finally {
|
|
3498
|
+
try {
|
|
3499
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3500
|
+
} finally {
|
|
3501
|
+
if (error)
|
|
3502
|
+
throw error[0];
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
});
|
|
3506
|
+
}
|
|
3507
|
+
async embed(text, options) {
|
|
3508
|
+
const results = await this.batchEmbed([text], options);
|
|
3509
|
+
return results[0];
|
|
3510
|
+
}
|
|
3511
|
+
async batchEmbed(texts, options) {
|
|
3512
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3513
|
+
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";
|
|
3514
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3515
|
+
const client = apiKey !== this.llmConfig.apiKey ? new import_openai3.default({
|
|
3516
|
+
apiKey,
|
|
3517
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3518
|
+
}) : this.client;
|
|
3519
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3520
|
+
return response.data.map((d) => d.embedding);
|
|
3521
|
+
}
|
|
3522
|
+
async ping() {
|
|
3523
|
+
try {
|
|
3524
|
+
await this.client.models.list();
|
|
3525
|
+
return true;
|
|
3526
|
+
} catch (err) {
|
|
3527
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3528
|
+
return false;
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
};
|
|
3532
|
+
|
|
3533
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3534
|
+
var import_axios2 = __toESM(require("axios"));
|
|
3535
|
+
init_templateUtils();
|
|
3536
|
+
|
|
3537
|
+
// src/config/UniversalProfiles.ts
|
|
3538
|
+
var OPENAI_BASE = {
|
|
3539
|
+
chatPath: "/chat/completions",
|
|
3540
|
+
embedPath: "/embeddings",
|
|
3541
|
+
responseExtractPath: "choices[0].message.content",
|
|
3542
|
+
embedExtractPath: "data[0].embedding",
|
|
3543
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3544
|
+
};
|
|
3545
|
+
var LLM_PROFILES = {
|
|
3546
|
+
"openai-compatible": OPENAI_BASE,
|
|
3547
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3548
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3549
|
+
}),
|
|
3550
|
+
"anthropic-claude": {
|
|
3551
|
+
chatPath: "/v1/messages",
|
|
3552
|
+
responseExtractPath: "content[0].text",
|
|
3553
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
3554
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3555
|
+
},
|
|
3556
|
+
"google-gemini": {
|
|
3557
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3558
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3559
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3560
|
+
},
|
|
3561
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3562
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3563
|
+
}),
|
|
3564
|
+
"ollama-standard": {
|
|
3565
|
+
chatPath: "/api/chat",
|
|
3566
|
+
embedPath: "/api/embeddings",
|
|
3567
|
+
responseExtractPath: "message.content",
|
|
3568
|
+
embedExtractPath: "embedding",
|
|
3569
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3570
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3571
|
+
}
|
|
3572
|
+
};
|
|
3573
|
+
|
|
3574
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3575
|
+
var UniversalLLMAdapter = class {
|
|
3576
|
+
constructor(config) {
|
|
3577
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3578
|
+
this.model = config.model;
|
|
3579
|
+
const llmConfig = config;
|
|
3580
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3581
|
+
let profile = {};
|
|
3582
|
+
if (typeof options.profile === "string") {
|
|
3583
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
3584
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3585
|
+
profile = options.profile;
|
|
3586
|
+
}
|
|
3587
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3588
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3589
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3590
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3591
|
+
this.apiKey = config.apiKey;
|
|
3592
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3593
|
+
if (!this.baseUrl) {
|
|
3594
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3595
|
+
}
|
|
3596
|
+
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3597
|
+
"Content-Type": "application/json"
|
|
3598
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3599
|
+
this.http = import_axios2.default.create({
|
|
3600
|
+
baseURL: this.baseUrl,
|
|
3601
|
+
headers: this.resolvedHeaders,
|
|
3602
|
+
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
async chat(messages, context) {
|
|
3606
|
+
var _a2, _b;
|
|
3607
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3608
|
+
const formattedMessages = [
|
|
3609
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3610
|
+
|
|
3611
|
+
Context:
|
|
3612
|
+
${context != null ? context : "None"}` },
|
|
3613
|
+
...messages
|
|
3614
|
+
];
|
|
3615
|
+
let payload;
|
|
3616
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3617
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3618
|
+
model: this.model,
|
|
3619
|
+
messages: formattedMessages,
|
|
3620
|
+
maxTokens: this.maxTokens,
|
|
3621
|
+
temperature: this.temperature
|
|
3622
|
+
});
|
|
3623
|
+
} else {
|
|
3624
|
+
payload = {
|
|
3625
|
+
model: this.model,
|
|
3626
|
+
messages: formattedMessages,
|
|
3627
|
+
max_tokens: this.maxTokens,
|
|
3628
|
+
temperature: this.temperature
|
|
3629
|
+
};
|
|
3630
|
+
}
|
|
3631
|
+
const { data } = await this.http.post(path2, payload);
|
|
3632
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3633
|
+
const result = resolvePath(data, extractPath);
|
|
3634
|
+
if (result === void 0) {
|
|
3635
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3636
|
+
}
|
|
3637
|
+
return String(result);
|
|
3638
|
+
}
|
|
3639
|
+
/**
|
|
3640
|
+
* Streaming chat using native fetch + ReadableStream.
|
|
3641
|
+
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3642
|
+
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3643
|
+
*/
|
|
3644
|
+
chatStream(messages, context) {
|
|
3645
|
+
return __asyncGenerator(this, null, function* () {
|
|
3646
|
+
var _a2, _b, _c;
|
|
3647
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3648
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3649
|
+
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3650
|
+
const formattedMessages = [
|
|
3651
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3652
|
+
|
|
3653
|
+
Context:
|
|
3654
|
+
${context != null ? context : "None"}` },
|
|
3655
|
+
...messages
|
|
3656
|
+
];
|
|
3657
|
+
let payload;
|
|
3658
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3659
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3660
|
+
model: this.model,
|
|
3661
|
+
messages: formattedMessages,
|
|
3662
|
+
maxTokens: this.maxTokens,
|
|
3663
|
+
temperature: this.temperature
|
|
3664
|
+
});
|
|
3665
|
+
if (typeof payload === "object" && payload !== null) {
|
|
3666
|
+
payload.stream = true;
|
|
3667
|
+
}
|
|
3668
|
+
} else {
|
|
3669
|
+
payload = {
|
|
3670
|
+
model: this.model,
|
|
3671
|
+
messages: formattedMessages,
|
|
3672
|
+
max_tokens: this.maxTokens,
|
|
3673
|
+
temperature: this.temperature,
|
|
3674
|
+
stream: true
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
const response = yield new __await(fetch(url, {
|
|
3678
|
+
method: "POST",
|
|
3679
|
+
headers: this.resolvedHeaders,
|
|
3680
|
+
body: JSON.stringify(payload)
|
|
3681
|
+
}));
|
|
3682
|
+
if (!response.ok) {
|
|
3683
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
3684
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3685
|
+
}
|
|
3686
|
+
if (!response.body) {
|
|
3687
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3688
|
+
}
|
|
3689
|
+
const reader = response.body.getReader();
|
|
3690
|
+
const decoder = new TextDecoder("utf-8");
|
|
3691
|
+
let buffer = "";
|
|
3692
|
+
try {
|
|
3693
|
+
while (true) {
|
|
3694
|
+
const { done, value } = yield new __await(reader.read());
|
|
3695
|
+
if (done) break;
|
|
3696
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3697
|
+
const lines = buffer.split("\n");
|
|
3698
|
+
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
3699
|
+
for (const line of lines) {
|
|
3700
|
+
const trimmed = line.trim();
|
|
3701
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
3702
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
3703
|
+
try {
|
|
3704
|
+
const json = JSON.parse(trimmed.slice(5).trim());
|
|
3705
|
+
const text = resolvePath(json, extractPath);
|
|
3706
|
+
if (text && typeof text === "string") yield text;
|
|
3707
|
+
} catch (e) {
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
if (buffer.trim() && buffer.trim() !== "data: [DONE]") {
|
|
3712
|
+
const jsonStr = buffer.replace(/^data:\s*/, "").trim();
|
|
3713
|
+
try {
|
|
3714
|
+
const json = JSON.parse(jsonStr);
|
|
3715
|
+
const text = resolvePath(json, extractPath);
|
|
3716
|
+
if (text && typeof text === "string") yield text;
|
|
3717
|
+
} catch (e) {
|
|
3350
3718
|
}
|
|
3351
3719
|
}
|
|
3352
3720
|
} finally {
|
|
@@ -3355,8 +3723,8 @@ ${context != null ? context : "None"}` },
|
|
|
3355
3723
|
});
|
|
3356
3724
|
}
|
|
3357
3725
|
async embed(text) {
|
|
3358
|
-
var
|
|
3359
|
-
const
|
|
3726
|
+
var _a2, _b;
|
|
3727
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3360
3728
|
let payload;
|
|
3361
3729
|
if (this.opts.embedPayloadTemplate) {
|
|
3362
3730
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3369,7 +3737,7 @@ ${context != null ? context : "None"}` },
|
|
|
3369
3737
|
input: text
|
|
3370
3738
|
};
|
|
3371
3739
|
}
|
|
3372
|
-
const { data } = await this.http.post(
|
|
3740
|
+
const { data } = await this.http.post(path2, payload);
|
|
3373
3741
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3374
3742
|
const vector = resolvePath(data, extractPath);
|
|
3375
3743
|
if (!Array.isArray(vector)) {
|
|
@@ -3437,13 +3805,13 @@ var AuthenticationException = class extends RetrivoraError {
|
|
|
3437
3805
|
}
|
|
3438
3806
|
};
|
|
3439
3807
|
function wrapError(err, defaultCode, defaultMessage) {
|
|
3440
|
-
var
|
|
3808
|
+
var _a2;
|
|
3441
3809
|
if (err instanceof RetrivoraError) {
|
|
3442
3810
|
return err;
|
|
3443
3811
|
}
|
|
3444
3812
|
const error = err;
|
|
3445
3813
|
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3446
|
-
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((
|
|
3814
|
+
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);
|
|
3447
3815
|
const code = error == null ? void 0 : error.code;
|
|
3448
3816
|
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3449
3817
|
return new RateLimitException(message, err);
|
|
@@ -3507,6 +3875,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3507
3875
|
"anthropic",
|
|
3508
3876
|
"ollama",
|
|
3509
3877
|
"gemini",
|
|
3878
|
+
"groq",
|
|
3879
|
+
"qwen",
|
|
3510
3880
|
"rest",
|
|
3511
3881
|
"universal_rest",
|
|
3512
3882
|
"custom",
|
|
@@ -3514,7 +3884,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3514
3884
|
];
|
|
3515
3885
|
}
|
|
3516
3886
|
static create(llmConfig, embeddingConfig) {
|
|
3517
|
-
var
|
|
3887
|
+
var _a2, _b, _c;
|
|
3518
3888
|
switch (llmConfig.provider) {
|
|
3519
3889
|
case "openai":
|
|
3520
3890
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3524,12 +3894,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3524
3894
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3525
3895
|
case "gemini":
|
|
3526
3896
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3897
|
+
case "groq":
|
|
3898
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3899
|
+
case "qwen":
|
|
3900
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3527
3901
|
case "rest":
|
|
3528
3902
|
case "universal_rest":
|
|
3529
3903
|
case "custom":
|
|
3530
3904
|
return new UniversalLLMAdapter(llmConfig);
|
|
3531
3905
|
default: {
|
|
3532
|
-
const providerName = String((
|
|
3906
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3533
3907
|
const customFactory = customProviders.get(providerName);
|
|
3534
3908
|
if (customFactory) {
|
|
3535
3909
|
return customFactory(llmConfig);
|
|
@@ -3566,6 +3940,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3566
3940
|
return OllamaProvider;
|
|
3567
3941
|
case "gemini":
|
|
3568
3942
|
return GeminiProvider;
|
|
3943
|
+
case "groq":
|
|
3944
|
+
return GroqProvider;
|
|
3945
|
+
case "qwen":
|
|
3946
|
+
return QwenProvider;
|
|
3569
3947
|
case "rest":
|
|
3570
3948
|
case "universal_rest":
|
|
3571
3949
|
case "custom":
|
|
@@ -3627,7 +4005,7 @@ var ProviderRegistry = class {
|
|
|
3627
4005
|
return null;
|
|
3628
4006
|
}
|
|
3629
4007
|
static async loadVectorProviderClass(provider) {
|
|
3630
|
-
var
|
|
4008
|
+
var _a2;
|
|
3631
4009
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3632
4010
|
switch (provider) {
|
|
3633
4011
|
case "pinecone": {
|
|
@@ -3636,7 +4014,7 @@ var ProviderRegistry = class {
|
|
|
3636
4014
|
}
|
|
3637
4015
|
case "pgvector":
|
|
3638
4016
|
case "postgresql": {
|
|
3639
|
-
const postgresMode = ((
|
|
4017
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3640
4018
|
if (postgresMode === "single") {
|
|
3641
4019
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3642
4020
|
return PostgreSQLProvider2;
|
|
@@ -4085,11 +4463,11 @@ var LlamaIndexIngestor = class {
|
|
|
4085
4463
|
* than standard character-count splitting.
|
|
4086
4464
|
*/
|
|
4087
4465
|
async chunk(text, options = {}) {
|
|
4088
|
-
var
|
|
4466
|
+
var _a2, _b;
|
|
4089
4467
|
try {
|
|
4090
4468
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4091
4469
|
const splitter = new SentenceSplitter({
|
|
4092
|
-
chunkSize: (
|
|
4470
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4093
4471
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4094
4472
|
});
|
|
4095
4473
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4198,7 +4576,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4198
4576
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4199
4577
|
*/
|
|
4200
4578
|
async run(input, chatHistory = []) {
|
|
4201
|
-
var
|
|
4579
|
+
var _a2, _b, _c;
|
|
4202
4580
|
if (!this.agent) {
|
|
4203
4581
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4204
4582
|
}
|
|
@@ -4209,7 +4587,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4209
4587
|
const response = await this.agent.invoke({
|
|
4210
4588
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4211
4589
|
});
|
|
4212
|
-
const lastMessage = (
|
|
4590
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4213
4591
|
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4214
4592
|
return lastMessage.content;
|
|
4215
4593
|
}
|
|
@@ -4220,6 +4598,437 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4220
4598
|
}
|
|
4221
4599
|
};
|
|
4222
4600
|
|
|
4601
|
+
// src/core/mcp.ts
|
|
4602
|
+
var import_child_process = require("child_process");
|
|
4603
|
+
var MCPClient = class {
|
|
4604
|
+
constructor(config) {
|
|
4605
|
+
this.config = config;
|
|
4606
|
+
this.messageIdCounter = 0;
|
|
4607
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4608
|
+
this.stdioBuffer = "";
|
|
4609
|
+
this.initialized = false;
|
|
4610
|
+
}
|
|
4611
|
+
getNextMessageId() {
|
|
4612
|
+
return ++this.messageIdCounter;
|
|
4613
|
+
}
|
|
4614
|
+
/**
|
|
4615
|
+
* Connect and initialize the MCP server connection.
|
|
4616
|
+
*/
|
|
4617
|
+
async connect() {
|
|
4618
|
+
if (this.initialized) return;
|
|
4619
|
+
if (this.config.transport === "stdio") {
|
|
4620
|
+
await this.connectStdio();
|
|
4621
|
+
} else {
|
|
4622
|
+
await this.connectSSE();
|
|
4623
|
+
}
|
|
4624
|
+
try {
|
|
4625
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4626
|
+
protocolVersion: "2024-11-05",
|
|
4627
|
+
capabilities: {},
|
|
4628
|
+
clientInfo: {
|
|
4629
|
+
name: "retrivora-sdk",
|
|
4630
|
+
version: "1.0.0"
|
|
4631
|
+
}
|
|
4632
|
+
});
|
|
4633
|
+
await this.sendNotification("notifications/initialized");
|
|
4634
|
+
this.initialized = true;
|
|
4635
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4636
|
+
} catch (err) {
|
|
4637
|
+
this.disconnect();
|
|
4638
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
async connectStdio() {
|
|
4642
|
+
var _a2;
|
|
4643
|
+
const cmd = this.config.command;
|
|
4644
|
+
if (!cmd) {
|
|
4645
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4646
|
+
}
|
|
4647
|
+
const args = this.config.args || [];
|
|
4648
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4649
|
+
this.childProcess = (0, import_child_process.spawn)(cmd, args, { env, shell: true });
|
|
4650
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4651
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4652
|
+
}
|
|
4653
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4654
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4655
|
+
this.processStdioLines();
|
|
4656
|
+
});
|
|
4657
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4658
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4659
|
+
});
|
|
4660
|
+
this.childProcess.on("close", (code) => {
|
|
4661
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4662
|
+
this.disconnect();
|
|
4663
|
+
});
|
|
4664
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4665
|
+
}
|
|
4666
|
+
processStdioLines() {
|
|
4667
|
+
let newlineIndex;
|
|
4668
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4669
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4670
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4671
|
+
if (!line) continue;
|
|
4672
|
+
try {
|
|
4673
|
+
const payload = JSON.parse(line);
|
|
4674
|
+
if (payload.id !== void 0) {
|
|
4675
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4676
|
+
if (req) {
|
|
4677
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4678
|
+
if (payload.error) {
|
|
4679
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4680
|
+
} else {
|
|
4681
|
+
req.resolve(payload.result);
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
} catch (e) {
|
|
4686
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
async connectSSE() {
|
|
4691
|
+
if (!this.config.url) {
|
|
4692
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4693
|
+
}
|
|
4694
|
+
this.sseUrl = this.config.url;
|
|
4695
|
+
}
|
|
4696
|
+
async sendJsonRpc(method, params) {
|
|
4697
|
+
const id = this.getNextMessageId();
|
|
4698
|
+
const request = {
|
|
4699
|
+
jsonrpc: "2.0",
|
|
4700
|
+
id,
|
|
4701
|
+
method,
|
|
4702
|
+
params
|
|
4703
|
+
};
|
|
4704
|
+
if (this.config.transport === "stdio") {
|
|
4705
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4706
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4707
|
+
}
|
|
4708
|
+
return new Promise((resolve, reject) => {
|
|
4709
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4710
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4711
|
+
});
|
|
4712
|
+
} else {
|
|
4713
|
+
if (!this.sseUrl) {
|
|
4714
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4715
|
+
}
|
|
4716
|
+
const response = await fetch(this.sseUrl, {
|
|
4717
|
+
method: "POST",
|
|
4718
|
+
headers: { "Content-Type": "application/json" },
|
|
4719
|
+
body: JSON.stringify(request)
|
|
4720
|
+
});
|
|
4721
|
+
if (!response.ok) {
|
|
4722
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4723
|
+
}
|
|
4724
|
+
const payload = await response.json();
|
|
4725
|
+
if (payload.error) {
|
|
4726
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4727
|
+
}
|
|
4728
|
+
return payload.result;
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
async sendNotification(method, params) {
|
|
4732
|
+
var _a2;
|
|
4733
|
+
const notification = {
|
|
4734
|
+
jsonrpc: "2.0",
|
|
4735
|
+
method,
|
|
4736
|
+
params
|
|
4737
|
+
};
|
|
4738
|
+
if (this.config.transport === "stdio") {
|
|
4739
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4740
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4741
|
+
}
|
|
4742
|
+
} else if (this.sseUrl) {
|
|
4743
|
+
await fetch(this.sseUrl, {
|
|
4744
|
+
method: "POST",
|
|
4745
|
+
headers: { "Content-Type": "application/json" },
|
|
4746
|
+
body: JSON.stringify(notification)
|
|
4747
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
/**
|
|
4751
|
+
* List all tools offered by the MCP server.
|
|
4752
|
+
*/
|
|
4753
|
+
async listTools() {
|
|
4754
|
+
await this.connect();
|
|
4755
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4756
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4757
|
+
}
|
|
4758
|
+
/**
|
|
4759
|
+
* Execute a tool on the MCP server.
|
|
4760
|
+
*/
|
|
4761
|
+
async callTool(name, args = {}) {
|
|
4762
|
+
await this.connect();
|
|
4763
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4764
|
+
}
|
|
4765
|
+
disconnect() {
|
|
4766
|
+
this.initialized = false;
|
|
4767
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4768
|
+
this.pendingRequests.clear();
|
|
4769
|
+
if (this.childProcess) {
|
|
4770
|
+
try {
|
|
4771
|
+
this.childProcess.kill();
|
|
4772
|
+
} catch (e) {
|
|
4773
|
+
}
|
|
4774
|
+
this.childProcess = void 0;
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
};
|
|
4778
|
+
var MCPRegistry = class {
|
|
4779
|
+
constructor(servers = []) {
|
|
4780
|
+
this.clients = [];
|
|
4781
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4782
|
+
}
|
|
4783
|
+
async getAllTools() {
|
|
4784
|
+
const list = [];
|
|
4785
|
+
await Promise.all(
|
|
4786
|
+
this.clients.map(async (client) => {
|
|
4787
|
+
try {
|
|
4788
|
+
const tools = await client.listTools();
|
|
4789
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4790
|
+
} catch (e) {
|
|
4791
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4792
|
+
}
|
|
4793
|
+
})
|
|
4794
|
+
);
|
|
4795
|
+
return list;
|
|
4796
|
+
}
|
|
4797
|
+
async callTool(toolName, args = {}) {
|
|
4798
|
+
for (const client of this.clients) {
|
|
4799
|
+
try {
|
|
4800
|
+
const tools = await client.listTools();
|
|
4801
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4802
|
+
return await client.callTool(toolName, args);
|
|
4803
|
+
}
|
|
4804
|
+
} catch (e) {
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4808
|
+
}
|
|
4809
|
+
disconnectAll() {
|
|
4810
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4811
|
+
}
|
|
4812
|
+
};
|
|
4813
|
+
|
|
4814
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4815
|
+
var MultiAgentCoordinator = class {
|
|
4816
|
+
constructor(options) {
|
|
4817
|
+
var _a2;
|
|
4818
|
+
this.llmProvider = options.llmProvider;
|
|
4819
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4820
|
+
this.documentSearch = options.documentSearch;
|
|
4821
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
4822
|
+
}
|
|
4823
|
+
/**
|
|
4824
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
4825
|
+
*/
|
|
4826
|
+
async run(question, history = []) {
|
|
4827
|
+
const generator = this.runStream(question, history);
|
|
4828
|
+
let finalReply = "";
|
|
4829
|
+
const sources = [];
|
|
4830
|
+
try {
|
|
4831
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4832
|
+
const chunk = temp.value;
|
|
4833
|
+
if (typeof chunk === "string") {
|
|
4834
|
+
finalReply += chunk;
|
|
4835
|
+
} else if (chunk && typeof chunk === "object") {
|
|
4836
|
+
if ("reply" in chunk && chunk.reply) {
|
|
4837
|
+
finalReply += chunk.reply;
|
|
4838
|
+
}
|
|
4839
|
+
if ("sources" in chunk && chunk.sources) {
|
|
4840
|
+
sources.push(...chunk.sources);
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
} catch (temp) {
|
|
4845
|
+
error = [temp];
|
|
4846
|
+
} finally {
|
|
4847
|
+
try {
|
|
4848
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4849
|
+
} finally {
|
|
4850
|
+
if (error)
|
|
4851
|
+
throw error[0];
|
|
4852
|
+
}
|
|
4853
|
+
}
|
|
4854
|
+
return {
|
|
4855
|
+
reply: finalReply,
|
|
4856
|
+
sources
|
|
4857
|
+
};
|
|
4858
|
+
}
|
|
4859
|
+
/**
|
|
4860
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
4861
|
+
*/
|
|
4862
|
+
runStream(_0) {
|
|
4863
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
4864
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
4865
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
4866
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
4867
|
+
|
|
4868
|
+
Available Tools:
|
|
4869
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
4870
|
+
|
|
4871
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
4872
|
+
${mcpTools.map((mt) => {
|
|
4873
|
+
var _a2;
|
|
4874
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
4875
|
+
}).join("\n")}
|
|
4876
|
+
|
|
4877
|
+
Tool Calling Protocol:
|
|
4878
|
+
If you need to call a tool, write:
|
|
4879
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
4880
|
+
And then STOP generating immediately.
|
|
4881
|
+
|
|
4882
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
4883
|
+
`;
|
|
4884
|
+
const supervisorHistory = [
|
|
4885
|
+
{ role: "system", content: systemPrompt },
|
|
4886
|
+
...history,
|
|
4887
|
+
{ role: "user", content: question }
|
|
4888
|
+
];
|
|
4889
|
+
let iteration = 0;
|
|
4890
|
+
const allSources = [];
|
|
4891
|
+
while (iteration < this.maxIterations) {
|
|
4892
|
+
iteration++;
|
|
4893
|
+
const context = "";
|
|
4894
|
+
let fullModelResponse = "";
|
|
4895
|
+
let textBuffer = "";
|
|
4896
|
+
let inThinking = false;
|
|
4897
|
+
let toolCallDetected = null;
|
|
4898
|
+
if (!this.llmProvider.chatStream) {
|
|
4899
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
4900
|
+
fullModelResponse = reply;
|
|
4901
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
4902
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
4903
|
+
let thinkingText = "";
|
|
4904
|
+
let answerText = reply;
|
|
4905
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
4906
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
4907
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
4908
|
+
yield { type: "thinking", text: thinkingText };
|
|
4909
|
+
}
|
|
4910
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4911
|
+
if (toolMatch) {
|
|
4912
|
+
const toolName = toolMatch[1];
|
|
4913
|
+
const toolArgsStr = toolMatch[2];
|
|
4914
|
+
try {
|
|
4915
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4916
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4917
|
+
} catch (e) {
|
|
4918
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4919
|
+
}
|
|
4920
|
+
} else {
|
|
4921
|
+
yield answerText;
|
|
4922
|
+
}
|
|
4923
|
+
} else {
|
|
4924
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
4925
|
+
try {
|
|
4926
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
4927
|
+
const chunk = temp.value;
|
|
4928
|
+
fullModelResponse += chunk;
|
|
4929
|
+
textBuffer += chunk;
|
|
4930
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
4931
|
+
inThinking = true;
|
|
4932
|
+
const idx = textBuffer.indexOf("<think>");
|
|
4933
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
4934
|
+
}
|
|
4935
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
4936
|
+
inThinking = false;
|
|
4937
|
+
const idx = textBuffer.indexOf("</think>");
|
|
4938
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
4939
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
4940
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
4941
|
+
}
|
|
4942
|
+
if (inThinking && textBuffer.length > 0) {
|
|
4943
|
+
yield { type: "thinking", text: textBuffer };
|
|
4944
|
+
textBuffer = "";
|
|
4945
|
+
}
|
|
4946
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
4947
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
4948
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
4949
|
+
if (precedingText.trim()) {
|
|
4950
|
+
yield precedingText;
|
|
4951
|
+
}
|
|
4952
|
+
textBuffer = textBuffer.slice(idx);
|
|
4953
|
+
}
|
|
4954
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
4955
|
+
yield textBuffer;
|
|
4956
|
+
textBuffer = "";
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
} catch (temp) {
|
|
4960
|
+
error = [temp];
|
|
4961
|
+
} finally {
|
|
4962
|
+
try {
|
|
4963
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
4964
|
+
} finally {
|
|
4965
|
+
if (error)
|
|
4966
|
+
throw error[0];
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
if (textBuffer.trim()) {
|
|
4970
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4971
|
+
if (toolMatch) {
|
|
4972
|
+
const toolName = toolMatch[1];
|
|
4973
|
+
const toolArgsStr = toolMatch[2];
|
|
4974
|
+
try {
|
|
4975
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4976
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4977
|
+
} catch (e) {
|
|
4978
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4979
|
+
}
|
|
4980
|
+
} else {
|
|
4981
|
+
yield textBuffer;
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
4986
|
+
if (toolCallDetected) {
|
|
4987
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
4988
|
+
yield {
|
|
4989
|
+
type: "thinking",
|
|
4990
|
+
text: `
|
|
4991
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
4992
|
+
`
|
|
4993
|
+
};
|
|
4994
|
+
let toolResultText = "";
|
|
4995
|
+
try {
|
|
4996
|
+
if (toolName === "document_search") {
|
|
4997
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
4998
|
+
toolResultText = `document_search returned:
|
|
4999
|
+
${searchRes.reply}
|
|
5000
|
+
|
|
5001
|
+
Sources count: ${searchRes.sources.length}`;
|
|
5002
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
5003
|
+
allSources.push(...searchRes.sources);
|
|
5004
|
+
yield { reply: "", sources: searchRes.sources };
|
|
5005
|
+
}
|
|
5006
|
+
} else {
|
|
5007
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
5008
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
5009
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
5010
|
+
}
|
|
5011
|
+
} catch (err) {
|
|
5012
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
5013
|
+
}
|
|
5014
|
+
supervisorHistory.push({
|
|
5015
|
+
role: "user",
|
|
5016
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
5017
|
+
${toolResultText}`
|
|
5018
|
+
});
|
|
5019
|
+
yield {
|
|
5020
|
+
type: "thinking",
|
|
5021
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
5022
|
+
`
|
|
5023
|
+
};
|
|
5024
|
+
} else {
|
|
5025
|
+
break;
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
});
|
|
5029
|
+
}
|
|
5030
|
+
};
|
|
5031
|
+
|
|
4223
5032
|
// src/core/BatchProcessor.ts
|
|
4224
5033
|
function isTransientError(error) {
|
|
4225
5034
|
if (!(error instanceof Error)) return false;
|
|
@@ -4540,7 +5349,7 @@ var QueryProcessor = class {
|
|
|
4540
5349
|
* @param validFields Optional list of known filterable fields to look for
|
|
4541
5350
|
*/
|
|
4542
5351
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4543
|
-
var
|
|
5352
|
+
var _a2, _b, _c, _d;
|
|
4544
5353
|
if (!question.trim()) return [];
|
|
4545
5354
|
const hints = /* @__PURE__ */ new Map();
|
|
4546
5355
|
const addHint = (value, field) => {
|
|
@@ -4620,7 +5429,7 @@ var QueryProcessor = class {
|
|
|
4620
5429
|
];
|
|
4621
5430
|
for (const p of universalPatterns) {
|
|
4622
5431
|
for (const match of question.matchAll(p.regex)) {
|
|
4623
|
-
const val = p.group ? (
|
|
5432
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4624
5433
|
if (!val) continue;
|
|
4625
5434
|
if (p.field) addHint(val, p.field);
|
|
4626
5435
|
else addHint(val);
|
|
@@ -4844,11 +5653,11 @@ var LLMRouter = class {
|
|
|
4844
5653
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4845
5654
|
*/
|
|
4846
5655
|
async initialize(prebuiltDefault) {
|
|
4847
|
-
var
|
|
5656
|
+
var _a2;
|
|
4848
5657
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4849
5658
|
this.models.set("default", defaultModel);
|
|
4850
5659
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4851
|
-
const providerFastDefault = (
|
|
5660
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4852
5661
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4853
5662
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4854
5663
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4867,8 +5676,8 @@ var LLMRouter = class {
|
|
|
4867
5676
|
* Falls back to 'default' if the requested role is not registered.
|
|
4868
5677
|
*/
|
|
4869
5678
|
get(role) {
|
|
4870
|
-
var
|
|
4871
|
-
const provider = (
|
|
5679
|
+
var _a2;
|
|
5680
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4872
5681
|
if (!provider) {
|
|
4873
5682
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4874
5683
|
}
|
|
@@ -4886,7 +5695,7 @@ var UITransformer = class _UITransformer {
|
|
|
4886
5695
|
* Prefer `analyzeAndDecide()` in production.
|
|
4887
5696
|
*/
|
|
4888
5697
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4889
|
-
var
|
|
5698
|
+
var _a2, _b, _c;
|
|
4890
5699
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4891
5700
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4892
5701
|
}
|
|
@@ -4906,7 +5715,7 @@ var UITransformer = class _UITransformer {
|
|
|
4906
5715
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4907
5716
|
}
|
|
4908
5717
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4909
|
-
return (
|
|
5718
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4910
5719
|
}
|
|
4911
5720
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4912
5721
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5231,11 +6040,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5231
6040
|
};
|
|
5232
6041
|
}
|
|
5233
6042
|
static transformToPieChart(data, profile, query = "") {
|
|
5234
|
-
var
|
|
6043
|
+
var _a2;
|
|
5235
6044
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5236
6045
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5237
|
-
var
|
|
5238
|
-
return String((
|
|
6046
|
+
var _a3;
|
|
6047
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5239
6048
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5240
6049
|
if (categories.length === 0) return null;
|
|
5241
6050
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5245,7 +6054,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5245
6054
|
});
|
|
5246
6055
|
return {
|
|
5247
6056
|
type: "pie_chart",
|
|
5248
|
-
title: `Distribution by ${(
|
|
6057
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5249
6058
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5250
6059
|
data: pieData
|
|
5251
6060
|
};
|
|
@@ -5255,8 +6064,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5255
6064
|
const valueField = profile.numericFields[0];
|
|
5256
6065
|
const buckets = /* @__PURE__ */ new Map();
|
|
5257
6066
|
profile.records.forEach((record) => {
|
|
5258
|
-
var
|
|
5259
|
-
const timestamp = String((
|
|
6067
|
+
var _a2, _b, _c;
|
|
6068
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5260
6069
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5261
6070
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5262
6071
|
});
|
|
@@ -5269,23 +6078,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5269
6078
|
};
|
|
5270
6079
|
}
|
|
5271
6080
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5272
|
-
var
|
|
6081
|
+
var _a2;
|
|
5273
6082
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5274
6083
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5275
6084
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5276
6085
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5277
6086
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5278
|
-
var
|
|
6087
|
+
var _a3, _b, _c, _d, _e;
|
|
5279
6088
|
const meta = item.metadata || {};
|
|
5280
6089
|
const label = String(
|
|
5281
|
-
(_c = (_b = (
|
|
6090
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5282
6091
|
);
|
|
5283
6092
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5284
6093
|
return { category: label, value: Number(value) };
|
|
5285
6094
|
});
|
|
5286
6095
|
return {
|
|
5287
6096
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5288
|
-
title: dimension ? `${(
|
|
6097
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5289
6098
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5290
6099
|
data: fallbackData
|
|
5291
6100
|
};
|
|
@@ -5320,11 +6129,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5320
6129
|
if (fields.length < 2) return null;
|
|
5321
6130
|
const [xField, yField] = fields;
|
|
5322
6131
|
const points = profile.records.map((record) => {
|
|
5323
|
-
var
|
|
6132
|
+
var _a2;
|
|
5324
6133
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5325
6134
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5326
6135
|
if (x === null || y === null) return null;
|
|
5327
|
-
return { x, y, label: String((
|
|
6136
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5328
6137
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5329
6138
|
if (points.length === 0) return null;
|
|
5330
6139
|
return {
|
|
@@ -5354,9 +6163,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5354
6163
|
static transformToRadarChart(data) {
|
|
5355
6164
|
const attributeMap = {};
|
|
5356
6165
|
data.forEach((item) => {
|
|
5357
|
-
var
|
|
6166
|
+
var _a2, _b, _c;
|
|
5358
6167
|
const meta = item.metadata || {};
|
|
5359
|
-
const seriesName = String((_c = (_b = (
|
|
6168
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5360
6169
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5361
6170
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5362
6171
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5438,22 +6247,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5438
6247
|
return null;
|
|
5439
6248
|
}
|
|
5440
6249
|
static normalizeTransformation(payload) {
|
|
5441
|
-
var
|
|
6250
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5442
6251
|
if (!payload || typeof payload !== "object") return null;
|
|
5443
6252
|
const p = payload;
|
|
5444
6253
|
const type = this.normalizeVisualizationType(
|
|
5445
|
-
String((_c = (_b = (
|
|
6254
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5446
6255
|
);
|
|
5447
6256
|
if (!type) return null;
|
|
5448
6257
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5449
6258
|
const description = p.description ? String(p.description) : void 0;
|
|
5450
|
-
const rawData = (_j = (_i = (_h = (
|
|
6259
|
+
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;
|
|
5451
6260
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5452
6261
|
const transformation = { type, title, description, data };
|
|
5453
6262
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5454
6263
|
}
|
|
5455
6264
|
static normalizeVisualizationType(type) {
|
|
5456
|
-
var
|
|
6265
|
+
var _a2;
|
|
5457
6266
|
const mapping = {
|
|
5458
6267
|
pie: "pie_chart",
|
|
5459
6268
|
pie_chart: "pie_chart",
|
|
@@ -5481,7 +6290,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5481
6290
|
product_carousel: "product_carousel",
|
|
5482
6291
|
carousel: "carousel"
|
|
5483
6292
|
};
|
|
5484
|
-
return (
|
|
6293
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5485
6294
|
}
|
|
5486
6295
|
static validateTransformation(t) {
|
|
5487
6296
|
const { type, data } = t;
|
|
@@ -5683,16 +6492,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5683
6492
|
return null;
|
|
5684
6493
|
}
|
|
5685
6494
|
static selectDimensionField(profile, query) {
|
|
5686
|
-
var
|
|
6495
|
+
var _a2, _b;
|
|
5687
6496
|
const productCategory = profile.categoricalFields.find(
|
|
5688
6497
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5689
6498
|
);
|
|
5690
6499
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5691
|
-
return (_b = (
|
|
6500
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5692
6501
|
}
|
|
5693
6502
|
static selectNumericField(profile, query) {
|
|
5694
|
-
var
|
|
5695
|
-
return (
|
|
6503
|
+
var _a2;
|
|
6504
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5696
6505
|
}
|
|
5697
6506
|
static rankFieldsByQuery(fields, query) {
|
|
5698
6507
|
const q = query.toLowerCase();
|
|
@@ -5721,8 +6530,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5721
6530
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5722
6531
|
const result = {};
|
|
5723
6532
|
profile.records.forEach((record) => {
|
|
5724
|
-
var
|
|
5725
|
-
const category = String((
|
|
6533
|
+
var _a2, _b, _c;
|
|
6534
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5726
6535
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5727
6536
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5728
6537
|
});
|
|
@@ -5801,8 +6610,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5801
6610
|
static aggregateByCategory(data, categories) {
|
|
5802
6611
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5803
6612
|
data.forEach((item) => {
|
|
5804
|
-
var
|
|
5805
|
-
const cat = (
|
|
6613
|
+
var _a2;
|
|
6614
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5806
6615
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5807
6616
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5808
6617
|
});
|
|
@@ -5810,17 +6619,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5810
6619
|
}
|
|
5811
6620
|
static extractTimeSeriesData(data) {
|
|
5812
6621
|
return data.map((item) => {
|
|
5813
|
-
var
|
|
6622
|
+
var _a2, _b, _c, _d, _e;
|
|
5814
6623
|
const meta = item.metadata || {};
|
|
5815
6624
|
return {
|
|
5816
|
-
timestamp: (_b = (
|
|
6625
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5817
6626
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5818
6627
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5819
6628
|
};
|
|
5820
6629
|
});
|
|
5821
6630
|
}
|
|
5822
6631
|
static extractNumericValue(meta) {
|
|
5823
|
-
var
|
|
6632
|
+
var _a2;
|
|
5824
6633
|
const preferredKeys = [
|
|
5825
6634
|
"value",
|
|
5826
6635
|
"count",
|
|
@@ -5835,7 +6644,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5835
6644
|
"price"
|
|
5836
6645
|
];
|
|
5837
6646
|
for (const key of preferredKeys) {
|
|
5838
|
-
const raw = (
|
|
6647
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5839
6648
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5840
6649
|
if (Number.isFinite(value)) return value;
|
|
5841
6650
|
}
|
|
@@ -5981,8 +6790,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5981
6790
|
let inStock = 0;
|
|
5982
6791
|
let outOfStock = 0;
|
|
5983
6792
|
data.forEach((d) => {
|
|
5984
|
-
var
|
|
5985
|
-
const cat = (
|
|
6793
|
+
var _a2, _b;
|
|
6794
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
5986
6795
|
if (cat === category) {
|
|
5987
6796
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
5988
6797
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -6026,9 +6835,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
6026
6835
|
}
|
|
6027
6836
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
6028
6837
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
6029
|
-
var
|
|
6838
|
+
var _a2;
|
|
6030
6839
|
if (!meta) return void 0;
|
|
6031
|
-
const mapping = (
|
|
6840
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
6032
6841
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
6033
6842
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
6034
6843
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -6037,13 +6846,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6037
6846
|
return resolveMetadataValue(meta, uiKey);
|
|
6038
6847
|
}
|
|
6039
6848
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6040
|
-
var
|
|
6849
|
+
var _a2;
|
|
6041
6850
|
const meta = item.metadata || {};
|
|
6042
6851
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6043
6852
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6044
6853
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6045
6854
|
const description = this.cleanProductDescription(
|
|
6046
|
-
(
|
|
6855
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6047
6856
|
);
|
|
6048
6857
|
if (name || this.isProductData(item)) {
|
|
6049
6858
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6151,10 +6960,10 @@ RULES:
|
|
|
6151
6960
|
}
|
|
6152
6961
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6153
6962
|
const items = sources.map((s, i) => {
|
|
6154
|
-
var
|
|
6963
|
+
var _a2, _b, _c, _d;
|
|
6155
6964
|
return {
|
|
6156
6965
|
index: i + 1,
|
|
6157
|
-
content: (_b = (
|
|
6966
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6158
6967
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6159
6968
|
score: (_d = s.score) != null ? _d : 0
|
|
6160
6969
|
};
|
|
@@ -6347,9 +7156,11 @@ var Pipeline = class {
|
|
|
6347
7156
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6348
7157
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6349
7158
|
this.initialised = false;
|
|
6350
|
-
|
|
7159
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7160
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7161
|
+
var _a2, _b, _c, _d, _e;
|
|
6351
7162
|
this.chunker = new DocumentChunker(
|
|
6352
|
-
(_b = (
|
|
7163
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6353
7164
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6354
7165
|
);
|
|
6355
7166
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6365,7 +7176,7 @@ var Pipeline = class {
|
|
|
6365
7176
|
return this.initialised ? this.llmProvider : void 0;
|
|
6366
7177
|
}
|
|
6367
7178
|
async initialize() {
|
|
6368
|
-
var
|
|
7179
|
+
var _a2, _b, _c, _d;
|
|
6369
7180
|
if (this.initialised) return;
|
|
6370
7181
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6371
7182
|
|
|
@@ -6408,12 +7219,47 @@ var Pipeline = class {
|
|
|
6408
7219
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6409
7220
|
}
|
|
6410
7221
|
await this.vectorDB.initialize();
|
|
6411
|
-
if (((
|
|
7222
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7223
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7224
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7225
|
+
llmProvider: this.llmProvider,
|
|
7226
|
+
mcpRegistry: this.mcpRegistry,
|
|
7227
|
+
documentSearch: async (query) => {
|
|
7228
|
+
return this.runNormalQuery(query);
|
|
7229
|
+
}
|
|
7230
|
+
});
|
|
6412
7231
|
this.agent = new LangChainAgent(this, this.config);
|
|
6413
7232
|
await this.agent.initialize(this.llmProvider);
|
|
6414
7233
|
}
|
|
7234
|
+
if ((_d = (_c = this.config.rag) == null ? void 0 : _c.cag) == null ? void 0 : _d.enabled) {
|
|
7235
|
+
await this.loadColdContext(this.config.projectId);
|
|
7236
|
+
}
|
|
6415
7237
|
this.initialised = true;
|
|
6416
7238
|
}
|
|
7239
|
+
async loadColdContext(ns) {
|
|
7240
|
+
var _a2, _b;
|
|
7241
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7242
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7243
|
+
try {
|
|
7244
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7245
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7246
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7247
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7248
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7249
|
+
if (coldMatches.length > 0) {
|
|
7250
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7251
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7252
|
+
this.coldContexts.set(ns, formatted);
|
|
7253
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7254
|
+
} else {
|
|
7255
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7256
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7257
|
+
}
|
|
7258
|
+
} catch (err) {
|
|
7259
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7260
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7261
|
+
}
|
|
7262
|
+
}
|
|
6417
7263
|
/**
|
|
6418
7264
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6419
7265
|
*/
|
|
@@ -6445,12 +7291,12 @@ var Pipeline = class {
|
|
|
6445
7291
|
}
|
|
6446
7292
|
/** Step 1: Chunk the document content. */
|
|
6447
7293
|
async prepareChunks(doc) {
|
|
6448
|
-
var
|
|
7294
|
+
var _a2, _b;
|
|
6449
7295
|
if (this.llamaIngestor) {
|
|
6450
7296
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6451
7297
|
docId: doc.docId,
|
|
6452
7298
|
metadata: doc.metadata,
|
|
6453
|
-
chunkSize: (
|
|
7299
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6454
7300
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6455
7301
|
});
|
|
6456
7302
|
}
|
|
@@ -6521,12 +7367,37 @@ var Pipeline = class {
|
|
|
6521
7367
|
extractionOptions
|
|
6522
7368
|
);
|
|
6523
7369
|
}
|
|
7370
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7371
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7372
|
+
let reply = "";
|
|
7373
|
+
let sources = [];
|
|
7374
|
+
try {
|
|
7375
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7376
|
+
const chunk = temp.value;
|
|
7377
|
+
if (typeof chunk === "string") {
|
|
7378
|
+
reply += chunk;
|
|
7379
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7380
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7381
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7382
|
+
}
|
|
7383
|
+
}
|
|
7384
|
+
} catch (temp) {
|
|
7385
|
+
error = [temp];
|
|
7386
|
+
} finally {
|
|
7387
|
+
try {
|
|
7388
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7389
|
+
} finally {
|
|
7390
|
+
if (error)
|
|
7391
|
+
throw error[0];
|
|
7392
|
+
}
|
|
7393
|
+
}
|
|
7394
|
+
return { reply, sources };
|
|
7395
|
+
}
|
|
6524
7396
|
async ask(question, history = [], namespace) {
|
|
6525
|
-
var
|
|
7397
|
+
var _a2, _b;
|
|
6526
7398
|
await this.initialize();
|
|
6527
|
-
if (((
|
|
6528
|
-
|
|
6529
|
-
return { reply: agentReply, sources: [] };
|
|
7399
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7400
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6530
7401
|
}
|
|
6531
7402
|
const stream = this.askStream(question, history, namespace);
|
|
6532
7403
|
let reply = "";
|
|
@@ -6546,17 +7417,58 @@ var Pipeline = class {
|
|
|
6546
7417
|
if ("trace" in chunk) trace = chunk.trace;
|
|
6547
7418
|
}
|
|
6548
7419
|
}
|
|
6549
|
-
} catch (temp) {
|
|
6550
|
-
error = [temp];
|
|
6551
|
-
} finally {
|
|
7420
|
+
} catch (temp) {
|
|
7421
|
+
error = [temp];
|
|
7422
|
+
} finally {
|
|
7423
|
+
try {
|
|
7424
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7425
|
+
} finally {
|
|
7426
|
+
if (error)
|
|
7427
|
+
throw error[0];
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7431
|
+
}
|
|
7432
|
+
askStream(_0) {
|
|
7433
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7434
|
+
var _a2, _b;
|
|
7435
|
+
yield new __await(this.initialize());
|
|
7436
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7437
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7438
|
+
try {
|
|
7439
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7440
|
+
const chunk = temp.value;
|
|
7441
|
+
yield chunk;
|
|
7442
|
+
}
|
|
7443
|
+
} catch (temp) {
|
|
7444
|
+
error = [temp];
|
|
7445
|
+
} finally {
|
|
7446
|
+
try {
|
|
7447
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7448
|
+
} finally {
|
|
7449
|
+
if (error)
|
|
7450
|
+
throw error[0];
|
|
7451
|
+
}
|
|
7452
|
+
}
|
|
7453
|
+
return;
|
|
7454
|
+
}
|
|
7455
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
6552
7456
|
try {
|
|
6553
|
-
|
|
7457
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7458
|
+
const chunk = temp2.value;
|
|
7459
|
+
yield chunk;
|
|
7460
|
+
}
|
|
7461
|
+
} catch (temp2) {
|
|
7462
|
+
error2 = [temp2];
|
|
6554
7463
|
} finally {
|
|
6555
|
-
|
|
6556
|
-
|
|
7464
|
+
try {
|
|
7465
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7466
|
+
} finally {
|
|
7467
|
+
if (error2)
|
|
7468
|
+
throw error2[0];
|
|
7469
|
+
}
|
|
6557
7470
|
}
|
|
6558
|
-
}
|
|
6559
|
-
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7471
|
+
});
|
|
6560
7472
|
}
|
|
6561
7473
|
/**
|
|
6562
7474
|
* High-performance streaming RAG flow.
|
|
@@ -6568,12 +7480,12 @@ var Pipeline = class {
|
|
|
6568
7480
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6569
7481
|
* - SchemaMapper.train runs while answer generation streams
|
|
6570
7482
|
*/
|
|
6571
|
-
|
|
7483
|
+
askStreamInternal(_0) {
|
|
6572
7484
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6573
|
-
var
|
|
7485
|
+
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;
|
|
6574
7486
|
yield new __await(this.initialize());
|
|
6575
7487
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6576
|
-
const topK = (_b = (
|
|
7488
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6577
7489
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6578
7490
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6579
7491
|
const requestStart = performance.now();
|
|
@@ -6586,20 +7498,21 @@ var Pipeline = class {
|
|
|
6586
7498
|
}
|
|
6587
7499
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6588
7500
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6589
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7501
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6590
7502
|
if (numericPredicates.length > 0) {
|
|
6591
7503
|
filter.__numericPredicates = numericPredicates;
|
|
6592
7504
|
}
|
|
6593
7505
|
const embedStart = performance.now();
|
|
6594
7506
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6595
7507
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6596
|
-
const
|
|
7508
|
+
const arch = (_h = this.config.rag) == null ? void 0 : _h.architecture;
|
|
7509
|
+
const useGraph = arch !== "naive" && arch !== "retrieve-and-rerank" && this.graphDB && ((_i = this.config.rag) == null ? void 0 : _i.useGraphRetrieval);
|
|
6597
7510
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6598
7511
|
QueryProcessor.determineRetrievalStrategy(
|
|
6599
7512
|
searchQuery,
|
|
6600
7513
|
useGraph ? this.llmRouter.get("fast") : void 0,
|
|
6601
|
-
(
|
|
6602
|
-
(
|
|
7514
|
+
(_j = this.config.rag) == null ? void 0 : _j.graphKeywords,
|
|
7515
|
+
(_k = this.config.rag) == null ? void 0 : _k.vectorKeywords
|
|
6603
7516
|
),
|
|
6604
7517
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6605
7518
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6609,7 +7522,7 @@ var Pipeline = class {
|
|
|
6609
7522
|
if (!cachedVector && queryVector.length > 0) {
|
|
6610
7523
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6611
7524
|
}
|
|
6612
|
-
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((
|
|
7525
|
+
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_l = this.config.rag) == null ? void 0 : _l.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
|
|
6613
7526
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6614
7527
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6615
7528
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6622,7 +7535,8 @@ var Pipeline = class {
|
|
|
6622
7535
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6623
7536
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6624
7537
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6625
|
-
|
|
7538
|
+
const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
|
|
7539
|
+
if (!hasNumericPredicates && useReranking) {
|
|
6626
7540
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6627
7541
|
} else if (!wantsExhaustiveList) {
|
|
6628
7542
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6652,6 +7566,32 @@ ${graphContext}
|
|
|
6652
7566
|
VECTOR CONTEXT:
|
|
6653
7567
|
${context}`;
|
|
6654
7568
|
}
|
|
7569
|
+
if ((_o = (_n = this.config.rag) == null ? void 0 : _n.cag) == null ? void 0 : _o.enabled) {
|
|
7570
|
+
if (!this.coldContexts.has(ns)) {
|
|
7571
|
+
yield new __await(this.loadColdContext(ns));
|
|
7572
|
+
}
|
|
7573
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7574
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7575
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7576
|
+
${coldContext}
|
|
7577
|
+
|
|
7578
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7579
|
+
${context}`;
|
|
7580
|
+
}
|
|
7581
|
+
}
|
|
7582
|
+
yield {
|
|
7583
|
+
reply: "",
|
|
7584
|
+
sources: sources.map((s) => {
|
|
7585
|
+
var _a3;
|
|
7586
|
+
return {
|
|
7587
|
+
id: s.id,
|
|
7588
|
+
score: s.score,
|
|
7589
|
+
content: s.content,
|
|
7590
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7591
|
+
namespace: ns
|
|
7592
|
+
};
|
|
7593
|
+
})
|
|
7594
|
+
};
|
|
6655
7595
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6656
7596
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6657
7597
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6679,10 +7619,10 @@ ${context}`;
|
|
|
6679
7619
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6680
7620
|
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.)";
|
|
6681
7621
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6682
|
-
const isNativeThinking = isClaude37 && (((
|
|
7622
|
+
const isNativeThinking = isClaude37 && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
|
|
6683
7623
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6684
7624
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6685
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7625
|
+
const isSimulatedThinking = !isNativeThinking && (((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === true || ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) === "enabled" || isReasoningModel && ((_u = this.config.llm.options) == null ? void 0 : _u.thinking) !== false);
|
|
6686
7626
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6687
7627
|
if (isSimulatedThinking) {
|
|
6688
7628
|
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.`)";
|
|
@@ -6690,7 +7630,7 @@ ${context}`;
|
|
|
6690
7630
|
const hardenedHistory = [...history];
|
|
6691
7631
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6692
7632
|
const messages = [...hardenedHistory, userQuestion];
|
|
6693
|
-
const systemPrompt = (
|
|
7633
|
+
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
6694
7634
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6695
7635
|
let fullReply = "";
|
|
6696
7636
|
let thinkingText = "";
|
|
@@ -6801,7 +7741,7 @@ ${context}`;
|
|
|
6801
7741
|
}
|
|
6802
7742
|
yield fullReply;
|
|
6803
7743
|
}
|
|
6804
|
-
const runHallucination = ((
|
|
7744
|
+
const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_x = this.config.llm.options) == null ? void 0 : _x.hallucinationScoring) !== false;
|
|
6805
7745
|
if (runHallucination) {
|
|
6806
7746
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6807
7747
|
}
|
|
@@ -6810,7 +7750,7 @@ ${context}`;
|
|
|
6810
7750
|
const latency = {
|
|
6811
7751
|
embedMs: Math.round(embedMs),
|
|
6812
7752
|
retrieveMs: Math.round(retrieveMs),
|
|
6813
|
-
rerankMs: ((
|
|
7753
|
+
rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
|
|
6814
7754
|
generateMs: Math.round(generateMs),
|
|
6815
7755
|
totalMs: Math.round(totalMs)
|
|
6816
7756
|
};
|
|
@@ -6823,33 +7763,63 @@ ${context}`;
|
|
|
6823
7763
|
totalTokens: promptTokens + completionTokens,
|
|
6824
7764
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6825
7765
|
};
|
|
7766
|
+
const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
|
|
6826
7767
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6827
7768
|
uiTransformationPromise,
|
|
6828
|
-
hallucinationScoringPromise
|
|
7769
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6829
7770
|
]));
|
|
6830
|
-
const
|
|
7771
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6831
7772
|
requestId,
|
|
6832
7773
|
query: question,
|
|
6833
7774
|
rewrittenQuery,
|
|
6834
7775
|
systemPrompt,
|
|
6835
7776
|
userPrompt: question + finalRestrictionSuffix,
|
|
6836
7777
|
chunks: sources.map((s) => {
|
|
6837
|
-
var
|
|
7778
|
+
var _a3;
|
|
6838
7779
|
return {
|
|
6839
7780
|
id: s.id,
|
|
6840
7781
|
score: s.score,
|
|
6841
7782
|
content: s.content,
|
|
6842
|
-
metadata: (
|
|
7783
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6843
7784
|
namespace: ns
|
|
6844
7785
|
};
|
|
6845
7786
|
}),
|
|
6846
7787
|
latency,
|
|
6847
7788
|
tokens,
|
|
6848
7789
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6849
|
-
},
|
|
6850
|
-
hallucinationScore:
|
|
6851
|
-
hallucinationReason:
|
|
7790
|
+
}, hScore ? {
|
|
7791
|
+
hallucinationScore: hScore.score,
|
|
7792
|
+
hallucinationReason: hScore.reason
|
|
6852
7793
|
} : {});
|
|
7794
|
+
const trace = buildTrace(hallucinationResult);
|
|
7795
|
+
if ((_A = this.config.telemetry) == null ? void 0 : _A.enabled) {
|
|
7796
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7797
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7798
|
+
(async () => {
|
|
7799
|
+
try {
|
|
7800
|
+
let finalTrace = trace;
|
|
7801
|
+
if (!awaitHallucination && runHallucination) {
|
|
7802
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7803
|
+
if (backgroundScoreResult) {
|
|
7804
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
await fetch(absoluteUrl, {
|
|
7808
|
+
method: "POST",
|
|
7809
|
+
headers: {
|
|
7810
|
+
"Content-Type": "application/json"
|
|
7811
|
+
},
|
|
7812
|
+
body: JSON.stringify({
|
|
7813
|
+
trace: finalTrace,
|
|
7814
|
+
licenseKey: this.config.licenseKey,
|
|
7815
|
+
projectId: ns
|
|
7816
|
+
})
|
|
7817
|
+
});
|
|
7818
|
+
} catch (err) {
|
|
7819
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
7820
|
+
}
|
|
7821
|
+
})();
|
|
7822
|
+
}
|
|
6853
7823
|
yield {
|
|
6854
7824
|
reply: "",
|
|
6855
7825
|
sources,
|
|
@@ -6869,7 +7839,7 @@ ${context}`;
|
|
|
6869
7839
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6870
7840
|
*/
|
|
6871
7841
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6872
|
-
var
|
|
7842
|
+
var _a2;
|
|
6873
7843
|
if (!sources || sources.length === 0) {
|
|
6874
7844
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6875
7845
|
}
|
|
@@ -6883,7 +7853,7 @@ ${context}`;
|
|
|
6883
7853
|
);
|
|
6884
7854
|
}
|
|
6885
7855
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6886
|
-
const disableLlmUiTransform = ((
|
|
7856
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6887
7857
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6888
7858
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6889
7859
|
}
|
|
@@ -6901,9 +7871,9 @@ ${context}`;
|
|
|
6901
7871
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6902
7872
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6903
7873
|
})).sort((a, b) => {
|
|
6904
|
-
var
|
|
7874
|
+
var _a2, _b;
|
|
6905
7875
|
const primary = predicates[0];
|
|
6906
|
-
const aValue = (
|
|
7876
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6907
7877
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6908
7878
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6909
7879
|
});
|
|
@@ -6975,8 +7945,8 @@ ${context}`;
|
|
|
6975
7945
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6976
7946
|
}
|
|
6977
7947
|
async retrieve(query, options) {
|
|
6978
|
-
var
|
|
6979
|
-
const ns = (
|
|
7948
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
7949
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
6980
7950
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6981
7951
|
const cacheKey = `${ns}::${query}`;
|
|
6982
7952
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -7008,7 +7978,7 @@ ${context}`;
|
|
|
7008
7978
|
) : [];
|
|
7009
7979
|
const resolvedSources = [];
|
|
7010
7980
|
for (const source of sources) {
|
|
7011
|
-
const parentId = (
|
|
7981
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
7012
7982
|
if (parentId) {
|
|
7013
7983
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
7014
7984
|
resolvedSources.push(source);
|
|
@@ -7186,14 +8156,228 @@ var ProviderHealthCheck = class {
|
|
|
7186
8156
|
}
|
|
7187
8157
|
};
|
|
7188
8158
|
|
|
8159
|
+
// src/core/LicenseVerifier.ts
|
|
8160
|
+
var crypto2 = __toESM(require("crypto"));
|
|
8161
|
+
var LicenseVerifier = class {
|
|
8162
|
+
/**
|
|
8163
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
8164
|
+
*
|
|
8165
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
8166
|
+
* @param currentProjectId - Project namespace ID.
|
|
8167
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
8168
|
+
*/
|
|
8169
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
8170
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
8171
|
+
const now = Date.now();
|
|
8172
|
+
if (licenseKey) {
|
|
8173
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
8174
|
+
const cached = this.cache.get(cacheKey);
|
|
8175
|
+
if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
|
|
8176
|
+
const currentTimestampSec = Math.floor(now / 1e3);
|
|
8177
|
+
if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
|
|
8178
|
+
this.cache.delete(cacheKey);
|
|
8179
|
+
} else {
|
|
8180
|
+
return cached.payload;
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
if (!licenseKey) {
|
|
8185
|
+
if (isProduction) {
|
|
8186
|
+
throw new ConfigurationException(
|
|
8187
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
8188
|
+
);
|
|
8189
|
+
}
|
|
8190
|
+
console.warn(
|
|
8191
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
8192
|
+
);
|
|
8193
|
+
return {
|
|
8194
|
+
projectId: currentProjectId,
|
|
8195
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
8196
|
+
// Valid for 24h
|
|
8197
|
+
tier: "hobby"
|
|
8198
|
+
};
|
|
8199
|
+
}
|
|
8200
|
+
try {
|
|
8201
|
+
const parts = licenseKey.split(".");
|
|
8202
|
+
if (parts.length !== 3) {
|
|
8203
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
8204
|
+
}
|
|
8205
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
8206
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
8207
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
8208
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
8209
|
+
const data = Buffer.from(dataToVerify);
|
|
8210
|
+
const isValid = crypto2.verify(
|
|
8211
|
+
"sha256",
|
|
8212
|
+
data,
|
|
8213
|
+
publicKey,
|
|
8214
|
+
signature
|
|
8215
|
+
);
|
|
8216
|
+
if (!isValid) {
|
|
8217
|
+
throw new Error("Signature verification failed.");
|
|
8218
|
+
}
|
|
8219
|
+
const payload = JSON.parse(
|
|
8220
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8221
|
+
);
|
|
8222
|
+
if (!payload.projectId) {
|
|
8223
|
+
throw new Error('License payload is missing "projectId".');
|
|
8224
|
+
}
|
|
8225
|
+
if (payload.projectId !== currentProjectId) {
|
|
8226
|
+
throw new Error(
|
|
8227
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
8228
|
+
);
|
|
8229
|
+
}
|
|
8230
|
+
if (!payload.expiresAt) {
|
|
8231
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
8232
|
+
}
|
|
8233
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
8234
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
8235
|
+
throw new Error(
|
|
8236
|
+
`License key has expired. Expiration: ${new Date(
|
|
8237
|
+
payload.expiresAt * 1e3
|
|
8238
|
+
).toDateString()}`
|
|
8239
|
+
);
|
|
8240
|
+
}
|
|
8241
|
+
if (isProduction && provider) {
|
|
8242
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8243
|
+
const normalizedProvider = provider.toLowerCase();
|
|
8244
|
+
if (tier === "hobby") {
|
|
8245
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
8246
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
8247
|
+
throw new Error(
|
|
8248
|
+
`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.`
|
|
8249
|
+
);
|
|
8250
|
+
}
|
|
8251
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
8252
|
+
const allowedPro = [
|
|
8253
|
+
"postgresql",
|
|
8254
|
+
"pgvector",
|
|
8255
|
+
"supabase",
|
|
8256
|
+
"pinecone",
|
|
8257
|
+
"qdrant",
|
|
8258
|
+
"mongodb",
|
|
8259
|
+
"milvus",
|
|
8260
|
+
"chroma",
|
|
8261
|
+
"chromadb"
|
|
8262
|
+
];
|
|
8263
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
8264
|
+
throw new Error(
|
|
8265
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
8266
|
+
);
|
|
8267
|
+
}
|
|
8268
|
+
}
|
|
8269
|
+
}
|
|
8270
|
+
if (licenseKey) {
|
|
8271
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
8272
|
+
this.cache.set(cacheKey, { payload, cachedAt: now });
|
|
8273
|
+
}
|
|
8274
|
+
return payload;
|
|
8275
|
+
} catch (err) {
|
|
8276
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8277
|
+
throw new ConfigurationException(
|
|
8278
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
8279
|
+
);
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8282
|
+
static async verifyIP(licenseKey) {
|
|
8283
|
+
if (!licenseKey) return;
|
|
8284
|
+
try {
|
|
8285
|
+
const parts = licenseKey.split(".");
|
|
8286
|
+
if (parts.length !== 3) return;
|
|
8287
|
+
const [, payloadB64] = parts;
|
|
8288
|
+
const payload = JSON.parse(
|
|
8289
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8290
|
+
);
|
|
8291
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8292
|
+
if (tier === "enterprise" || tier === "custom") {
|
|
8293
|
+
return;
|
|
8294
|
+
}
|
|
8295
|
+
if (payload.ipv4 || payload.ipv6) {
|
|
8296
|
+
let currentIpv4 = "";
|
|
8297
|
+
let currentIpv6 = "";
|
|
8298
|
+
try {
|
|
8299
|
+
const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
8300
|
+
const data = await res.json();
|
|
8301
|
+
currentIpv4 = data.ip;
|
|
8302
|
+
} catch (e) {
|
|
8303
|
+
}
|
|
8304
|
+
try {
|
|
8305
|
+
const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
8306
|
+
const data = await res.json();
|
|
8307
|
+
currentIpv6 = data.ip;
|
|
8308
|
+
} catch (e) {
|
|
8309
|
+
}
|
|
8310
|
+
const localIps = [];
|
|
8311
|
+
try {
|
|
8312
|
+
const osModule = require("os");
|
|
8313
|
+
const interfaces = osModule.networkInterfaces();
|
|
8314
|
+
for (const name of Object.keys(interfaces)) {
|
|
8315
|
+
for (const iface of interfaces[name] || []) {
|
|
8316
|
+
if (!iface.internal) {
|
|
8317
|
+
localIps.push(iface.address);
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8320
|
+
}
|
|
8321
|
+
} catch (e) {
|
|
8322
|
+
}
|
|
8323
|
+
const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
|
|
8324
|
+
const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
|
|
8325
|
+
if (payload.ipv4 && payload.ipv6) {
|
|
8326
|
+
if (!isIpv4Match && !isIpv6Match) {
|
|
8327
|
+
throw new Error(
|
|
8328
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
8329
|
+
);
|
|
8330
|
+
}
|
|
8331
|
+
} else if (payload.ipv4 && !isIpv4Match) {
|
|
8332
|
+
throw new Error(
|
|
8333
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
|
|
8334
|
+
);
|
|
8335
|
+
} else if (payload.ipv6 && !isIpv6Match) {
|
|
8336
|
+
throw new Error(
|
|
8337
|
+
`License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
8338
|
+
);
|
|
8339
|
+
}
|
|
8340
|
+
}
|
|
8341
|
+
} catch (err) {
|
|
8342
|
+
if (err.message.includes("License key access restricted")) {
|
|
8343
|
+
throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
|
|
8344
|
+
}
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
};
|
|
8348
|
+
// A simple in-memory cache to save CPU overhead of cryptographic signature checks.
|
|
8349
|
+
LicenseVerifier.cache = /* @__PURE__ */ new Map();
|
|
8350
|
+
LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
|
|
8351
|
+
// Cache verified license for 60 seconds
|
|
8352
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
8353
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
8354
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
8355
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
8356
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
8357
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
8358
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
8359
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
8360
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
8361
|
+
MwIDAQAB
|
|
8362
|
+
-----END PUBLIC KEY-----`;
|
|
8363
|
+
|
|
7189
8364
|
// src/core/VectorPlugin.ts
|
|
7190
8365
|
var VectorPlugin = class {
|
|
7191
8366
|
constructor(hostConfig) {
|
|
7192
|
-
|
|
7193
|
-
this.
|
|
8367
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8368
|
+
this.config = resolvedConfig;
|
|
8369
|
+
this.validationPromise = (async () => {
|
|
8370
|
+
var _a2;
|
|
8371
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8372
|
+
LicenseVerifier.verify(
|
|
8373
|
+
resolvedConfig.licenseKey,
|
|
8374
|
+
resolvedConfig.projectId,
|
|
8375
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8376
|
+
);
|
|
8377
|
+
})();
|
|
7194
8378
|
this.validationPromise.catch(() => {
|
|
7195
8379
|
});
|
|
7196
|
-
this.pipeline = new Pipeline(
|
|
8380
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7197
8381
|
}
|
|
7198
8382
|
/**
|
|
7199
8383
|
* Get the current resolved configuration.
|
|
@@ -7322,8 +8506,8 @@ var DocumentParser = class {
|
|
|
7322
8506
|
* Extract text from a File or Buffer based on its type.
|
|
7323
8507
|
*/
|
|
7324
8508
|
static async parse(file, fileName, mimeType) {
|
|
7325
|
-
var
|
|
7326
|
-
const extension = (
|
|
8509
|
+
var _a2;
|
|
8510
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7327
8511
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7328
8512
|
return this.readAsText(file);
|
|
7329
8513
|
}
|
|
@@ -7375,7 +8559,496 @@ var DocumentParser = class {
|
|
|
7375
8559
|
}
|
|
7376
8560
|
};
|
|
7377
8561
|
|
|
8562
|
+
// src/core/DatabaseStorage.ts
|
|
8563
|
+
var fs = __toESM(require("fs"));
|
|
8564
|
+
var path = __toESM(require("path"));
|
|
8565
|
+
var DatabaseStorage = class {
|
|
8566
|
+
constructor(config) {
|
|
8567
|
+
// Dynamic PG Pool
|
|
8568
|
+
this.pgPool = null;
|
|
8569
|
+
// Dynamic MongoDB Client
|
|
8570
|
+
this.mongoClient = null;
|
|
8571
|
+
this.mongoDbName = "";
|
|
8572
|
+
// Filesystem fallback configuration
|
|
8573
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8574
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8575
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8576
|
+
var _a2, _b, _c, _d, _e;
|
|
8577
|
+
this.config = config;
|
|
8578
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8579
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8580
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8581
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8582
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8583
|
+
}
|
|
8584
|
+
/**
|
|
8585
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8586
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8587
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8588
|
+
*/
|
|
8589
|
+
checkPremiumSubscription() {
|
|
8590
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8591
|
+
return;
|
|
8592
|
+
}
|
|
8593
|
+
if (!this.config.licenseKey) {
|
|
8594
|
+
throw new Error(
|
|
8595
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8596
|
+
);
|
|
8597
|
+
}
|
|
8598
|
+
try {
|
|
8599
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8600
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8601
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8602
|
+
throw new Error(
|
|
8603
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8604
|
+
);
|
|
8605
|
+
}
|
|
8606
|
+
} catch (err) {
|
|
8607
|
+
throw new Error(
|
|
8608
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8609
|
+
);
|
|
8610
|
+
}
|
|
8611
|
+
}
|
|
8612
|
+
checkHistoryEnabled() {
|
|
8613
|
+
var _a2, _b;
|
|
8614
|
+
this.checkPremiumSubscription();
|
|
8615
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8616
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
checkFeedbackEnabled() {
|
|
8620
|
+
var _a2, _b;
|
|
8621
|
+
this.checkPremiumSubscription();
|
|
8622
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8623
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
async getPGPool() {
|
|
8627
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8628
|
+
const _g2 = global;
|
|
8629
|
+
if (_g2[globalKey]) {
|
|
8630
|
+
this.pgPool = _g2[globalKey];
|
|
8631
|
+
return this.pgPool;
|
|
8632
|
+
}
|
|
8633
|
+
const opts = this.config.vectorDb.options;
|
|
8634
|
+
if (!opts.connectionString) {
|
|
8635
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8636
|
+
}
|
|
8637
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8638
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8639
|
+
_g2[globalKey] = this.pgPool;
|
|
8640
|
+
const client = await this.pgPool.connect();
|
|
8641
|
+
try {
|
|
8642
|
+
await client.query(`
|
|
8643
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8644
|
+
id TEXT PRIMARY KEY,
|
|
8645
|
+
session_id TEXT NOT NULL,
|
|
8646
|
+
role TEXT NOT NULL,
|
|
8647
|
+
content TEXT NOT NULL,
|
|
8648
|
+
sources JSONB,
|
|
8649
|
+
ui_transformation JSONB,
|
|
8650
|
+
trace JSONB,
|
|
8651
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8652
|
+
)
|
|
8653
|
+
`);
|
|
8654
|
+
await client.query(`
|
|
8655
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8656
|
+
id TEXT PRIMARY KEY,
|
|
8657
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8658
|
+
session_id TEXT NOT NULL,
|
|
8659
|
+
rating TEXT NOT NULL,
|
|
8660
|
+
comment TEXT,
|
|
8661
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8662
|
+
)
|
|
8663
|
+
`);
|
|
8664
|
+
} finally {
|
|
8665
|
+
client.release();
|
|
8666
|
+
}
|
|
8667
|
+
return this.pgPool;
|
|
8668
|
+
}
|
|
8669
|
+
async getMongoClient() {
|
|
8670
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8671
|
+
const _g2 = global;
|
|
8672
|
+
if (_g2[globalKey]) {
|
|
8673
|
+
this.mongoClient = _g2[globalKey];
|
|
8674
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8675
|
+
return this.mongoClient;
|
|
8676
|
+
}
|
|
8677
|
+
const opts = this.config.vectorDb.options;
|
|
8678
|
+
if (!opts.uri || !opts.database) {
|
|
8679
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8680
|
+
}
|
|
8681
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8682
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8683
|
+
await this.mongoClient.connect();
|
|
8684
|
+
_g2[globalKey] = this.mongoClient;
|
|
8685
|
+
this.mongoDbName = opts.database;
|
|
8686
|
+
return this.mongoClient;
|
|
8687
|
+
}
|
|
8688
|
+
getMongoDb() {
|
|
8689
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8690
|
+
}
|
|
8691
|
+
// Helper for FS fallback reads
|
|
8692
|
+
readLocalFile(filePath) {
|
|
8693
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8694
|
+
try {
|
|
8695
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8696
|
+
return JSON.parse(raw) || [];
|
|
8697
|
+
} catch (e) {
|
|
8698
|
+
return [];
|
|
8699
|
+
}
|
|
8700
|
+
}
|
|
8701
|
+
// Helper for FS fallback writes
|
|
8702
|
+
writeLocalFile(filePath, data) {
|
|
8703
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8704
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8705
|
+
}
|
|
8706
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8707
|
+
}
|
|
8708
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8709
|
+
async saveMessage(sessionId, message) {
|
|
8710
|
+
this.checkHistoryEnabled();
|
|
8711
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8712
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8713
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8714
|
+
const pool = await this.getPGPool();
|
|
8715
|
+
await pool.query(
|
|
8716
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8717
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8718
|
+
ON CONFLICT (id) DO UPDATE
|
|
8719
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8720
|
+
[
|
|
8721
|
+
msgId,
|
|
8722
|
+
sessionId,
|
|
8723
|
+
message.role,
|
|
8724
|
+
message.content,
|
|
8725
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
8726
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
8727
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
8728
|
+
createdAt
|
|
8729
|
+
]
|
|
8730
|
+
);
|
|
8731
|
+
} else if (this.provider === "mongodb") {
|
|
8732
|
+
await this.getMongoClient();
|
|
8733
|
+
const db = this.getMongoDb();
|
|
8734
|
+
const col = db.collection(this.historyTableName);
|
|
8735
|
+
await col.updateOne(
|
|
8736
|
+
{ id: msgId },
|
|
8737
|
+
{
|
|
8738
|
+
$set: {
|
|
8739
|
+
id: msgId,
|
|
8740
|
+
session_id: sessionId,
|
|
8741
|
+
role: message.role,
|
|
8742
|
+
content: message.content,
|
|
8743
|
+
sources: message.sources || null,
|
|
8744
|
+
ui_transformation: message.uiTransformation || null,
|
|
8745
|
+
trace: message.trace || null,
|
|
8746
|
+
created_at: createdAt
|
|
8747
|
+
}
|
|
8748
|
+
},
|
|
8749
|
+
{ upsert: true }
|
|
8750
|
+
);
|
|
8751
|
+
} else {
|
|
8752
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8753
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
8754
|
+
const item = {
|
|
8755
|
+
id: msgId,
|
|
8756
|
+
session_id: sessionId,
|
|
8757
|
+
role: message.role,
|
|
8758
|
+
content: message.content,
|
|
8759
|
+
sources: message.sources || null,
|
|
8760
|
+
ui_transformation: message.uiTransformation || null,
|
|
8761
|
+
trace: message.trace || null,
|
|
8762
|
+
created_at: createdAt
|
|
8763
|
+
};
|
|
8764
|
+
if (index !== -1) {
|
|
8765
|
+
history[index] = item;
|
|
8766
|
+
} else {
|
|
8767
|
+
history.push(item);
|
|
8768
|
+
}
|
|
8769
|
+
this.writeLocalFile(this.historyFile, history);
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
async getHistory(sessionId) {
|
|
8773
|
+
this.checkHistoryEnabled();
|
|
8774
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8775
|
+
const pool = await this.getPGPool();
|
|
8776
|
+
const res = await pool.query(
|
|
8777
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
8778
|
+
FROM ${this.historyTableName}
|
|
8779
|
+
WHERE session_id = $1
|
|
8780
|
+
ORDER BY created_at ASC`,
|
|
8781
|
+
[sessionId]
|
|
8782
|
+
);
|
|
8783
|
+
return res.rows;
|
|
8784
|
+
} else if (this.provider === "mongodb") {
|
|
8785
|
+
await this.getMongoClient();
|
|
8786
|
+
const db = this.getMongoDb();
|
|
8787
|
+
const col = db.collection(this.historyTableName);
|
|
8788
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
8789
|
+
return items.map((item) => ({
|
|
8790
|
+
id: item.id,
|
|
8791
|
+
role: item.role,
|
|
8792
|
+
content: item.content,
|
|
8793
|
+
sources: item.sources,
|
|
8794
|
+
uiTransformation: item.ui_transformation,
|
|
8795
|
+
trace: item.trace,
|
|
8796
|
+
createdAt: item.created_at
|
|
8797
|
+
}));
|
|
8798
|
+
} else {
|
|
8799
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8800
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
8801
|
+
}
|
|
8802
|
+
}
|
|
8803
|
+
async clearHistory(sessionId) {
|
|
8804
|
+
this.checkHistoryEnabled();
|
|
8805
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8806
|
+
const pool = await this.getPGPool();
|
|
8807
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
8808
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
8809
|
+
} else if (this.provider === "mongodb") {
|
|
8810
|
+
await this.getMongoClient();
|
|
8811
|
+
const db = this.getMongoDb();
|
|
8812
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
8813
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
8814
|
+
} else {
|
|
8815
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8816
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
8817
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
8818
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
8819
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
8820
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
8821
|
+
}
|
|
8822
|
+
}
|
|
8823
|
+
async listSessions() {
|
|
8824
|
+
this.checkHistoryEnabled();
|
|
8825
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8826
|
+
const pool = await this.getPGPool();
|
|
8827
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
8828
|
+
return res.rows.map((r) => r.session_id);
|
|
8829
|
+
} else if (this.provider === "mongodb") {
|
|
8830
|
+
await this.getMongoClient();
|
|
8831
|
+
const db = this.getMongoDb();
|
|
8832
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
8833
|
+
} else {
|
|
8834
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8835
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
8836
|
+
return Array.from(sessions);
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
8840
|
+
async saveFeedback(feedback) {
|
|
8841
|
+
this.checkFeedbackEnabled();
|
|
8842
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8843
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8844
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8845
|
+
const pool = await this.getPGPool();
|
|
8846
|
+
await pool.query(
|
|
8847
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
8848
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
8849
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
8850
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
8851
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
8852
|
+
);
|
|
8853
|
+
} else if (this.provider === "mongodb") {
|
|
8854
|
+
await this.getMongoClient();
|
|
8855
|
+
const db = this.getMongoDb();
|
|
8856
|
+
const col = db.collection(this.feedbackTableName);
|
|
8857
|
+
await col.updateOne(
|
|
8858
|
+
{ message_id: feedback.messageId },
|
|
8859
|
+
{
|
|
8860
|
+
$set: {
|
|
8861
|
+
id,
|
|
8862
|
+
message_id: feedback.messageId,
|
|
8863
|
+
session_id: feedback.sessionId,
|
|
8864
|
+
rating: feedback.rating,
|
|
8865
|
+
comment: feedback.comment || null,
|
|
8866
|
+
created_at: createdAt
|
|
8867
|
+
}
|
|
8868
|
+
},
|
|
8869
|
+
{ upsert: true }
|
|
8870
|
+
);
|
|
8871
|
+
} else {
|
|
8872
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8873
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
8874
|
+
const item = {
|
|
8875
|
+
id,
|
|
8876
|
+
message_id: feedback.messageId,
|
|
8877
|
+
session_id: feedback.sessionId,
|
|
8878
|
+
rating: feedback.rating,
|
|
8879
|
+
comment: feedback.comment || null,
|
|
8880
|
+
created_at: createdAt
|
|
8881
|
+
};
|
|
8882
|
+
if (index !== -1) {
|
|
8883
|
+
list[index] = item;
|
|
8884
|
+
} else {
|
|
8885
|
+
list.push(item);
|
|
8886
|
+
}
|
|
8887
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
8888
|
+
}
|
|
8889
|
+
}
|
|
8890
|
+
async getFeedback(messageId) {
|
|
8891
|
+
this.checkFeedbackEnabled();
|
|
8892
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8893
|
+
const pool = await this.getPGPool();
|
|
8894
|
+
const res = await pool.query(
|
|
8895
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8896
|
+
FROM ${this.feedbackTableName}
|
|
8897
|
+
WHERE message_id = $1`,
|
|
8898
|
+
[messageId]
|
|
8899
|
+
);
|
|
8900
|
+
return res.rows[0] || null;
|
|
8901
|
+
} else if (this.provider === "mongodb") {
|
|
8902
|
+
await this.getMongoClient();
|
|
8903
|
+
const db = this.getMongoDb();
|
|
8904
|
+
const col = db.collection(this.feedbackTableName);
|
|
8905
|
+
const item = await col.findOne({ message_id: messageId });
|
|
8906
|
+
if (!item) return null;
|
|
8907
|
+
return {
|
|
8908
|
+
id: item.id,
|
|
8909
|
+
messageId: item.message_id,
|
|
8910
|
+
sessionId: item.session_id,
|
|
8911
|
+
rating: item.rating,
|
|
8912
|
+
comment: item.comment,
|
|
8913
|
+
createdAt: item.created_at
|
|
8914
|
+
};
|
|
8915
|
+
} else {
|
|
8916
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8917
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
async listFeedback() {
|
|
8921
|
+
this.checkFeedbackEnabled();
|
|
8922
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8923
|
+
const pool = await this.getPGPool();
|
|
8924
|
+
const res = await pool.query(
|
|
8925
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8926
|
+
FROM ${this.feedbackTableName}
|
|
8927
|
+
ORDER BY created_at DESC`
|
|
8928
|
+
);
|
|
8929
|
+
return res.rows;
|
|
8930
|
+
} else if (this.provider === "mongodb") {
|
|
8931
|
+
await this.getMongoClient();
|
|
8932
|
+
const db = this.getMongoDb();
|
|
8933
|
+
const col = db.collection(this.feedbackTableName);
|
|
8934
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
8935
|
+
return items.map((item) => ({
|
|
8936
|
+
id: item.id,
|
|
8937
|
+
messageId: item.message_id,
|
|
8938
|
+
sessionId: item.session_id,
|
|
8939
|
+
rating: item.rating,
|
|
8940
|
+
comment: item.comment,
|
|
8941
|
+
createdAt: item.created_at
|
|
8942
|
+
}));
|
|
8943
|
+
} else {
|
|
8944
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8945
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
async disconnect() {
|
|
8949
|
+
if (this.pgPool) {
|
|
8950
|
+
await this.pgPool.end();
|
|
8951
|
+
this.pgPool = null;
|
|
8952
|
+
}
|
|
8953
|
+
if (this.mongoClient) {
|
|
8954
|
+
await this.mongoClient.close();
|
|
8955
|
+
this.mongoClient = null;
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
};
|
|
8959
|
+
|
|
7378
8960
|
// src/handlers/index.ts
|
|
8961
|
+
async function checkAuth(req, onAuthorize) {
|
|
8962
|
+
if (!onAuthorize) return null;
|
|
8963
|
+
try {
|
|
8964
|
+
const res = await onAuthorize(req);
|
|
8965
|
+
if (res === false) {
|
|
8966
|
+
return import_server.NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
8967
|
+
}
|
|
8968
|
+
if (res instanceof Response) {
|
|
8969
|
+
return res;
|
|
8970
|
+
}
|
|
8971
|
+
return null;
|
|
8972
|
+
} catch (err) {
|
|
8973
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
8974
|
+
return import_server.NextResponse.json({ error: msg }, { status: 401 });
|
|
8975
|
+
}
|
|
8976
|
+
}
|
|
8977
|
+
var RateLimiter = class {
|
|
8978
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
8979
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
8980
|
+
this.windowMs = windowMs;
|
|
8981
|
+
this.max = max;
|
|
8982
|
+
}
|
|
8983
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
8984
|
+
allow(key) {
|
|
8985
|
+
const now = Date.now();
|
|
8986
|
+
const cutoff = now - this.windowMs;
|
|
8987
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8988
|
+
existing.push(now);
|
|
8989
|
+
this.hits.set(key, existing);
|
|
8990
|
+
if (this.hits.size > 5e3) {
|
|
8991
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
8992
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
8995
|
+
return existing.length <= this.max;
|
|
8996
|
+
}
|
|
8997
|
+
retryAfterSec(key) {
|
|
8998
|
+
const now = Date.now();
|
|
8999
|
+
const cutoff = now - this.windowMs;
|
|
9000
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9001
|
+
if (existing.length === 0) return 0;
|
|
9002
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
9003
|
+
}
|
|
9004
|
+
};
|
|
9005
|
+
var _g = global;
|
|
9006
|
+
var _a;
|
|
9007
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
9008
|
+
function getRateLimitKey(req) {
|
|
9009
|
+
var _a2, _b;
|
|
9010
|
+
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";
|
|
9011
|
+
return `ip:${ip}`;
|
|
9012
|
+
}
|
|
9013
|
+
function checkRateLimit(req) {
|
|
9014
|
+
const key = getRateLimitKey(req);
|
|
9015
|
+
if (!rateLimiter.allow(key)) {
|
|
9016
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
9017
|
+
return new Response(
|
|
9018
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
9019
|
+
{
|
|
9020
|
+
status: 429,
|
|
9021
|
+
headers: {
|
|
9022
|
+
"Content-Type": "application/json",
|
|
9023
|
+
"Retry-After": String(retryAfter),
|
|
9024
|
+
"X-RateLimit-Limit": "30",
|
|
9025
|
+
"X-RateLimit-Window": "60"
|
|
9026
|
+
}
|
|
9027
|
+
}
|
|
9028
|
+
);
|
|
9029
|
+
}
|
|
9030
|
+
return null;
|
|
9031
|
+
}
|
|
9032
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
9033
|
+
function sanitizeInput(raw) {
|
|
9034
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
9035
|
+
const trimmed = stripped.trim();
|
|
9036
|
+
if (!trimmed) {
|
|
9037
|
+
return { ok: false, error: "message must not be empty" };
|
|
9038
|
+
}
|
|
9039
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
9040
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
9041
|
+
}
|
|
9042
|
+
return { ok: true, value: trimmed };
|
|
9043
|
+
}
|
|
9044
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
9045
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
9046
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
9047
|
+
if (!_g[cacheKey]) {
|
|
9048
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
9049
|
+
}
|
|
9050
|
+
return _g[cacheKey];
|
|
9051
|
+
}
|
|
7379
9052
|
function sseFrame(payload) {
|
|
7380
9053
|
return `data: ${JSON.stringify(payload)}
|
|
7381
9054
|
|
|
@@ -7413,47 +9086,88 @@ var SSE_HEADERS = {
|
|
|
7413
9086
|
"X-Accel-Buffering": "no"
|
|
7414
9087
|
// Disable Nginx buffering for streaming
|
|
7415
9088
|
};
|
|
7416
|
-
function createChatHandler(configOrPlugin) {
|
|
7417
|
-
const plugin =
|
|
9089
|
+
function createChatHandler(configOrPlugin, options) {
|
|
9090
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9091
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9092
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7418
9093
|
return async function POST(req) {
|
|
9094
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9095
|
+
if (authResult) return authResult;
|
|
9096
|
+
const rateLimited = checkRateLimit(req);
|
|
9097
|
+
if (rateLimited) return rateLimited;
|
|
7419
9098
|
try {
|
|
7420
9099
|
const body = await req.json();
|
|
7421
|
-
const { message, history = [], namespace } = body;
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
9100
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9101
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9102
|
+
if (!sanitized.ok) {
|
|
9103
|
+
return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
9104
|
+
}
|
|
9105
|
+
const message = sanitized.value;
|
|
9106
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9107
|
+
await storage.saveMessage(sessionId, {
|
|
9108
|
+
id: userMsgId,
|
|
9109
|
+
role: "user",
|
|
9110
|
+
content: message
|
|
9111
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7425
9112
|
const result = await plugin.chat(message, history, namespace);
|
|
7426
|
-
|
|
9113
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9114
|
+
await storage.saveMessage(sessionId, {
|
|
9115
|
+
id: assistantMsgId,
|
|
9116
|
+
role: "assistant",
|
|
9117
|
+
content: result.reply,
|
|
9118
|
+
sources: result.sources,
|
|
9119
|
+
uiTransformation: result.ui_transformation,
|
|
9120
|
+
trace: result.trace
|
|
9121
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9122
|
+
return import_server.NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9123
|
+
messageId: assistantMsgId,
|
|
9124
|
+
userMessageId: userMsgId
|
|
9125
|
+
}));
|
|
7427
9126
|
} catch (err) {
|
|
7428
9127
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7429
9128
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
7430
9129
|
}
|
|
7431
9130
|
};
|
|
7432
9131
|
}
|
|
7433
|
-
function createStreamHandler(configOrPlugin) {
|
|
7434
|
-
const plugin =
|
|
9132
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9133
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9134
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9135
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7435
9136
|
return async function POST(req) {
|
|
9137
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9138
|
+
if (authResult) return authResult;
|
|
9139
|
+
const rateLimited = checkRateLimit(req);
|
|
9140
|
+
if (rateLimited) return rateLimited;
|
|
7436
9141
|
let body;
|
|
7437
9142
|
try {
|
|
7438
9143
|
body = await req.json();
|
|
7439
9144
|
} catch (e) {
|
|
7440
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9145
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7441
9146
|
status: 400,
|
|
7442
9147
|
headers: { "Content-Type": "application/json" }
|
|
7443
9148
|
});
|
|
7444
9149
|
}
|
|
7445
|
-
const { message, history = [], namespace } = body;
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
9150
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9151
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9152
|
+
if (!sanitized.ok) {
|
|
9153
|
+
return new Response(
|
|
9154
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9155
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9156
|
+
);
|
|
7451
9157
|
}
|
|
9158
|
+
const message = sanitized.value;
|
|
9159
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9160
|
+
await storage.saveMessage(sessionId, {
|
|
9161
|
+
id: userMsgId,
|
|
9162
|
+
role: "user",
|
|
9163
|
+
content: message
|
|
9164
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9165
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7452
9166
|
const encoder = new TextEncoder();
|
|
7453
9167
|
let isActive = true;
|
|
7454
9168
|
const stream = new ReadableStream({
|
|
7455
9169
|
async start(controller) {
|
|
7456
|
-
var
|
|
9170
|
+
var _a2;
|
|
7457
9171
|
const enqueue = (text) => {
|
|
7458
9172
|
if (!isActive) return;
|
|
7459
9173
|
try {
|
|
@@ -7464,11 +9178,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7464
9178
|
};
|
|
7465
9179
|
try {
|
|
7466
9180
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9181
|
+
let fullReply = "";
|
|
7467
9182
|
try {
|
|
7468
9183
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7469
9184
|
const chunk = temp.value;
|
|
7470
9185
|
if (!isActive) break;
|
|
7471
9186
|
if (typeof chunk === "string") {
|
|
9187
|
+
fullReply += chunk;
|
|
7472
9188
|
enqueue(sseTextFrame(chunk));
|
|
7473
9189
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7474
9190
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7481,9 +9197,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7481
9197
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7482
9198
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7483
9199
|
}
|
|
9200
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7484
9201
|
if (sources.length > 0) {
|
|
7485
9202
|
try {
|
|
7486
|
-
|
|
9203
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7487
9204
|
if (uiTransformation) {
|
|
7488
9205
|
enqueue(sseUIFrame(uiTransformation));
|
|
7489
9206
|
}
|
|
@@ -7491,11 +9208,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7491
9208
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7492
9209
|
try {
|
|
7493
9210
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7494
|
-
if (fallback)
|
|
9211
|
+
if (fallback) {
|
|
9212
|
+
uiTransformation = fallback;
|
|
9213
|
+
enqueue(sseUIFrame(fallback));
|
|
9214
|
+
}
|
|
7495
9215
|
} catch (e) {
|
|
7496
9216
|
}
|
|
7497
9217
|
}
|
|
7498
9218
|
}
|
|
9219
|
+
await storage.saveMessage(sessionId, {
|
|
9220
|
+
id: assistantMsgId,
|
|
9221
|
+
role: "assistant",
|
|
9222
|
+
content: fullReply,
|
|
9223
|
+
sources,
|
|
9224
|
+
uiTransformation,
|
|
9225
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9226
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7499
9227
|
}
|
|
7500
9228
|
}
|
|
7501
9229
|
} catch (temp) {
|
|
@@ -7532,12 +9260,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7532
9260
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7533
9261
|
}
|
|
7534
9262
|
});
|
|
7535
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9263
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7536
9264
|
};
|
|
7537
9265
|
}
|
|
7538
|
-
function createIngestHandler(configOrPlugin) {
|
|
7539
|
-
const plugin =
|
|
9266
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9267
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9268
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7540
9269
|
return async function POST(req) {
|
|
9270
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9271
|
+
if (authResult) return authResult;
|
|
7541
9272
|
try {
|
|
7542
9273
|
const body = await req.json();
|
|
7543
9274
|
const { documents, namespace } = body;
|
|
@@ -7552,9 +9283,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7552
9283
|
}
|
|
7553
9284
|
};
|
|
7554
9285
|
}
|
|
7555
|
-
function createHealthHandler(configOrPlugin) {
|
|
7556
|
-
const plugin =
|
|
7557
|
-
|
|
9286
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9287
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9288
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9289
|
+
return async function GET(req) {
|
|
9290
|
+
if (req) {
|
|
9291
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9292
|
+
if (authResult) return authResult;
|
|
9293
|
+
}
|
|
7558
9294
|
try {
|
|
7559
9295
|
const health = await plugin.checkHealth();
|
|
7560
9296
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7569,9 +9305,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7569
9305
|
}
|
|
7570
9306
|
};
|
|
7571
9307
|
}
|
|
7572
|
-
function createUploadHandler(configOrPlugin) {
|
|
7573
|
-
const plugin =
|
|
9308
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9309
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9310
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7574
9311
|
return async function POST(req) {
|
|
9312
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9313
|
+
if (authResult) return authResult;
|
|
7575
9314
|
try {
|
|
7576
9315
|
const formData = await req.formData();
|
|
7577
9316
|
const files = formData.getAll("files");
|
|
@@ -7645,9 +9384,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7645
9384
|
}
|
|
7646
9385
|
};
|
|
7647
9386
|
}
|
|
7648
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
7649
|
-
const plugin =
|
|
9387
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9388
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9389
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7650
9390
|
return async function POST(req) {
|
|
9391
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9392
|
+
if (authResult) return authResult;
|
|
7651
9393
|
try {
|
|
7652
9394
|
const body = await req.json();
|
|
7653
9395
|
const { query, namespace } = body;
|
|
@@ -7662,13 +9404,108 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
7662
9404
|
}
|
|
7663
9405
|
};
|
|
7664
9406
|
}
|
|
7665
|
-
function
|
|
7666
|
-
const plugin =
|
|
7667
|
-
const
|
|
7668
|
-
const
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
9407
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9408
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9409
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9410
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9411
|
+
return async function handler(req) {
|
|
9412
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9413
|
+
if (authResult) return authResult;
|
|
9414
|
+
const url = new URL(req.url);
|
|
9415
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9416
|
+
if (req.method === "GET") {
|
|
9417
|
+
try {
|
|
9418
|
+
const history = await storage.getHistory(sessionId);
|
|
9419
|
+
return import_server.NextResponse.json({ history });
|
|
9420
|
+
} catch (err) {
|
|
9421
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9422
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9423
|
+
}
|
|
9424
|
+
} else if (req.method === "POST") {
|
|
9425
|
+
try {
|
|
9426
|
+
const body = await req.json().catch(() => ({}));
|
|
9427
|
+
const sid = body.sessionId || sessionId;
|
|
9428
|
+
await storage.clearHistory(sid);
|
|
9429
|
+
return import_server.NextResponse.json({ success: true });
|
|
9430
|
+
} catch (err) {
|
|
9431
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9432
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9433
|
+
}
|
|
9434
|
+
}
|
|
9435
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9439
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9440
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9441
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9442
|
+
return async function handler(req) {
|
|
9443
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9444
|
+
if (authResult) return authResult;
|
|
9445
|
+
if (req.method === "GET") {
|
|
9446
|
+
try {
|
|
9447
|
+
const url = new URL(req.url);
|
|
9448
|
+
const messageId = url.searchParams.get("messageId");
|
|
9449
|
+
if (!messageId) {
|
|
9450
|
+
const feedbackList = await storage.listFeedback();
|
|
9451
|
+
return import_server.NextResponse.json({ feedback: feedbackList });
|
|
9452
|
+
}
|
|
9453
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9454
|
+
return import_server.NextResponse.json({ feedback });
|
|
9455
|
+
} catch (err) {
|
|
9456
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9457
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9458
|
+
}
|
|
9459
|
+
} else if (req.method === "POST") {
|
|
9460
|
+
try {
|
|
9461
|
+
const body = await req.json();
|
|
9462
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9463
|
+
if (!messageId) {
|
|
9464
|
+
return import_server.NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9465
|
+
}
|
|
9466
|
+
if (!rating) {
|
|
9467
|
+
return import_server.NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9468
|
+
}
|
|
9469
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9470
|
+
return import_server.NextResponse.json({ success: true });
|
|
9471
|
+
} catch (err) {
|
|
9472
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9473
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9474
|
+
}
|
|
9475
|
+
}
|
|
9476
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9477
|
+
};
|
|
9478
|
+
}
|
|
9479
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9480
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9481
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9482
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9483
|
+
return async function GET(req) {
|
|
9484
|
+
if (req) {
|
|
9485
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9486
|
+
if (authResult) return authResult;
|
|
9487
|
+
}
|
|
9488
|
+
void req;
|
|
9489
|
+
try {
|
|
9490
|
+
const sessions = await storage.listSessions();
|
|
9491
|
+
return import_server.NextResponse.json({ sessions });
|
|
9492
|
+
} catch (err) {
|
|
9493
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9494
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9495
|
+
}
|
|
9496
|
+
};
|
|
9497
|
+
}
|
|
9498
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9499
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9500
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9501
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9502
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9503
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9504
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9505
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9506
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9507
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9508
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
7672
9509
|
async function routePostRequest(req, segment) {
|
|
7673
9510
|
switch (segment) {
|
|
7674
9511
|
case "chat":
|
|
@@ -7680,22 +9517,35 @@ function createRagHandler(configOrPlugin) {
|
|
|
7680
9517
|
case "suggestions":
|
|
7681
9518
|
return suggestionsHandler(req);
|
|
7682
9519
|
case "health":
|
|
7683
|
-
return healthHandler();
|
|
9520
|
+
return healthHandler(req);
|
|
9521
|
+
case "history":
|
|
9522
|
+
case "history/clear":
|
|
9523
|
+
return historyHandler(req);
|
|
9524
|
+
case "feedback":
|
|
9525
|
+
return feedbackHandler(req);
|
|
7684
9526
|
default:
|
|
7685
9527
|
return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
7686
9528
|
}
|
|
7687
9529
|
}
|
|
7688
9530
|
async function routeGetRequest(req, segment) {
|
|
7689
|
-
|
|
7690
|
-
|
|
9531
|
+
switch (segment) {
|
|
9532
|
+
case "health":
|
|
9533
|
+
return healthHandler(req);
|
|
9534
|
+
case "history":
|
|
9535
|
+
return historyHandler(req);
|
|
9536
|
+
case "feedback":
|
|
9537
|
+
return feedbackHandler(req);
|
|
9538
|
+
case "sessions":
|
|
9539
|
+
return sessionsHandler(req);
|
|
9540
|
+
default:
|
|
9541
|
+
return import_server.NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
7691
9542
|
}
|
|
7692
|
-
return import_server.NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
|
|
7693
9543
|
}
|
|
7694
9544
|
async function getSegment(context) {
|
|
7695
|
-
var
|
|
7696
|
-
const resolvedParams = typeof ((
|
|
9545
|
+
var _a2;
|
|
9546
|
+
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;
|
|
7697
9547
|
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
7698
|
-
return segments
|
|
9548
|
+
return segments.join("/") || "chat";
|
|
7699
9549
|
}
|
|
7700
9550
|
return {
|
|
7701
9551
|
GET: async (req, context) => {
|
|
@@ -7721,9 +9571,12 @@ function createRagHandler(configOrPlugin) {
|
|
|
7721
9571
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7722
9572
|
0 && (module.exports = {
|
|
7723
9573
|
createChatHandler,
|
|
9574
|
+
createFeedbackHandler,
|
|
7724
9575
|
createHealthHandler,
|
|
9576
|
+
createHistoryHandler,
|
|
7725
9577
|
createIngestHandler,
|
|
7726
9578
|
createRagHandler,
|
|
9579
|
+
createSessionsHandler,
|
|
7727
9580
|
createStreamHandler,
|
|
7728
9581
|
createSuggestionsHandler,
|
|
7729
9582
|
createUploadHandler,
|